@pareto4/pp-core 1.17.1 → 1.19.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 +5 -3
- package/agents/pp-code-fixer.md +9 -16
- package/agents/pp-code-reviewer.md +2 -78
- package/agents/pp-codebase-mapper.md +3 -0
- package/agents/pp-debugger.md +3 -2
- package/agents/pp-executor.md +25 -30
- package/agents/pp-integration-checker.md +1 -0
- package/agents/pp-phase-researcher.md +3 -1
- package/agents/pp-plan-checker.md +3 -0
- package/agents/pp-planner.md +16 -12
- package/agents/pp-research-synthesizer.md +1 -1
- package/agents/pp-ui-auditor.md +1 -0
- package/agents/pp-ui-researcher.md +3 -1
- package/agents/pp-vault-reviewer.md +43 -189
- package/agents/pp-verifier.md +10 -8
- package/commands/pp-add-tests.md +1 -1
- package/commands/pp-debug.md +1 -0
- package/commands/pp-init.md +4 -3
- package/commands/pp-ns-manage.md +1 -1
- package/commands/pp-ns-review.md +1 -1
- package/commands/pp-quick.md +3 -0
- package/commands/pp-review-backlog.md +2 -1
- package/commands/pp-vault-promote.md +7 -8
- package/commands/pp-vault-review.md +6 -7
- package/gemini-extension.json +1 -1
- package/package.json +3 -6
- package/pp-core/bin/lib/capability-registry.cjs +15 -357
- package/pp-core/bin/lib/capability-state.cjs +15 -79
- package/pp-core/bin/lib/capability-writer.cjs +2 -16
- package/pp-core/bin/lib/check-command-router.cjs +342 -2298
- package/pp-core/bin/lib/clusters.cjs +2 -2
- package/pp-core/bin/lib/commands.cjs +79 -4
- package/pp-core/bin/lib/compose-bindings.cjs +99 -16
- package/pp-core/bin/lib/config.cjs +3 -6
- package/pp-core/bin/lib/discovery-rollup.cjs +9 -6
- package/pp-core/bin/lib/discovery-screens.cjs +20 -2
- package/pp-core/bin/lib/discovery-sweep.cjs +12 -3
- package/pp-core/bin/lib/discovery-vault-check.cjs +37 -3
- package/pp-core/bin/lib/git-base-branch.cjs +10 -13
- package/pp-core/bin/lib/git-provider.cjs +5 -6
- package/pp-core/bin/lib/init-contract.cjs +55 -42
- package/pp-core/bin/lib/init-interactive.cjs +6 -20
- package/pp-core/bin/lib/io.cjs +2 -8
- package/pp-core/bin/lib/loop-resolver.cjs +8 -32
- package/pp-core/bin/lib/org-profile.cjs +16 -92
- package/pp-core/bin/lib/vault-command-router.cjs +174 -1206
- package/pp-core/bin/lib/vault-coordinates.cjs +4 -4
- package/pp-core/bin/lib/vault-index.cjs +44 -74
- package/pp-core/bin/lib/vault-seal.cjs +37 -122
- 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 +15 -16
- package/pp-core/bin/lib/vault-trace.cjs +40 -3016
- package/pp-core/bin/lib/vault-update.cjs +5 -26
- package/pp-core/bin/lib/vault.cjs +122 -316
- package/pp-core/bin/pp-tools.cjs +15 -36
- package/pp-core/org-profile.json +1 -1
- package/pp-core/references/autonomous-best-effort.md +4 -3
- package/pp-core/references/autonomous-lifecycle.md +1 -0
- package/pp-core/references/autonomous-smart-discuss.md +5 -1
- package/pp-core/references/discovery-id-conventions.md +35 -2
- package/pp-core/references/execute-mvp-tdd.md +3 -3
- package/pp-core/references/git-integration.md +57 -33
- package/pp-core/references/git-planning-commit.md +31 -9
- package/pp-core/references/phase-argument-parsing.md +1 -0
- package/pp-core/references/planner-gap-closure.md +1 -0
- package/pp-core/references/planner-revision.md +3 -1
- package/pp-core/references/planner-tdd.md +4 -4
- package/pp-core/references/planner-vault-standards.md +16 -25
- package/pp-core/references/planning-config.md +3 -3
- package/pp-core/references/shell-portability.md +28 -0
- package/pp-core/references/tdd.md +20 -16
- package/pp-core/references/worktree-path-safety.md +1 -0
- package/pp-core/templates/README.md +1 -1
- package/pp-core/templates/VAULT-REVIEW.md +24 -170
- package/pp-core/templates/milestone.md +5 -5
- package/pp-core/workflows/add-backlog.md +1 -1
- package/pp-core/workflows/add-tests.md +8 -5
- package/pp-core/workflows/add-todo.md +3 -1
- package/pp-core/workflows/ai-integration-phase.md +2 -1
- package/pp-core/workflows/audit-fix.md +7 -6
- package/pp-core/workflows/audit-milestone.md +1 -0
- package/pp-core/workflows/autonomous.md +6 -0
- package/pp-core/workflows/check-todos.md +2 -1
- package/pp-core/workflows/cleanup.md +3 -1
- package/pp-core/workflows/code-review-fix.md +15 -8
- package/pp-core/workflows/code-review.md +16 -58
- package/pp-core/workflows/complete-milestone.md +13 -3
- package/pp-core/workflows/debug.md +4 -2
- package/pp-core/workflows/diagnose-issues.md +1 -1
- package/pp-core/workflows/discovery-sprint/prototype.md +2 -2
- package/pp-core/workflows/discovery-sprint/session-13-gates.md +1 -1
- package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +51 -7
- package/pp-core/workflows/discovery-sprint/sessions/02-as-is.md +5 -3
- package/pp-core/workflows/discovery-sprint/sessions/03-to-be.md +10 -8
- package/pp-core/workflows/discovery-sprint/sessions/04-ux-design.md +11 -2
- package/pp-core/workflows/discovery-sprint/sessions/05-architecture.md +5 -5
- package/pp-core/workflows/discovery-sprint/sessions/06-security.md +3 -3
- package/pp-core/workflows/discovery-sprint/sessions/07-identity.md +2 -2
- package/pp-core/workflows/discovery-sprint/sessions/08-integration.md +14 -2
- package/pp-core/workflows/discovery-sprint/sessions/09-qa.md +2 -2
- package/pp-core/workflows/discovery-sprint/sessions/10-infrastructure.md +10 -10
- package/pp-core/workflows/discovery-sprint/sessions/11-roadmap.md +11 -8
- package/pp-core/workflows/discovery-sprint/sessions/12-delivery-model.md +21 -18
- package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +5 -3
- package/pp-core/workflows/discovery-sprint/templates/context-template.md +9 -3
- package/pp-core/workflows/discovery-sprint/vault-context.md +17 -12
- package/pp-core/workflows/discovery-sprint.md +11 -8
- package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +1 -0
- package/pp-core/workflows/discuss-phase-assumptions.md +5 -3
- package/pp-core/workflows/discuss-phase.md +8 -3
- package/pp-core/workflows/docs-update.md +1 -0
- package/pp-core/workflows/eval-review.md +2 -1
- package/pp-core/workflows/execute-phase/steps/check-query-gate.md +13 -14
- package/pp-core/workflows/execute-phase/steps/cross-ai-delegation.md +1 -0
- package/pp-core/workflows/execute-phase/steps/execute-pre-dispatch.md +5 -25
- package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -0
- package/pp-core/workflows/execute-phase/steps/vault-fetch.md +18 -6
- package/pp-core/workflows/execute-phase/steps/vault-load-gate.md +6 -109
- package/pp-core/workflows/execute-phase/steps/verify-post-gate.md +1 -17
- package/pp-core/workflows/execute-phase.md +21 -12
- package/pp-core/workflows/execute-plan.md +24 -15
- package/pp-core/workflows/explore.md +1 -1
- package/pp-core/workflows/forensics.md +4 -2
- package/pp-core/workflows/health.md +1 -0
- package/pp-core/workflows/help/modes/full.md +1 -1
- package/pp-core/workflows/import.md +2 -1
- package/pp-core/workflows/ingest-docs.md +1 -0
- package/pp-core/workflows/init/steps/client-context-capture.md +1 -0
- package/pp-core/workflows/init/steps/github-provisioning.md +145 -0
- package/pp-core/workflows/init/steps/gitlab-provisioning.md +18 -4
- package/pp-core/workflows/init/steps/reachability-outcome.md +3 -1
- package/pp-core/workflows/init.md +56 -66
- package/pp-core/workflows/map-codebase.md +5 -1
- package/pp-core/workflows/milestone-summary.md +2 -1
- package/pp-core/workflows/mvp-phase.md +1 -0
- package/pp-core/workflows/new-milestone.md +9 -5
- package/pp-core/workflows/new-project.md +9 -8
- package/pp-core/workflows/new-workspace.md +1 -0
- package/pp-core/workflows/next.md +2 -1
- package/pp-core/workflows/pause-work.md +6 -4
- package/pp-core/workflows/plan-milestone-gaps.md +3 -1
- package/pp-core/workflows/plan-phase/steps/chunked-planning.md +1 -1
- package/pp-core/workflows/plan-phase.md +21 -6
- package/pp-core/workflows/plan-review-convergence.md +2 -0
- package/pp-core/workflows/plant-seed.md +4 -2
- package/pp-core/workflows/pr-branch.md +2 -0
- package/pp-core/workflows/progress.md +5 -0
- package/pp-core/workflows/quick.md +19 -12
- package/pp-core/workflows/reapply-patches.md +3 -0
- package/pp-core/workflows/remove-phase.md +1 -1
- package/pp-core/workflows/resume-project.md +3 -0
- package/pp-core/workflows/review.md +7 -1
- package/pp-core/workflows/secure-phase.md +2 -1
- package/pp-core/workflows/session-report.md +1 -0
- package/pp-core/workflows/ship.md +8 -1
- package/pp-core/workflows/sketch-wrap-up.md +1 -1
- package/pp-core/workflows/sketch.md +3 -2
- package/pp-core/workflows/spec-phase.md +2 -1
- package/pp-core/workflows/spike-wrap-up.md +1 -1
- package/pp-core/workflows/spike.md +4 -3
- package/pp-core/workflows/sync-skills.md +5 -2
- package/pp-core/workflows/thread.md +3 -2
- package/pp-core/workflows/transition.md +6 -0
- package/pp-core/workflows/ui-phase.md +3 -1
- package/pp-core/workflows/ui-review.md +2 -1
- package/pp-core/workflows/ultraplan-phase.md +1 -0
- package/pp-core/workflows/undo.md +14 -10
- package/pp-core/workflows/update.md +5 -0
- package/pp-core/workflows/validate-phase.md +9 -6
- package/pp-core/workflows/vault-review.md +65 -186
- package/pp-core/workflows/vault-write-back.md +78 -110
- package/pp-core/workflows/verify-phase.md +5 -0
- package/pp-core/workflows/verify-work.md +9 -2
- package/scripts/gen-capability-registry.cjs +12 -93
- package/scripts/lint-test-file-count.allowlist.json +1 -19
- package/scripts/lint-test-file-count.cjs +5 -6
- package/scripts/prompt-injection-scan.sh +1 -4
- package/scripts/sync-runtime-launcher.cjs +115 -5
- package/pp-core/bin/lib/practices-review-check.cjs +0 -944
- package/pp-core/bin/lib/vault-audit.cjs +0 -2594
- package/pp-core/bin/lib/vault-mode.cjs +0 -235
- package/pp-core/bin/lib/vault-practices.cjs +0 -2057
- package/pp-core/bin/lib/vault-review.cjs +0 -2102
- package/pp-core/bin/lib/vault-write-back.cjs +0 -905
- package/pp-core/references/planner-vault-practices.md +0 -95
- package/pp-core/references/practice-arithmetic-contract.md +0 -121
- package/pp-core/references/verifier-practice-verdicts.md +0 -263
- package/pp-core/templates/practices/README.md +0 -248
- 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/execute-phase/steps/verifier-practice-payload.md +0 -165
- package/scripts/gen-practice-arithmetic-contract.cjs +0 -412
- package/scripts/practice-arithmetic-contract.allow.json +0 -35
- package/scripts/record-vault-mode-golden.cjs +0 -89
- package/scripts/vault-calibrate.cjs +0 -996
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
<purpose>
|
|
2
|
-
Take one local
|
|
3
|
-
vault
|
|
4
|
-
irreversible outward action: it shows the operator the complete preview, asks once
|
|
5
|
-
to proceed, and only on explicit approval re-invokes the same guarded CLI
|
|
6
|
-
mode. It never authors, edits
|
|
7
|
-
|
|
8
|
-
workflow only calls.
|
|
2
|
+
Take one local standards document from preview to a confirmed, pushed promotion into the client
|
|
3
|
+
vault, together with its INDEX.md entry, and nothing more. This workflow is the single human gate
|
|
4
|
+
in front of an irreversible outward action: it shows the operator the complete preview, asks once
|
|
5
|
+
whether to proceed, and only on explicit approval re-invokes the same guarded CLI verb in confirmed
|
|
6
|
+
mode. It never authors, edits or reformats the document, and it performs no git operation of its
|
|
7
|
+
own; every outward action happens inside `pp_run vault standards promote`.
|
|
9
8
|
</purpose>
|
|
10
9
|
|
|
11
10
|
<required_reading>
|
|
@@ -15,79 +14,67 @@ Read all files referenced by the invoking prompt's execution_context before star
|
|
|
15
14
|
<process>
|
|
16
15
|
|
|
17
16
|
<step name="text_mode">
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
workflow
|
|
22
|
-
operator to type their choice number. This is required because non-Claude runtimes have no
|
|
23
|
-
interactive question tool, and the confirmation in Step 4 is the entire point of this
|
|
24
|
-
workflow — it must degrade to plain text, never disappear.
|
|
25
|
-
</step>
|
|
26
|
-
|
|
27
|
-
<step name="resolve_launcher">
|
|
28
|
-
Resolve the `pp_run` launcher shim before any other step, so every call below goes through
|
|
29
|
-
the repo-local or installed `pp-tools` binary rather than assuming a global install:
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
```
|
|
17
|
+
Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS`. When `TEXT_MODE` is active, replace
|
|
18
|
+
every `AskUserQuestion` call in this workflow, including the gate below, with a plain-text numbered
|
|
19
|
+
list, and ask the operator to type their choice number. The confirmation is the point of this
|
|
20
|
+
workflow: it must degrade to plain text, never disappear.
|
|
33
21
|
</step>
|
|
34
22
|
|
|
35
23
|
<step name="resolve_input">
|
|
36
|
-
Take
|
|
37
|
-
none was given, ask the operator for one with a plain prompt:
|
|
24
|
+
Take from `$ARGUMENTS`:
|
|
38
25
|
|
|
39
|
-
|
|
40
|
-
Path to the local
|
|
41
|
-
|
|
26
|
+
- the document path: the first token that is not a flag (required; ask for it with a plain prompt
|
|
27
|
+
when it is missing: `Path to the local standards document to promote (e.g. docs/standards/api-errors.md):`);
|
|
28
|
+
- `--path <vault-path>`: where the document goes in the vault (optional; defaults to
|
|
29
|
+
`standards/<file name>`);
|
|
30
|
+
- `--entry "<what it is>; used when <…>"`: the document's INDEX.md entry text (required when the
|
|
31
|
+
vault's INDEX.md does not list the document yet; replaces the existing line when given for a
|
|
32
|
+
listed document);
|
|
33
|
+
- `--section <title>`: the INDEX.md `##` section a new entry goes under (optional).
|
|
34
|
+
|
|
35
|
+
When the document is new to the vault and no `--entry` was given, ask the operator for one plain
|
|
36
|
+
sentence of the form `<what the document is>; used when <when a plan should follow it>`. Never
|
|
37
|
+
invent it.
|
|
42
38
|
|
|
43
|
-
Do not compose,
|
|
44
|
-
|
|
45
|
-
that path are exactly the bytes that will be previewed and, if approved, pushed.
|
|
39
|
+
Do not compose, rewrite or reformat the document at this or any later step. Whatever bytes are on
|
|
40
|
+
disk at that path are exactly the bytes that will be previewed and, if approved, pushed.
|
|
46
41
|
|
|
47
42
|
```bash
|
|
48
|
-
|
|
43
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
44
|
+
DOC_FILE="<the resolved path>"
|
|
45
|
+
PROMOTE_ARGS=() # add --path, --entry and --section with their values, as given
|
|
49
46
|
```
|
|
50
47
|
</step>
|
|
51
48
|
|
|
52
49
|
<step name="preview">
|
|
53
|
-
Run the promote verb
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
Run the promote verb without `--confirmed`, capturing stdout, stderr and the exit code. This
|
|
51
|
+
invocation performs no outward action: it clones the client vault into a disposable directory,
|
|
52
|
+
writes the change there, and reports the diff.
|
|
56
53
|
|
|
57
54
|
```bash
|
|
58
55
|
_PP_SHIM_NAME="pp-tools.cjs"; _pp_root() { ( for _v in $(env | sed -n 's/^\(GIT_[A-Za-z0-9_]*\)=.*/\1/p'); do unset "$_v"; done; _c=$(git rev-parse --git-common-dir 2>/dev/null); if [ "${_c##*/}" = .git ] && cd "$_c/.." 2>/dev/null; then pwd -P; else git rev-parse --show-toplevel 2>/dev/null || pwd; fi ); }; pp_run() { case "$PP_TOOLS" in *.cjs) node "$PP_TOOLS" "$@";; *) "$PP_TOOLS" "$@";; esac; }; _PP_RUNTIME_ROOT="${RUNTIME_DIR:-$(_pp_root)}"; PP_TOOLS="${_PP_RUNTIME_ROOT}/pp-core/bin/${_PP_SHIM_NAME}"; if [ -f "$PP_TOOLS" ]; then :; elif [ -f "${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}"; elif command -v pp-tools >/dev/null 2>&1; then PP_TOOLS="$(command -v pp-tools)"; else echo "ERROR: pp-tools.cjs not found at $PP_TOOLS and pp-tools is not on PATH. Run: npx -y @pareto4/pp-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${PP_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${PP_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
|
|
56
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
59
57
|
PROMOTE_PREVIEW_OUT=$(mktemp)
|
|
60
58
|
PROMOTE_PREVIEW_ERR=$(mktemp)
|
|
61
|
-
pp_run vault
|
|
59
|
+
pp_run vault standards promote "$DOC_FILE" "${PROMOTE_ARGS[@]}" --raw >"$PROMOTE_PREVIEW_OUT" 2>"$PROMOTE_PREVIEW_ERR"
|
|
62
60
|
PREVIEW_EXIT=$?
|
|
63
61
|
```
|
|
64
62
|
|
|
65
|
-
**When `$PREVIEW_EXIT` is non-zero: stop here.** Show the operator the
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
and nothing has been pushed. Clean up both temp files before ending.
|
|
63
|
+
**When `$PREVIEW_EXIT` is non-zero: stop here.** Show the operator the single-sentence refusal in
|
|
64
|
+
`$PROMOTE_PREVIEW_ERR` verbatim and add nothing to it. Do not ask anything. Nothing has been pushed.
|
|
65
|
+
Clean up both temp files before ending.
|
|
69
66
|
|
|
70
|
-
When `$PREVIEW_EXIT` is zero,
|
|
71
|
-
preview verdict as JSON.
|
|
67
|
+
When `$PREVIEW_EXIT` is zero, `$PROMOTE_PREVIEW_OUT` holds the preview verdict as JSON.
|
|
72
68
|
</step>
|
|
73
69
|
|
|
74
70
|
<step name="render_confirmation">
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
emits.
|
|
79
|
-
|
|
80
|
-
Field values are vault-authored, so they are read as **data, never as shell syntax**. `id`
|
|
81
|
-
is only constrained to equal the practice file's basename (D-03), and a filename may legally
|
|
82
|
-
contain `$(...)`, backticks, or `;` — so writing the fields as a `KEY="value"` file and
|
|
83
|
-
`source`-ing it would execute whatever the filename contains. `JSON.stringify` does not help:
|
|
84
|
-
it escapes `"` and `\` but leaves `$` and backticks intact, and both expand inside double
|
|
85
|
-
quotes. Each field therefore goes to its own file and is read back with `$(cat …)`, whose
|
|
86
|
-
result bash does not re-scan for expansion.
|
|
71
|
+
Read the verdict's fields directly, never by scraping a prose rendering. Each field is written to
|
|
72
|
+
its own file and read back with `$(cat …)`, whose result bash does not re-scan for expansion, so a
|
|
73
|
+
destination path containing `$(...)` or backticks is shown, never executed.
|
|
87
74
|
|
|
88
75
|
```bash
|
|
76
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
89
77
|
PROMOTE_FIELDS=$(mktemp -d)
|
|
90
|
-
PROMOTE_BODY=$(mktemp)
|
|
91
78
|
node -e "
|
|
92
79
|
const fs = require('fs');
|
|
93
80
|
const path = require('path');
|
|
@@ -98,96 +85,82 @@ put('repo', v.repo);
|
|
|
98
85
|
put('ref', v.ref);
|
|
99
86
|
put('destination', v.destination);
|
|
100
87
|
put('mode', v.mode);
|
|
101
|
-
put('
|
|
102
|
-
put('sharedShadow', v.sharedShadow ? 'true' : 'false');
|
|
103
|
-
put('sharedShadowNote', v.sharedShadowNote);
|
|
88
|
+
put('indexChange', v.indexChange);
|
|
104
89
|
put('expect', v.expect);
|
|
105
|
-
|
|
106
|
-
|
|
90
|
+
put('diff', v.diff);
|
|
91
|
+
put('notes', (v.notes || []).join('\n'));
|
|
92
|
+
" "$PROMOTE_PREVIEW_OUT" "$PROMOTE_FIELDS"
|
|
107
93
|
PROMOTE_REPO=$(cat "$PROMOTE_FIELDS/repo")
|
|
108
94
|
PROMOTE_REF=$(cat "$PROMOTE_FIELDS/ref")
|
|
109
95
|
PROMOTE_DEST=$(cat "$PROMOTE_FIELDS/destination")
|
|
110
96
|
PROMOTE_MODE=$(cat "$PROMOTE_FIELDS/mode")
|
|
111
|
-
|
|
112
|
-
PROMOTE_SHARED=$(cat "$PROMOTE_FIELDS/sharedShadow")
|
|
113
|
-
PROMOTE_SHARED_NOTE=$(cat "$PROMOTE_FIELDS/sharedShadowNote")
|
|
97
|
+
PROMOTE_INDEX=$(cat "$PROMOTE_FIELDS/indexChange")
|
|
114
98
|
PROMOTE_EXPECT=$(cat "$PROMOTE_FIELDS/expect")
|
|
115
99
|
```
|
|
116
100
|
|
|
117
|
-
Show the operator, in this
|
|
118
|
-
never truncated, summarized, or collapsed to "the first N lines":
|
|
101
|
+
Show the operator, in this order, never truncated or summarised:
|
|
119
102
|
|
|
120
103
|
1. The target vault repository (`$PROMOTE_REPO`) and ref (`$PROMOTE_REF`).
|
|
121
|
-
2. The destination path
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
5.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
6. The complete contents of `$PROMOTE_BODY` — the full diff when `$PROMOTE_MODE` is
|
|
131
|
-
`update`, or the full new-file content when it is `create`. Show every byte; the operator
|
|
132
|
-
is about to approve exactly these bytes, so nothing here may be shortened.
|
|
104
|
+
2. The destination path in the vault (`$PROMOTE_DEST`), and whether this **creates** a new
|
|
105
|
+
standards document or **updates** an existing one (`$PROMOTE_MODE`).
|
|
106
|
+
3. What happens to INDEX.md (`$PROMOTE_INDEX`): `added` (a new line), `replaced` (its line gets the
|
|
107
|
+
new entry text) or `unchanged`.
|
|
108
|
+
4. One line stating that the secret scan inside the promote verb found nothing; a document that
|
|
109
|
+
failed it would have been refused before any preview existed.
|
|
110
|
+
5. Any notes in `$PROMOTE_FIELDS/notes`.
|
|
111
|
+
6. The complete contents of `$PROMOTE_FIELDS/diff`: the document and the INDEX.md change, every
|
|
112
|
+
byte. The operator is about to approve exactly these bytes.
|
|
133
113
|
</step>
|
|
134
114
|
|
|
135
115
|
<step name="gate">
|
|
136
|
-
Ask
|
|
137
|
-
active) whether to push this to the client vault. Offer exactly two outcomes — there is no
|
|
138
|
-
default, no timeout, and no auto-advance, because this is an irreversible outward action and
|
|
139
|
-
this confirmation is the whole review step:
|
|
116
|
+
Ask once whether to push. Exactly two outcomes, no default, no timeout, no auto-advance:
|
|
140
117
|
|
|
141
118
|
```text
|
|
142
119
|
AskUserQuestion([
|
|
143
120
|
{
|
|
144
121
|
header: "Push to client vault",
|
|
145
|
-
question: "Push this
|
|
122
|
+
question: "Push this standards document to the client vault now?",
|
|
146
123
|
multiSelect: false,
|
|
147
124
|
options: [
|
|
148
|
-
{ label: "Push it", description: "Push exactly the diff
|
|
125
|
+
{ label: "Push it", description: "Push exactly the diff shown above" },
|
|
149
126
|
{ label: "Stop", description: "Do not push anything — the vault stays unchanged" }
|
|
150
127
|
]
|
|
151
128
|
}
|
|
152
129
|
])
|
|
153
130
|
```
|
|
154
131
|
|
|
155
|
-
**When the operator chooses to stop:**
|
|
156
|
-
|
|
132
|
+
**When the operator chooses to stop:** say in one sentence that nothing was pushed and the client
|
|
133
|
+
vault is unchanged, clean up the temp paths, and end.
|
|
157
134
|
|
|
158
|
-
**When the operator chooses to push:** continue
|
|
135
|
+
**When the operator chooses to push:** continue.
|
|
159
136
|
</step>
|
|
160
137
|
|
|
161
138
|
<step name="push">
|
|
162
|
-
Only inside this approved branch, run the
|
|
163
|
-
|
|
164
|
-
workflow never runs an outward git operation itself — the only thing it does here is invoke
|
|
165
|
-
this verb a second time; every push, every commit, and every other outward action happens
|
|
166
|
-
inside the verb, not in this shell block.
|
|
139
|
+
Only inside this approved branch, run the verb again with the same arguments, `--confirmed`, and the
|
|
140
|
+
expect token carried verbatim from the preview.
|
|
167
141
|
|
|
168
142
|
```bash
|
|
143
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
169
144
|
PROMOTE_PUSH_OUT=$(mktemp)
|
|
170
145
|
PROMOTE_PUSH_ERR=$(mktemp)
|
|
171
|
-
pp_run vault
|
|
146
|
+
pp_run vault standards promote "$DOC_FILE" "${PROMOTE_ARGS[@]}" --confirmed --expect "$PROMOTE_EXPECT" --raw >"$PROMOTE_PUSH_OUT" 2>"$PROMOTE_PUSH_ERR"
|
|
172
147
|
PUSH_EXIT=$?
|
|
173
148
|
```
|
|
174
149
|
|
|
175
|
-
**When `$PUSH_EXIT` is non-zero:** show the
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
The remedy is simply to run this workflow again from the top — the new preview will diff
|
|
180
|
-
against their current version. Clean up all temp files before ending.
|
|
181
|
-
|
|
182
|
-
When `$PUSH_EXIT` is zero, continue to Step 6 with `$PROMOTE_PUSH_OUT` holding the push
|
|
183
|
-
verdict as JSON.
|
|
150
|
+
**When `$PUSH_EXIT` is non-zero:** show the verb's single-sentence refusal from `$PROMOTE_PUSH_ERR`
|
|
151
|
+
verbatim and end; a refusal guarantees nothing was pushed. A concurrent-edit refusal is ordinary:
|
|
152
|
+
someone changed the document or INDEX.md in the vault since the preview. The remedy is to run this
|
|
153
|
+
workflow again from the top. Clean up all temp paths before ending.
|
|
184
154
|
</step>
|
|
185
155
|
|
|
186
156
|
<step name="report">
|
|
187
|
-
|
|
188
|
-
|
|
157
|
+
Read the push verdict's fields the same way, then show the operator the repository, the destination,
|
|
158
|
+
the new commit, what happened to INDEX.md, and whether the local vault cache was refreshed. When the
|
|
159
|
+
refresh did not succeed, say so plainly: the next vault fetch picks the change up; the push itself
|
|
160
|
+
succeeded.
|
|
189
161
|
|
|
190
162
|
```bash
|
|
163
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
191
164
|
node -e "
|
|
192
165
|
const fs = require('fs');
|
|
193
166
|
const v = JSON.parse(fs.readFileSync(process.argv[1], 'utf8'));
|
|
@@ -195,19 +168,14 @@ process.stdout.write(
|
|
|
195
168
|
'repo=' + (v.repo ?? '') + '\n' +
|
|
196
169
|
'destination=' + (v.destination ?? '') + '\n' +
|
|
197
170
|
'commit=' + (v.commit ?? '') + '\n' +
|
|
171
|
+
'indexChange=' + (v.indexChange ?? '') + '\n' +
|
|
198
172
|
'cacheRefreshed=' + String(!!v.cacheRefreshed) + '\n'
|
|
199
173
|
);
|
|
200
174
|
" "$PROMOTE_PUSH_OUT"
|
|
201
175
|
```
|
|
202
176
|
|
|
203
|
-
|
|
204
|
-
and
|
|
205
|
-
not succeed, say so plainly and note that the next vault fetch will pick up the change — this
|
|
206
|
-
is a cosmetic staleness in the local cache only, not a sign the push failed.
|
|
207
|
-
|
|
208
|
-
Clean up every temp path created in this workflow (`$PROMOTE_PREVIEW_OUT`,
|
|
209
|
-
`$PROMOTE_PREVIEW_ERR`, `$PROMOTE_BODY`, `$PROMOTE_PUSH_OUT`, `$PROMOTE_PUSH_ERR`, and the
|
|
210
|
-
`$PROMOTE_FIELDS` **directory**, which needs `rm -rf`) before ending.
|
|
177
|
+
Clean up every temp path created in this workflow (`$PROMOTE_PREVIEW_OUT`, `$PROMOTE_PREVIEW_ERR`,
|
|
178
|
+
`$PROMOTE_PUSH_OUT`, `$PROMOTE_PUSH_ERR`, and the `$PROMOTE_FIELDS` directory with `rm -rf`).
|
|
211
179
|
</step>
|
|
212
180
|
|
|
213
181
|
</process>
|
|
@@ -38,6 +38,7 @@ Extract from init JSON: `phase_dir`, `phase_number`, `phase_name`, `has_plans`,
|
|
|
38
38
|
|
|
39
39
|
Then load phase details and list plans/summaries:
|
|
40
40
|
```bash
|
|
41
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
41
42
|
pp_run query roadmap.get-phase "${phase_number}"
|
|
42
43
|
grep -E "^| ${phase_number}" .planning/REQUIREMENTS.md 2>/dev/null || true
|
|
43
44
|
ls "$phase_dir"/*-SUMMARY.md "$phase_dir"/*-PLAN.md 2>/dev/null || true
|
|
@@ -57,6 +58,7 @@ Extract **phase goal** from ROADMAP.md (the outcome to verify, not tasks), **req
|
|
|
57
58
|
Use `pp-tools.cjs query` verify handlers (or legacy pp-tools) to extract must_haves from each PLAN:
|
|
58
59
|
|
|
59
60
|
```bash
|
|
61
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
60
62
|
for plan in "$PHASE_DIR"/*-PLAN.md; do
|
|
61
63
|
MUST_HAVES=$(pp_run query frontmatter.get "$plan" --field must_haves)
|
|
62
64
|
echo "=== $plan ===" && echo "$MUST_HAVES"
|
|
@@ -124,6 +126,7 @@ For each truth: identify supporting artifacts → check artifact status → chec
|
|
|
124
126
|
Use `pp-tools.cjs query verify.artifacts` (or legacy pp-tools) for artifact verification against must_haves in each PLAN:
|
|
125
127
|
|
|
126
128
|
```bash
|
|
129
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
127
130
|
for plan in "$PHASE_DIR"/*-PLAN.md; do
|
|
128
131
|
ARTIFACT_RESULT=$(pp_run query verify.artifacts "$plan")
|
|
129
132
|
echo "=== $plan ===" && echo "$ARTIFACT_RESULT"
|
|
@@ -167,6 +170,7 @@ wiring or leftover code from plan revisions.
|
|
|
167
170
|
Use `pp-tools.cjs query verify.key-links` (or legacy pp-tools) for key link verification against must_haves in each PLAN:
|
|
168
171
|
|
|
169
172
|
```bash
|
|
173
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
170
174
|
for plan in "$PHASE_DIR"/*-PLAN.md; do
|
|
171
175
|
LINKS_RESULT=$(pp_run query verify.key-links "$plan")
|
|
172
176
|
echo "=== $plan ===" && echo "$LINKS_RESULT"
|
|
@@ -223,6 +227,7 @@ phase.
|
|
|
223
227
|
no `<decisions>` block.
|
|
224
228
|
|
|
225
229
|
```bash
|
|
230
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
226
231
|
GATE_CFG=$(pp_run query config-get workflow.context_coverage_gate 2>/dev/null || echo "true")
|
|
227
232
|
if [ "$GATE_CFG" != "false" ]; then
|
|
228
233
|
# Discover the phase CONTEXT.md via glob expansion rather than `ls | head`
|
|
@@ -38,6 +38,7 @@ If $ARGUMENTS contains a phase number, load context:
|
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
_PP_SHIM_NAME="pp-tools.cjs"; _pp_root() { ( for _v in $(env | sed -n 's/^\(GIT_[A-Za-z0-9_]*\)=.*/\1/p'); do unset "$_v"; done; _c=$(git rev-parse --git-common-dir 2>/dev/null); if [ "${_c##*/}" = .git ] && cd "$_c/.." 2>/dev/null; then pwd -P; else git rev-parse --show-toplevel 2>/dev/null || pwd; fi ); }; pp_run() { case "$PP_TOOLS" in *.cjs) node "$PP_TOOLS" "$@";; *) "$PP_TOOLS" "$@";; esac; }; _PP_RUNTIME_ROOT="${RUNTIME_DIR:-$(_pp_root)}"; PP_TOOLS="${_PP_RUNTIME_ROOT}/pp-core/bin/${_PP_SHIM_NAME}"; if [ -f "$PP_TOOLS" ]; then :; elif [ -f "${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}"; elif command -v pp-tools >/dev/null 2>&1; then PP_TOOLS="$(command -v pp-tools)"; else echo "ERROR: pp-tools.cjs not found at $PP_TOOLS and pp-tools is not on PATH. Run: npx -y @pareto4/pp-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${PP_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${PP_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
|
|
41
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
41
42
|
GSD_WS=""
|
|
42
43
|
echo "$ARGUMENTS" | grep -qE -- '--ws[[:space:]]+[^[:space:]]+' && GSD_WS=$(echo "$ARGUMENTS" | grep -oE -- '--ws[[:space:]]+[^[:space:]]+')
|
|
43
44
|
PHASE_ARG=$(echo "$ARGUMENTS" | sed -E 's/--ws[[:space:]]+[^[:space:]]+//g' | xargs)
|
|
@@ -51,6 +52,7 @@ AGENT_SKILLS_CHECKER=$(pp_run query agent-skills pp-plan-checker)
|
|
|
51
52
|
Parse JSON for: `planner_model`, `checker_model`, `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `has_verification`, `uat_path`.
|
|
52
53
|
|
|
53
54
|
```bash
|
|
55
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
54
56
|
# MVP mode detection via the centralized phase.mvp-mode resolver.
|
|
55
57
|
# verify-work has no --mvp CLI flag (mode is inherited from the planned phase),
|
|
56
58
|
# so we omit --cli-flag — the verb falls through roadmap → config → false.
|
|
@@ -111,6 +113,7 @@ Continue to `create_uat_file`.
|
|
|
111
113
|
Before UAT, check UI capability activation and whether Playwright/Puppeteer MCP tools are available.
|
|
112
114
|
|
|
113
115
|
```bash
|
|
116
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
114
117
|
PLAN_HOOKS_JSON=$(pp_run loop render-hooks plan:pre --raw)
|
|
115
118
|
UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1)
|
|
116
119
|
```
|
|
@@ -148,6 +151,7 @@ UI checkpoints: {N} auto-verified, {M} queued for manual review
|
|
|
148
151
|
Use `phase_dir` from init (or run init if not already done).
|
|
149
152
|
|
|
150
153
|
```bash
|
|
154
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
151
155
|
ls "$phase_dir"/*-SUMMARY.md 2>/dev/null || true
|
|
152
156
|
```
|
|
153
157
|
|
|
@@ -167,6 +171,7 @@ When `MVP_MODE=false` (mode is null, absent, or the phase has no `**Mode:**` lin
|
|
|
167
171
|
**User-story format guard.** When `MVP_MODE=true`, also verify the phase's goal is in User Story format via the centralized validator:
|
|
168
172
|
|
|
169
173
|
```bash
|
|
174
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
170
175
|
PHASE_GOAL=$(pp_run query roadmap.get-phase "${phase_number}" ${GSD_WS} --pick goal)
|
|
171
176
|
USER_STORY_VALID=$(pp_run query user-story.validate --story "$PHASE_GOAL" --pick valid)
|
|
172
177
|
if [ "$USER_STORY_VALID" != "true" ]; then
|
|
@@ -434,7 +439,7 @@ Clear Current Test section:
|
|
|
434
439
|
|
|
435
440
|
Commit the UAT file:
|
|
436
441
|
```bash
|
|
437
|
-
pp_run query commit "
|
|
442
|
+
pp_run query commit "docs(planning): complete UAT - {passed} passed, {issues} issues" --phase "{phase_num}" --files ".planning/phases/XX-name/{phase_num}-UAT.md"
|
|
438
443
|
```
|
|
439
444
|
|
|
440
445
|
Present summary:
|
|
@@ -458,12 +463,13 @@ Present summary:
|
|
|
458
463
|
**If issues == 0:**
|
|
459
464
|
|
|
460
465
|
```bash
|
|
466
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
461
467
|
VERIFY_POST_HOOKS_JSON=$(pp_run loop render-hooks verify:post --raw)
|
|
462
468
|
printf '%s' "$VERIFY_POST_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('VERIFY_POST_HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
|
|
463
469
|
SECURITY_FILE=$(ls "${PHASE_DIR}"/*-SECURITY.md 2>/dev/null | head -1)
|
|
464
470
|
```
|
|
465
471
|
|
|
466
|
-
**Vault
|
|
472
|
+
**Vault gates.** Read `pp-core/workflows/execute-phase/steps/verify-post-gate.md` — it
|
|
467
473
|
dispatches this point's blocking gates to the generic enforcer, which owns the halt. Rendering the
|
|
468
474
|
payload above is not enforcing it, and the branch below marks the phase complete.
|
|
469
475
|
|
|
@@ -478,6 +484,7 @@ Skill(skill="pp-${ref.skill}", args="{phase}")
|
|
|
478
484
|
After the skill returns, refresh `SECURITY_FILE`:
|
|
479
485
|
|
|
480
486
|
```bash
|
|
487
|
+
[ -z "${ZSH_VERSION:-}" ] || emulate -R sh
|
|
481
488
|
SECURITY_FILE=$(ls "${PHASE_DIR}"/*-SECURITY.md 2>/dev/null | head -1)
|
|
482
489
|
```
|
|
483
490
|
|
|
@@ -1247,8 +1247,7 @@ function validateGate(gate, prefix) {
|
|
|
1247
1247
|
* - contribution.into ∈ step's agentRoles, OR contribution.into names an agent
|
|
1248
1248
|
* already registered by some capability's own `agents` array (a non-pipeline
|
|
1249
1249
|
* consumer of the same loop point, e.g. code-review.md reading execute:post
|
|
1250
|
-
* alongside execute-phase.md
|
|
1251
|
-
* execute:post -> pp-code-reviewer contribution)
|
|
1250
|
+
* alongside execute-phase.md)
|
|
1252
1251
|
* - when references a config key in cap.config
|
|
1253
1252
|
*
|
|
1254
1253
|
* NOTE: step.consumes satisfiability is NOT checked here — it requires the full
|
|
@@ -1331,78 +1330,9 @@ function validateAgainstContract(cap, capId, knownAgentIds) {
|
|
|
1331
1330
|
return errors;
|
|
1332
1331
|
}
|
|
1333
1332
|
|
|
1334
|
-
/**
|
|
1335
|
-
* Phase 15 D-02: validate the per-hook `vaultMode` filter field.
|
|
1336
|
-
*
|
|
1337
|
-
* The pure loop resolver evaluates `vaultMode` against an injected mode value
|
|
1338
|
-
* and never emits it, so an unknown or misplaced value must be refused HERE,
|
|
1339
|
-
* at generation, never interpreted at runtime. Three rules, each reported on
|
|
1340
|
-
* its own:
|
|
1341
|
-
* (a) the field is allowed on contributions and gates only (a step is
|
|
1342
|
-
* refused);
|
|
1343
|
-
* (b) the value must be a string in the vault capability's declared
|
|
1344
|
-
* `config["vault.mode"].values`. That enum declaration is the ONE owner of
|
|
1345
|
-
* the closed set; it is read here, never restated. With no vault
|
|
1346
|
-
* capability, or no such values array, there is no closed set and every
|
|
1347
|
-
* `vaultMode` is refused (fail closed);
|
|
1348
|
-
* (c) the declaring capability must be `vault` or list `vault` in `requires`,
|
|
1349
|
-
* so a filtered hook can only exist where the vault gate's closure holds.
|
|
1350
|
-
*
|
|
1351
|
-
* Presence is own-property presence, so a JSON `null` is refused under (b).
|
|
1352
|
-
*
|
|
1353
|
-
* @param {Map<string, object>} capMap
|
|
1354
|
-
* @returns {string[]} error strings; empty = all pass
|
|
1355
|
-
*/
|
|
1356
|
-
function validateVaultModeField(capMap) {
|
|
1357
|
-
const errors = [];
|
|
1358
|
-
const vaultCap = capMap.get('vault');
|
|
1359
|
-
const modeDecl = vaultCap && vaultCap.config && typeof vaultCap.config === 'object'
|
|
1360
|
-
? vaultCap.config['vault.mode']
|
|
1361
|
-
: undefined;
|
|
1362
|
-
const allowed = modeDecl && Array.isArray(modeDecl.values)
|
|
1363
|
-
? modeDecl.values.filter((v) => typeof v === 'string')
|
|
1364
|
-
: null;
|
|
1365
|
-
const KINDS = [['steps', 'step'], ['contributions', 'contribution'], ['gates', 'gate']];
|
|
1366
|
-
for (const [capId, cap] of capMap) {
|
|
1367
|
-
if (!cap || typeof cap !== 'object') continue;
|
|
1368
|
-
const prefix = 'capability "' + capId + '"';
|
|
1369
|
-
const requiresVault = Array.isArray(cap.requires) && cap.requires.includes('vault');
|
|
1370
|
-
for (const [arrKey, kind] of KINDS) {
|
|
1371
|
-
const arr = Array.isArray(cap[arrKey]) ? cap[arrKey] : [];
|
|
1372
|
-
for (const hook of arr) {
|
|
1373
|
-
if (!hook || typeof hook !== 'object') continue;
|
|
1374
|
-
if (!Object.prototype.hasOwnProperty.call(hook, 'vaultMode')) continue;
|
|
1375
|
-
const where = prefix + ' ' + kind + ' at point "' + String(hook.point) + '"';
|
|
1376
|
-
const value = hook.vaultMode;
|
|
1377
|
-
if (kind === 'step') {
|
|
1378
|
-
errors.push(where + ': vaultMode is allowed on contributions and gates only');
|
|
1379
|
-
}
|
|
1380
|
-
if (allowed === null) {
|
|
1381
|
-
errors.push(
|
|
1382
|
-
where + ': vaultMode ' + JSON.stringify(value) + ' cannot be checked: the vault capability ' +
|
|
1383
|
-
'declares no "vault.mode" values, which own the closed set',
|
|
1384
|
-
);
|
|
1385
|
-
} else if (typeof value !== 'string' || !allowed.includes(value)) {
|
|
1386
|
-
errors.push(
|
|
1387
|
-
where + ': vaultMode ' + JSON.stringify(value) + ' is not one of [' + allowed.join(', ') +
|
|
1388
|
-
'] (the closed set owned by the vault capability\'s "vault.mode" values)',
|
|
1389
|
-
);
|
|
1390
|
-
}
|
|
1391
|
-
if (capId !== 'vault' && !requiresVault) {
|
|
1392
|
-
errors.push(
|
|
1393
|
-
where + ': vaultMode is allowed only on the "vault" capability or a capability that ' +
|
|
1394
|
-
'lists "vault" in requires',
|
|
1395
|
-
);
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
return errors;
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
1333
|
/**
|
|
1404
1334
|
* Quick 261015-ect (QD-13): the vault-family rule for `requiresPlatformBindings`,
|
|
1405
|
-
*
|
|
1335
|
+
* A capability that is `vault` or
|
|
1406
1336
|
* lists `vault` in `requires` MUST declare the field, so a vault-family
|
|
1407
1337
|
* capability added later cannot render hooks on a project the vault does not
|
|
1408
1338
|
* govern by forgetting it. A capability outside the family may declare it too.
|
|
@@ -1441,18 +1371,15 @@ const SEAL_FIELD_NAME = 'onRecordedArtifacts';
|
|
|
1441
1371
|
* A gate carrying the field renders for an enabled, config-inactive capability
|
|
1442
1372
|
* over recorded vault artifacts, bypassing the capability's active check and
|
|
1443
1373
|
* its `when` (D-18). That is a widening of render behaviour, so the field is
|
|
1444
|
-
* closed HERE, at generation, to exactly the shape the
|
|
1445
|
-
*
|
|
1374
|
+
* closed HERE, at generation, to exactly the shape the shipped seal gate has.
|
|
1375
|
+
* Five rules, each reported on its own:
|
|
1446
1376
|
* (a) gates only (a step or contribution carrying it is refused);
|
|
1447
1377
|
* (b) the value is literal `true` (`"true"`, `1`, `null`, `false` refused);
|
|
1448
|
-
* (c) the declaring capability
|
|
1449
|
-
*
|
|
1450
|
-
*
|
|
1451
|
-
*
|
|
1452
|
-
* (
|
|
1453
|
-
* the predicate, research C-1);
|
|
1454
|
-
* (e) the gate is `blocking: true`;
|
|
1455
|
-
* (f) the point is `ship:pre` (D-21: the requirement's block point; a seal at
|
|
1378
|
+
* (c) the declaring capability is `vault` or lists `vault` in `requires`.
|
|
1379
|
+
* A seal gate never dispatches twice: the resolver drops it whenever its
|
|
1380
|
+
* capability is active, so it renders only with the vault switched off;
|
|
1381
|
+
* (d) the gate is `blocking: true`;
|
|
1382
|
+
* (e) the point is `ship:pre` (D-21: the requirement's block point; a seal at
|
|
1456
1383
|
* verify:post would halt execute-phase on a switch set on purpose).
|
|
1457
1384
|
*
|
|
1458
1385
|
* Presence is own-property presence.
|
|
@@ -1481,15 +1408,12 @@ function validateSealField(capMap) {
|
|
|
1481
1408
|
if (value !== true) {
|
|
1482
1409
|
errors.push(where + ': ' + SEAL_FIELD_NAME + ' must be literal true (got ' + JSON.stringify(value) + ')');
|
|
1483
1410
|
}
|
|
1484
|
-
if (capId
|
|
1411
|
+
if (capId !== 'vault' && !requiresVault) {
|
|
1485
1412
|
errors.push(
|
|
1486
|
-
where + ': ' + SEAL_FIELD_NAME + ' is allowed only on
|
|
1487
|
-
'
|
|
1413
|
+
where + ': ' + SEAL_FIELD_NAME + ' is allowed only on the "vault" capability or a capability that ' +
|
|
1414
|
+
'lists "vault" in requires',
|
|
1488
1415
|
);
|
|
1489
1416
|
}
|
|
1490
|
-
if (!Object.prototype.hasOwnProperty.call(hook, 'vaultMode')) {
|
|
1491
|
-
errors.push(where + ': a gate carrying ' + SEAL_FIELD_NAME + ' must also carry vaultMode');
|
|
1492
|
-
}
|
|
1493
1417
|
if (hook.blocking !== true) {
|
|
1494
1418
|
errors.push(where + ': a gate carrying ' + SEAL_FIELD_NAME + ' must be blocking: true');
|
|
1495
1419
|
}
|
|
@@ -1662,10 +1586,6 @@ const TIER_RANK = { core: 0, standard: 1, full: 2 };
|
|
|
1662
1586
|
function validateCrossCapability(capMap, centralKeys) {
|
|
1663
1587
|
const errors = [];
|
|
1664
1588
|
|
|
1665
|
-
// Phase 15 D-02: the per-hook vaultMode filter field (needs capMap to read the
|
|
1666
|
-
// vault capability's closed value set and every capability's `requires`).
|
|
1667
|
-
errors.push(...validateVaultModeField(capMap));
|
|
1668
|
-
|
|
1669
1589
|
// Phase 16 D-19: the per-hook seal field (needs capMap for every capability's
|
|
1670
1590
|
// `requires`).
|
|
1671
1591
|
errors.push(...validateSealField(capMap));
|
|
@@ -2841,7 +2761,6 @@ module.exports = {
|
|
|
2841
2761
|
validateAgainstContract,
|
|
2842
2762
|
validateConsumesGlobal,
|
|
2843
2763
|
validateCrossCapability,
|
|
2844
|
-
validateVaultModeField,
|
|
2845
2764
|
validateSealField,
|
|
2846
2765
|
validatePlatformBindingsField,
|
|
2847
2766
|
SEAL_FIELD_NAME,
|
|
@@ -114,14 +114,6 @@
|
|
|
114
114
|
],
|
|
115
115
|
"issue": "180"
|
|
116
116
|
},
|
|
117
|
-
"vault-review": {
|
|
118
|
-
"files": [
|
|
119
|
-
"vault-review.integration.test.cjs",
|
|
120
|
-
"vault-review.security.test.cjs",
|
|
121
|
-
"vault-review.test.cjs"
|
|
122
|
-
],
|
|
123
|
-
"issue": "71924 — Vault Assurance phase 06 (06-03/06-04), three distinct concerns for pp-core/bin/lib/vault-review.cjs: vault-review.test (06-03 unit tests over every pure derivation — the verdict vocabularies, both derived-N-A arms, the counts arithmetic, the range resolver and the clean-render refusal predicate), vault-review.integration.test (06-04 SEAM tests — the deterministic validator of the agent-written artifact, plus the `check vault-review` arm driven through the real pp-core/bin/pp-tools.cjs, where the exit-0/no-block-key contract of D-06-01 and VERIFY-03 is proved at the boundary a gate enforcer actually reads, with RED control 2 proving that guard non-vacuous), and vault-review.security.test (06-04 ADVERSARIAL tests — a spoofed external-content fence-end marker, directive-shaped text and a forged tool-call block planted in real practice BODIES, proving 05-REVIEW's open Critical CR-02 is not repeated on this surface, plus the CR-03 class: no absolute filesystem path in any emitted byte). The split mirrors the `vault` cluster's own reasoning: the unit lane, the CLI seam and the security marker are independently load-bearing verification gates, and the `.security.test.cjs` marker is what makes the adversarial lane identifiable to a reader and to scripts/run-tests.cjs. Consolidating would blur three different questions into one file."
|
|
124
|
-
},
|
|
125
117
|
"verify": {
|
|
126
118
|
"files": [
|
|
127
119
|
"bug-2969-verify-reapply-patches.test.cjs",
|
|
@@ -189,22 +181,12 @@
|
|
|
189
181
|
"files": [
|
|
190
182
|
"feat-71924-vault-required-gate.test.cjs",
|
|
191
183
|
"vault-doors.integration.test.cjs",
|
|
192
|
-
"vault-practices.property.test.cjs",
|
|
193
184
|
"vault-read-path.test.cjs",
|
|
194
185
|
"vault-security.test.cjs",
|
|
195
186
|
"vault-status-check.test.cjs",
|
|
196
187
|
"vault.test.cjs"
|
|
197
188
|
],
|
|
198
|
-
"issue": "v1.7.0 Client Vault Load — four distinct concerns: vault.test (fetch/status/summary unit), vault-security (VSEC-02/03 write-guard + secret/fence), vault-read-path (VGATE-03 SUMMARY pointer), vault-status-check (VGATE-02 gate-query handler).
|
|
199
|
-
},
|
|
200
|
-
"vault-practices": {
|
|
201
|
-
"files": [
|
|
202
|
-
"vault-practices-examples.test.cjs",
|
|
203
|
-
"vault-practices-matcher.test.cjs",
|
|
204
|
-
"vault-practices.slow.test.cjs",
|
|
205
|
-
"vault-practices.test.cjs"
|
|
206
|
-
],
|
|
207
|
-
"issue": "Phase 24 (24-01/24-02/24-04) — three distinct concerns for pp-core/bin/lib/vault-practices.cjs: vault-practices.test (24-01 parser/validation/discovery unit tests), vault-practices-matcher.test (24-02 glob matcher + two-bucket result + report unit tests), vault-practices-examples.test (24-04 shipped-example drift guard + minimal-comments global-bucket smoke case, PRAC-03 Success Criterion 3). All three test the same production module and are each independently load-bearing; consolidating would blur distinct plan-level verification gates. Vault Assurance phase 05 (#71924) added vault-practices.slow.test.cjs — the >5 s six-axis worst-case matcher corpus for the same production module (pp-core/bin/lib/vault-practices.cjs), split out per the .slow suffix convention so the default suite stays fast; attributed here once the count lint learned to strip the .slow suffix."
|
|
189
|
+
"issue": "v1.7.0 Client Vault Load — four distinct concerns: vault.test (fetch/status/summary unit), vault-security (VSEC-02/03 write-guard + secret/fence), vault-read-path (VGATE-03 SUMMARY pointer), vault-status-check (VGATE-02 gate-query handler). Vault Assurance phase 02 (#71924) added feat-71924-vault-required-gate.test.cjs as the phase's ONE consolidated source-grep feature file — it owns the source-text assertions for GATE-02, GATE-03, GATE-06, GATE-08, GATE-09 and GATE-10 together, deliberately in a single file so the phase's six requirements do not each spawn a sibling; later plans in the phase extend it rather than adding files. Vault Assurance phase 16 plan 10 added vault-doors.integration.test.cjs as the phase's ONE door fence-proof owner (DOOR-01..05, D-09): every door's shipped fence (execute-plan, quick, fast, debug, the secondary doors) composed by tests/helpers/gate-fence-composer.cjs and run in bash and zsh, one describe per door plan, so 16-12..16-15 extend it rather than each adding a sibling. The hyphen-prefix matcher attributes it here because no vault-doors module exists; it tests workflow fences, not vault.cjs."
|
|
208
190
|
}
|
|
209
191
|
}
|
|
210
192
|
}
|