@pareto4/pp-core 1.8.2 → 1.10.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 +1 -1
- package/README.md +3 -0
- package/agents/pp-code-fixer.md +11 -0
- package/agents/pp-code-reviewer.md +77 -1
- package/agents/pp-executor.md +34 -1
- package/agents/pp-planner.md +24 -103
- package/bin/install.js +9 -1
- package/commands/pp-ns-manage.md +2 -1
- package/commands/pp-vault-promote.md +31 -0
- package/gemini-extension.json +1 -1
- package/package.json +6 -3
- package/pareto-skills/pp-project-setup/SKILL.md +32 -440
- package/pp-core/bin/lib/capability-registry.cjs +111 -2
- package/pp-core/bin/lib/capability-state.cjs +54 -10
- package/pp-core/bin/lib/check-command-router.cjs +473 -3
- package/pp-core/bin/lib/clusters.cjs +3 -0
- package/pp-core/bin/lib/config.cjs +7 -22
- package/pp-core/bin/lib/io.cjs +7 -0
- package/pp-core/bin/lib/loop-resolver.cjs +6 -0
- package/pp-core/bin/lib/practices-review-check.cjs +938 -0
- package/pp-core/bin/lib/profile-output.cjs +4 -2
- package/pp-core/bin/lib/vault-command-router.cjs +108 -2
- package/pp-core/bin/lib/vault-practices.cjs +982 -0
- package/pp-core/bin/lib/vault-write-back.cjs +756 -0
- package/pp-core/bin/lib/vault.cjs +45 -3
- package/pp-core/bin/pp-tools.cjs +26 -0
- package/pp-core/bin/shared/config-schema.manifest.json +4 -0
- package/pp-core/references/planner-checkpoints.md +72 -0
- package/pp-core/references/planner-tdd.md +55 -0
- package/pp-core/references/planner-vault-practices.md +67 -0
- package/pp-core/templates/practices/README.md +122 -0
- package/pp-core/templates/practices/error-handling.md +18 -0
- package/pp-core/templates/practices/minimal-comments.md +14 -0
- package/pp-core/templates/practices/naming-convention.md +18 -0
- package/pp-core/templates/practices/practice-template.md +23 -0
- package/pp-core/workflows/code-review.md +74 -18
- package/pp-core/workflows/discovery-sprint.md +409 -16
- package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +250 -0
- package/pp-core/workflows/discovery-to-build.md +218 -48
- package/pp-core/workflows/discuss-phase.md +1 -1
- package/pp-core/workflows/execute-phase.md +1 -1
- package/pp-core/workflows/plan-phase.md +1 -1
- package/pp-core/workflows/ship.md +1 -0
- package/pp-core/workflows/vault-write-back.md +213 -0
- package/scripts/changeset/lint.cjs +20 -5
- package/scripts/gen-capability-registry.cjs +68 -8
- package/scripts/lint-allow-test-rule-refs.allowlist.json +8 -1
- package/scripts/lint-descriptions.cjs +3 -1
- package/scripts/lint-docs-required.cjs +10 -3
- package/scripts/lint-legacy-dir-name.cjs +5 -0
- package/scripts/lint-test-file-count.allowlist.json +10 -1
- package/scripts/release-channel.cjs +58 -0
- package/scripts/release-tarball-smoke.cjs +4 -0
- package/scripts/verify-opengsd-sweep.cjs +12 -0
- package/scripts/verify-rename-guard.cjs +333 -0
|
@@ -88,6 +88,14 @@ Code review skipped (code-review capability inactive)
|
|
|
88
88
|
Exit workflow.
|
|
89
89
|
|
|
90
90
|
Default is active through the Capability Registry schema — only skip when the registry resolves no active code-review step hook. This check runs AFTER phase validation so invalid phase errors are shown first.
|
|
91
|
+
|
|
92
|
+
Resolve the practices contribution independently, from the SAME `EXECUTE_POST_HOOKS_JSON` variable already fetched above — do not add a second `pp_run loop render-hooks` call:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
PRACTICES_CONTRIBUTION_FRAGMENT=""
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Resolve active entries in `EXECUTE_POST_HOOKS_JSON` where `kind == "contribution"` and `into == "pp-code-reviewer"`, and capture that entry's `fragment.inline` verbatim into `PRACTICES_CONTRIBUTION_FRAGMENT`. When no such entry is active, `PRACTICES_CONTRIBUTION_FRAGMENT` stays empty and the review runs exactly as it does today — the practices dimension is inert, not degraded.
|
|
91
99
|
</step>
|
|
92
100
|
|
|
93
101
|
<step name="resolve_depth">
|
|
@@ -359,9 +367,9 @@ if (resolved) process.stdout.write(resolved);
|
|
|
359
367
|
|
|
360
368
|
2) If binary is missing, fail with actionable message:
|
|
361
369
|
```bash
|
|
362
|
-
if [ -z
|
|
363
|
-
echo
|
|
364
|
-
echo
|
|
370
|
+
if [ -z "$FALLOW_BIN" ]; then
|
|
371
|
+
echo "Error: fallow is enabled but no binary was found."
|
|
372
|
+
echo "Install fallow via \`npm install -D fallow\` or \`cargo install fallow\`."
|
|
365
373
|
# Exit workflow
|
|
366
374
|
fi
|
|
367
375
|
```
|
|
@@ -375,36 +383,36 @@ FALLOW_STDERR_TMP=$(mktemp)
|
|
|
375
383
|
# Derive the phase base commit; if none is found, fall back to repo scope (fallow
|
|
376
384
|
# auto-detects the base branch).
|
|
377
385
|
FALLOW_SCOPE_ARGS=()
|
|
378
|
-
if [
|
|
379
|
-
FALLOW_PHASE_COMMITS=$(git log --oneline --all --grep
|
|
380
|
-
if [ -n
|
|
381
|
-
FALLOW_BASE=$(echo
|
|
382
|
-
FALLOW_SCOPE_ARGS=(--changed-since
|
|
386
|
+
if [ "$FALLOW_SCOPE" = "phase" ]; then
|
|
387
|
+
FALLOW_PHASE_COMMITS=$(git log --oneline --all --grep="${PADDED_PHASE}" --format="%H" 2>/dev/null)
|
|
388
|
+
if [ -n "$FALLOW_PHASE_COMMITS" ]; then
|
|
389
|
+
FALLOW_BASE=$(echo "$FALLOW_PHASE_COMMITS" | tail -1)^
|
|
390
|
+
FALLOW_SCOPE_ARGS=(--changed-since "$FALLOW_BASE")
|
|
383
391
|
fi
|
|
384
392
|
fi
|
|
385
393
|
|
|
386
|
-
timeout 120
|
|
394
|
+
timeout 120 "$FALLOW_BIN" audit --format json --quiet --max-crap "$FALLOW_MAX_CRAP" "${FALLOW_SCOPE_ARGS[@]+"${FALLOW_SCOPE_ARGS[@]}"}" > "${FALLOW_JSON_PATH}.tmp" 2>"$FALLOW_STDERR_TMP"
|
|
387
395
|
FALLOW_EXIT=$?
|
|
388
396
|
|
|
389
397
|
# fallow exits 0 (clean) or 1 (issues found) — BOTH are successful runs that produce a
|
|
390
398
|
# valid JSON report. Only a timeout (124), usage error (2), or crash yields no usable JSON.
|
|
391
399
|
# Decide success by whether the output parses as a fallow report, not by exit code.
|
|
392
|
-
FALLOW_OK=$(FALLOW_TMP
|
|
400
|
+
FALLOW_OK=$(FALLOW_TMP="${FALLOW_JSON_PATH}.tmp" node -e "
|
|
393
401
|
try {
|
|
394
402
|
const fs = require('fs');
|
|
395
403
|
const txt = fs.readFileSync(process.env.FALLOW_TMP, 'utf8');
|
|
396
404
|
const o = JSON.parse(txt);
|
|
397
405
|
process.stdout.write(o && typeof o === 'object' && 'verdict' in o ? '1' : '0');
|
|
398
406
|
} catch { process.stdout.write('0'); }
|
|
399
|
-
|
|
400
|
-
if [
|
|
401
|
-
FALLOW_STDERR_SUMMARY=$(head -5
|
|
402
|
-
rm -f
|
|
403
|
-
echo
|
|
404
|
-
FALLOW_JSON_PATH
|
|
407
|
+
")
|
|
408
|
+
if [ "$FALLOW_OK" != "1" ]; then
|
|
409
|
+
FALLOW_STDERR_SUMMARY=$(head -5 "$FALLOW_STDERR_TMP")
|
|
410
|
+
rm -f "${FALLOW_JSON_PATH}.tmp" "$FALLOW_STDERR_TMP"
|
|
411
|
+
echo "WARNING: fallow structural pre-pass failed (exit ${FALLOW_EXIT}): ${FALLOW_STDERR_SUMMARY}"
|
|
412
|
+
FALLOW_JSON_PATH=""
|
|
405
413
|
else
|
|
406
|
-
mv
|
|
407
|
-
rm -f
|
|
414
|
+
mv "${FALLOW_JSON_PATH}.tmp" "$FALLOW_JSON_PATH"
|
|
415
|
+
rm -f "$FALLOW_STDERR_TMP"
|
|
408
416
|
fi
|
|
409
417
|
```
|
|
410
418
|
|
|
@@ -477,6 +485,16 @@ if [ -n "$FALLOW_JSON_PATH" ] && [ -f "$FALLOW_JSON_PATH" ]; then
|
|
|
477
485
|
fi
|
|
478
486
|
```
|
|
479
487
|
|
|
488
|
+
Build practices contribution block for agent:
|
|
489
|
+
```bash
|
|
490
|
+
PRACTICES_CONTRIBUTION_BLOCK=""
|
|
491
|
+
if [ -n "$PRACTICES_CONTRIBUTION_FRAGMENT" ]; then
|
|
492
|
+
# Escape any literal closing tag before embedding; the closing tag literal is escaped so text arriving from outside this workflow cannot end the block early and steer the reviewer.
|
|
493
|
+
SAFE_PRACTICES_FRAGMENT=$(echo "$PRACTICES_CONTRIBUTION_FRAGMENT" | sed 's#</practices_contribution>#<\/practices_contribution>#g')
|
|
494
|
+
PRACTICES_CONTRIBUTION_BLOCK=$(printf '<practices_contribution>\n%s\n</practices_contribution>\n' "$SAFE_PRACTICES_FRAGMENT")
|
|
495
|
+
fi
|
|
496
|
+
```
|
|
497
|
+
|
|
480
498
|
Spawn the pp-code-reviewer agent:
|
|
481
499
|
|
|
482
500
|
Print: `◆ Spawning code reviewer... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)`
|
|
@@ -489,6 +507,8 @@ ${FILES_TO_READ}
|
|
|
489
507
|
|
|
490
508
|
${STRUCTURAL_FINDINGS_BLOCK}
|
|
491
509
|
|
|
510
|
+
${PRACTICES_CONTRIBUTION_BLOCK}
|
|
511
|
+
|
|
492
512
|
<config>
|
|
493
513
|
depth: ${REVIEW_DEPTH}
|
|
494
514
|
phase_dir: ${PHASE_DIR}
|
|
@@ -549,6 +569,30 @@ fi
|
|
|
549
569
|
```
|
|
550
570
|
</step>
|
|
551
571
|
|
|
572
|
+
<step name="check_practice_boundaries">
|
|
573
|
+
This is a safety report about untrusted client vault text already written to `${REVIEW_PATH}`, ahead of `dispatch_fix`, and never skipped when `--fix` short-circuits `present_results`. A boundary shortfall is a defect in the report, not the reviewed code, so this check never changes an exit status — failing the review would punish the wrong artifact. The detection logic lives in `src/practices-review-check.cts`, a compiled module whose own test suite (`tests/practices-review-check.test.cjs`) pins the property that a malformed finding can only ever change its own verdict, never a sibling's.
|
|
574
|
+
|
|
575
|
+
```bash
|
|
576
|
+
pp_run check practices-review --review "${REVIEW_PATH}" --boundaries 2>/dev/null || true
|
|
577
|
+
```
|
|
578
|
+
</step>
|
|
579
|
+
|
|
580
|
+
<step name="check_unfenced_vault_quotes">
|
|
581
|
+
Safety report about client vault text already in `${REVIEW_PATH}`, scoped to the WHOLE file — the sibling above cannot see a verbatim client quote unfenced in narrative prose. The comparison corpus is the client's own words from inside the boundary lines only, never the fixed reference-data sentences the check itself prepends to every excerpt. Reports findings only and never changes an exit status — a quote shortfall is a defect in the review, not the reviewed code. The detection logic lives in the same compiled `src/practices-review-check.cts` module as the sibling step above, with its own pinned regression tests.
|
|
582
|
+
|
|
583
|
+
**Resolve and compare in one block**, deliberately: the block resolves and consumes the corpus in one invocation AND decides whether to attempt the resolution from inside that same invocation, because a gate read from another fenced block is the identical failure the merge exists to prevent. `REVIEW_FILES` and `REVIEW_PATH` are still read from earlier in the workflow — they are this step's actual inputs, not its gate — and both now degrade visibly rather than silently: an empty `REVIEW_PATH` produces an operator-visible usage line instead of a byte-identical clean result (the CLI seam's empty-value guard, T-27-R8-05), and an empty or unset `REVIEW_FILES` produces its own one-line notice from inside this same block, before the corpus is ever resolved — an unresolved comparison corpus is never mistaken for a clean result. A test harness can supply both `REVIEW_PATH` and `VAULT_QUOTE_CORPUS` directly, no vault/matcher/model:
|
|
584
|
+
|
|
585
|
+
```bash
|
|
586
|
+
VAULT_QUOTE_CORPUS=""
|
|
587
|
+
if [ -z "${REVIEW_FILES[@]+x}" ]; then
|
|
588
|
+
echo "practices quote check: no review files in scope — corpus not resolved"
|
|
589
|
+
elif ! VAULT_QUOTE_CORPUS=$(pp_run vault practices match "${REVIEW_FILES[@]}" --raw 2>/dev/null); then
|
|
590
|
+
VAULT_QUOTE_CORPUS=""
|
|
591
|
+
fi
|
|
592
|
+
VAULT_QUOTE_CORPUS="${VAULT_QUOTE_CORPUS}" pp_run check practices-review --review "${REVIEW_PATH}" --quotes 2>/dev/null || true
|
|
593
|
+
```
|
|
594
|
+
</step>
|
|
595
|
+
|
|
552
596
|
<step name="dispatch_fix">
|
|
553
597
|
If the `--fix` flag was passed (`FIX_FLAG=true`), delegate to the `code-review-fix.md` workflow
|
|
554
598
|
to auto-apply findings from the REVIEW.md that was just written (or that already existed).
|
|
@@ -612,6 +656,15 @@ INFO=$(echo "$FRONTMATTER" | grep "info:" | head -1 | cut -d: -f2 | xargs)
|
|
|
612
656
|
TOTAL=$(echo "$FRONTMATTER" | grep "total:" | head -1 | cut -d: -f2 | xargs)
|
|
613
657
|
```
|
|
614
658
|
|
|
659
|
+
The six lines above take the first match over the whole frontmatter and therefore read the bugs/security numbers only — this is why the practices key below is read from its own slice and written after the existing counts (D-07):
|
|
660
|
+
|
|
661
|
+
```bash
|
|
662
|
+
# Scoped read: the practices: block only, so its total: line can never collide with
|
|
663
|
+
# the bugs/security first-match extraction above.
|
|
664
|
+
PRACTICES_FRONTMATTER_BLOCK=$(printf '%s\n' "$FRONTMATTER" | sed -n -e '/^practices:/,/^[^[:space:]]/{' -e '/^practices:/p' -e '/^[[:space:]]/p' -e '}')
|
|
665
|
+
PRACTICES_TOTAL=$(echo "$PRACTICES_FRONTMATTER_BLOCK" | grep -E "^[[:space:]]*total:" | head -1 | cut -d: -f2 | xargs)
|
|
666
|
+
```
|
|
667
|
+
|
|
615
668
|
Display inline summary to user:
|
|
616
669
|
|
|
617
670
|
```
|
|
@@ -630,10 +683,13 @@ Display inline summary to user:
|
|
|
630
683
|
Info: ${INFO}
|
|
631
684
|
──────────
|
|
632
685
|
Total: ${TOTAL}
|
|
686
|
+
${PRACTICES_TOTAL:+ Practices (advisory): ${PRACTICES_TOTAL}}
|
|
633
687
|
|
|
634
688
|
───────────────────────────────────────────────────────────────
|
|
635
689
|
```
|
|
636
690
|
|
|
691
|
+
When `PRACTICES_TOTAL` is empty, omit the Practices line entirely — the block renders exactly as it did before this phase, with no blank line left in its place.
|
|
692
|
+
|
|
637
693
|
If status is "clean":
|
|
638
694
|
```
|
|
639
695
|
✓ No issues found. All ${FILES_REVIEWED} files pass review at ${REVIEW_DEPTH} depth.
|