@pareto4/pp-core 1.5.3 → 1.6.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/commands/pp-init.md +36 -0
- package/commands/pp-ns-project.md +2 -1
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/pp-core/bin/lib/capability-registry.cjs +135 -2
- package/pp-core/bin/lib/check-command-router.cjs +183 -1
- package/pp-core/bin/lib/clusters.cjs +1 -0
- package/pp-core/bin/lib/command-aliases.cjs +7 -0
- package/pp-core/bin/lib/io.cjs +2 -0
- package/pp-core/bin/lib/platform-bindings.cjs +336 -0
- package/pp-core/bin/lib/profile-output.cjs +220 -5
- package/pp-core/bin/pp-tools.cjs +40 -3
- package/pp-core/templates/claude-md.md +4 -4
- package/pp-core/workflows/discovery-sprint.md +27 -10
- package/pp-core/workflows/execute-phase/steps/client-context-gate.md +37 -0
- package/pp-core/workflows/execute-phase.md +4 -0
- package/pp-core/workflows/init.md +530 -0
- package/pp-core/workflows/new-project.md +54 -1
- package/pp-core/workflows/ship.md +24 -1
- package/pp-core/workflows/verify-work.md +1 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -0
package/pp-core/bin/pp-tools.cjs
CHANGED
|
@@ -209,6 +209,7 @@ const phase = require('./lib/phase.cjs');
|
|
|
209
209
|
const roadmap = require('./lib/roadmap.cjs');
|
|
210
210
|
const verify = require('./lib/verify.cjs');
|
|
211
211
|
const config = require('./lib/config.cjs');
|
|
212
|
+
const platformBindings = require('./lib/platform-bindings.cjs');
|
|
212
213
|
const template = require('./lib/template.cjs');
|
|
213
214
|
const milestone = require('./lib/milestone.cjs');
|
|
214
215
|
const commands = require('./lib/commands.cjs');
|
|
@@ -236,6 +237,7 @@ const { routeTaskCommand } = require('./lib/task-command-router.cjs');
|
|
|
236
237
|
const { parseNamedArgs, parseMultiwordArg } = require('./lib/command-arg-projection.cjs');
|
|
237
238
|
const { cmdGitBaseBranch } = require('./lib/git-base-branch.cjs');
|
|
238
239
|
const { getEffectiveAuthority, classifyDriftSeverity } = require('./lib/plan-drift-guard.cjs');
|
|
240
|
+
const profileOutput = require('./lib/profile-output.cjs');
|
|
239
241
|
|
|
240
242
|
// ─── Bridge collapsed (Phase 4) ────────────────────────────────────────────────
|
|
241
243
|
// Non-family commands now run through their CJS handlers directly. Keep the
|
|
@@ -521,10 +523,10 @@ async function main() {
|
|
|
521
523
|
'config-ensure-section, config-get, config-new-project, config-path, config-set, migrate-config, ' +
|
|
522
524
|
'current-timestamp, detect-custom-files, docs-init, drift-guard, effort, extract-messages, find-phase, ' +
|
|
523
525
|
'from-gsd2, frontmatter, gap-analysis, generate-claude-md, generate-claude-profile, ' +
|
|
524
|
-
'generate-dev-preferences, generate-slug, graphify, history-digest, init, intel, ' +
|
|
525
|
-
'capability, classify-confidence, git, learnings, list-todos, loop, milestone, package-legitimacy, phase, phase-plan-index, phases, profile-questionnaire, ' +
|
|
526
|
+
'generate-client-context, generate-dev-preferences, generate-slug, graphify, history-digest, init, intel, ' +
|
|
527
|
+
'capability, classify-confidence, git, learnings, list-todos, loop, milestone, package-legitimacy, phase, phase-plan-index, phases, platform-bindings, profile-questionnaire, ' +
|
|
526
528
|
'profile-sample, progress, prompt-budget, requirements, research-plan, research-store, resolve-granularity, resolve-model, roadmap, scaffold, state, ' +
|
|
527
|
-
'task, template, user-story, validate, verify, verify-path-exists, verify-summary, workstream, worktree\n\n' +
|
|
529
|
+
'task, template, user-story, validate, validate-bindings, verify, verify-path-exists, verify-summary, workstream, worktree\n\n' +
|
|
528
530
|
'Global flags:\n' +
|
|
529
531
|
' --raw Emit raw output without post-processing\n' +
|
|
530
532
|
' --pick <field> Extract a single field from JSON output (dot/bracket notation)\n' +
|
|
@@ -697,6 +699,41 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
697
699
|
break;
|
|
698
700
|
}
|
|
699
701
|
|
|
702
|
+
case 'platform-bindings': {
|
|
703
|
+
platformBindings.cmdPlatformBindings(cwd, args.slice(1), raw);
|
|
704
|
+
break;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
case 'validate-bindings': {
|
|
708
|
+
platformBindings.cmdValidateBindings(cwd, args.slice(1), raw);
|
|
709
|
+
break;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
case 'generate-client-context': {
|
|
713
|
+
// generate-client-context --from-json <path> [--output <path>] [--force]
|
|
714
|
+
// generate-client-context --read [--output <path>]
|
|
715
|
+
const gcArgs = args.slice(1);
|
|
716
|
+
const gcOptions = {};
|
|
717
|
+
for (let i = 0; i < gcArgs.length; i++) {
|
|
718
|
+
const a = gcArgs[i];
|
|
719
|
+
if (a === '--from-json') {
|
|
720
|
+
const v = gcArgs[i + 1];
|
|
721
|
+
if (v !== undefined && !v.startsWith('--')) { gcOptions.fromJson = v; i++; }
|
|
722
|
+
else error('--from-json requires a <path> argument');
|
|
723
|
+
} else if (a === '--output') {
|
|
724
|
+
const v = gcArgs[i + 1];
|
|
725
|
+
if (v !== undefined && !v.startsWith('--')) { gcOptions.output = v; i++; }
|
|
726
|
+
else error('--output requires a <path> argument');
|
|
727
|
+
} else if (a === '--read') {
|
|
728
|
+
gcOptions.read = true;
|
|
729
|
+
} else if (a === '--force') {
|
|
730
|
+
gcOptions.force = true;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
profileOutput.cmdGenerateClientContext(cwd, gcOptions, raw);
|
|
734
|
+
break;
|
|
735
|
+
}
|
|
736
|
+
|
|
700
737
|
case 'resolve-granularity': {
|
|
701
738
|
// Parse optional --granularity <val> flag (space form only); positional is phase-type.
|
|
702
739
|
// The =form (--granularity=<val>) is intentionally not supported: parseNamedArgs and
|
|
@@ -90,17 +90,17 @@ No project skills found. Add skills to any of: `.claude/skills/`, `.agents/skill
|
|
|
90
90
|
|
|
91
91
|
### Workflow Enforcement Section
|
|
92
92
|
```
|
|
93
|
-
<!-- PP:workflow-start source:
|
|
94
|
-
##
|
|
93
|
+
<!-- PP:workflow-start source:pp-core defaults -->
|
|
94
|
+
## pp-core Workflow Enforcement
|
|
95
95
|
|
|
96
|
-
Before using Edit, Write, or other file-changing tools, start work through a
|
|
96
|
+
Before using Edit, Write, or other file-changing tools, start work through a pp-core command so planning artifacts and execution context stay in sync.
|
|
97
97
|
|
|
98
98
|
Use these entry points:
|
|
99
99
|
- `/pp:quick` for small fixes, doc updates, and ad-hoc tasks
|
|
100
100
|
- `/pp:debug` for investigation and bug fixing
|
|
101
101
|
- `/pp:execute-phase` for planned phase work
|
|
102
102
|
|
|
103
|
-
Do not make direct repo edits outside a
|
|
103
|
+
Do not make direct repo edits outside a pp-core workflow unless the user explicitly asks to bypass it.
|
|
104
104
|
<!-- PP:workflow-end -->
|
|
105
105
|
```
|
|
106
106
|
|
|
@@ -16,7 +16,19 @@ First parse `SESSION_ARG` (the optional session number 1–13) from `$ARGUMENTS`
|
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
18
|
_PP_SHIM_NAME="pp-tools.cjs"; _PP_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; PP_TOOLS="${_PP_RUNTIME_ROOT}/pp-core/bin/${_PP_SHIM_NAME}"; if [ -f "$PP_TOOLS" ]; then pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif command -v pp-tools >/dev/null 2>&1; then PP_TOOLS="$(command -v pp-tools)"; pp_run() { "$PP_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$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
|
|
19
|
-
|
|
19
|
+
# WR-03: validate the FULL numeric token. The old pattern (1[0-3]|[1-9]) let grep
|
|
20
|
+
# truncate out-of-range input to a spuriously valid session (14→1, 25→2, 99→9).
|
|
21
|
+
# Extract the whole digit run, then range-check 1–13; flag anything else as invalid.
|
|
22
|
+
SESSION_RAW=$(printf '%s' "${ARGUMENTS:-}" | grep -oE '[0-9]+' | head -1)
|
|
23
|
+
SESSION_ARG=""
|
|
24
|
+
SESSION_INVALID=""
|
|
25
|
+
if [ -n "$SESSION_RAW" ]; then
|
|
26
|
+
if [ "$SESSION_RAW" -ge 1 ] 2>/dev/null && [ "$SESSION_RAW" -le 13 ] 2>/dev/null; then
|
|
27
|
+
SESSION_ARG="$SESSION_RAW"
|
|
28
|
+
else
|
|
29
|
+
SESSION_INVALID="$SESSION_RAW"
|
|
30
|
+
fi
|
|
31
|
+
fi
|
|
20
32
|
INIT=$(pp_run query init.phase-op "${SESSION_ARG:-}")
|
|
21
33
|
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
22
34
|
```
|
|
@@ -26,9 +38,10 @@ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
|
26
38
|
**Text mode:** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS` OR `text_mode` from init JSON is `true`. When TEXT_MODE is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (Codex, Gemini CLI, etc.) where `AskUserQuestion` is not available.
|
|
27
39
|
|
|
28
40
|
**Dispatch:**
|
|
29
|
-
- If `
|
|
30
|
-
|
|
31
|
-
-
|
|
41
|
+
- If `SESSION_INVALID` is non-empty → show a usage error: "Session `$SESSION_INVALID` is out
|
|
42
|
+
of range — valid sessions are 1–13." Do not run any session or the progress view.
|
|
43
|
+
- Else if `SESSION_ARG` is empty (no numeric argument) → execute **Flow 1: Show Progress**
|
|
44
|
+
- Else (`SESSION_ARG` is a number 1–13) → execute **Flow 2: Facilitate Session N**
|
|
32
45
|
|
|
33
46
|
---
|
|
34
47
|
|
|
@@ -694,8 +707,8 @@ This session uses the **Session 3: Process-First Protocol** (Steps 5A–5G descr
|
|
|
694
707
|
2. **Technology stack selection**
|
|
695
708
|
- What is the preferred frontend technology (React, Angular, Vue, Mendix, etc.)?
|
|
696
709
|
- What is the preferred backend technology (Node.js, .NET, Java, Python)?
|
|
697
|
-
- What database technology is appropriate (relational, document, graph, time-series)?
|
|
698
|
-
- What messaging or eventing technology will be used (Kafka, RabbitMQ
|
|
710
|
+
- What database technology is appropriate (relational e.g. Cloud SQL via pareto-platform-gcp, document, graph, time-series)?
|
|
711
|
+
- What messaging or eventing technology will be used (Google Cloud Pub/Sub via pareto-platform-gcp, Kafka, RabbitMQ)?
|
|
699
712
|
- What caching strategy applies (Redis, in-memory, CDN)?
|
|
700
713
|
|
|
701
714
|
3. **Key architectural components**
|
|
@@ -717,6 +730,8 @@ This session uses the **Session 3: Process-First Protocol** (Steps 5A–5G descr
|
|
|
717
730
|
|
|
718
731
|
**Notes Template:**
|
|
719
732
|
|
|
733
|
+
> **Platform standard (D-08):** The Pareto platform standard is GCP / `pareto-platform-gcp`. Fill this table against that baseline unless the client has an overriding constraint.
|
|
734
|
+
|
|
720
735
|
**Technology Stack Decisions**
|
|
721
736
|
|
|
722
737
|
| Layer | Technology | Version | Rationale | Alternatives Considered | Risk |
|
|
@@ -1129,7 +1144,7 @@ This session uses the **Session 3: Process-First Protocol** (Steps 5A–5G descr
|
|
|
1129
1144
|
**What We Cover:**
|
|
1130
1145
|
|
|
1131
1146
|
1. **Cloud / hosting strategy**
|
|
1132
|
-
- What cloud provider will be used (AWS, Azure,
|
|
1147
|
+
- What cloud provider will be used (GCP / `pareto-platform-gcp` is the Pareto platform standard; or AWS, Azure, on-premises, hybrid)?
|
|
1133
1148
|
- What is the account and subscription structure?
|
|
1134
1149
|
- What regions and availability zones are required?
|
|
1135
1150
|
- Are there data sovereignty or residency requirements that constrain hosting?
|
|
@@ -1138,12 +1153,12 @@ This session uses the **Session 3: Process-First Protocol** (Steps 5A–5G descr
|
|
|
1138
1153
|
2. **Deployment strategy**
|
|
1139
1154
|
- What deployment model will be used (blue-green, canary, rolling, immutable)?
|
|
1140
1155
|
- How will the CI/CD pipeline be structured?
|
|
1141
|
-
- What tools will be used for CI/CD (GitHub Actions, Azure DevOps,
|
|
1156
|
+
- What tools will be used for CI/CD (GitLab CI is the Pareto platform pipeline; or GitHub Actions, Azure DevOps, Jenkins)?
|
|
1142
1157
|
- How will infrastructure be managed (IaC with Terraform, Pulumi, CloudFormation)?
|
|
1143
|
-
- What is the approach to containerization (Docker
|
|
1158
|
+
- What is the approach to containerization (GKE or Cloud Run via pareto-platform-gcp; Docker/Kubernetes on-prem; or other cloud options)?
|
|
1144
1159
|
|
|
1145
1160
|
3. **Monitoring, logging, and alerting**
|
|
1146
|
-
- What monitoring platform will be used (Datadog, New Relic,
|
|
1161
|
+
- What monitoring platform will be used (Google Cloud Monitoring / Cloud Logging via pareto-platform-gcp; or Datadog, New Relic, CloudWatch)?
|
|
1147
1162
|
- What metrics will be tracked (latency, error rate, throughput, saturation)?
|
|
1148
1163
|
- What is the alerting strategy (thresholds, escalation chains, on-call rotation)?
|
|
1149
1164
|
- How will application logs be aggregated and queried?
|
|
@@ -1162,6 +1177,8 @@ This session uses the **Session 3: Process-First Protocol** (Steps 5A–5G descr
|
|
|
1162
1177
|
|
|
1163
1178
|
**Notes Template:**
|
|
1164
1179
|
|
|
1180
|
+
> **Platform standard (D-08):** The Pareto deployment platform is GCP / `pareto-platform-gcp` with GitLab CI as the CI/CD pipeline and Google Cloud Monitoring / Cloud Logging for observability. Fill the tables below against this baseline unless the client has an overriding constraint.
|
|
1181
|
+
|
|
1165
1182
|
**Infrastructure Architecture**
|
|
1166
1183
|
|
|
1167
1184
|
| Component | Service / Product | Region | Tier / SKU | Redundancy | Est. Monthly Cost | Notes |
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Client-context gate (Build) — execute-phase sub-step
|
|
2
|
+
|
|
3
|
+
Confirms the Build agent has client context in hand before any executor is dispatched.
|
|
4
|
+
Gated entirely on `.platform-bindings.json` (D-13 / D-04, mirroring Phase 9): when no
|
|
5
|
+
bindings file is present this gate is a **no-op** — no prompt fires and Build proceeds
|
|
6
|
+
unchanged. All checks are **offline** — this gate never calls Obsidian, MCP, or any network
|
|
7
|
+
resource. The captured `## Client Context & Patterns` block in CLAUDE.md (the Phase 9
|
|
8
|
+
artifact, already on the Build/Validate read path) is the source of truth; the live vault is
|
|
9
|
+
out of scope here.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
_PP_SHIM_NAME="pp-tools.cjs"; _PP_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; PP_TOOLS="${_PP_RUNTIME_ROOT}/pp-core/bin/${_PP_SHIM_NAME}"; if [ -f "$PP_TOOLS" ]; then pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif command -v pp-tools >/dev/null 2>&1; then PP_TOOLS="$(command -v pp-tools)"; pp_run() { "$PP_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$PP_TOOLS" "$@"; }; 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}"; pp_run() { node "$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
|
|
13
|
+
CTX_GATE_PRESENT=$(pp_run query platform-bindings --pick present 2>/dev/null || echo false)
|
|
14
|
+
CTX_BLOCK=$(pp_run query generate-client-context --read 2>/dev/null || echo '{"present":false}')
|
|
15
|
+
CTX_BLOCK_PRESENT=$(printf '%s' "$CTX_BLOCK" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{process.stdout.write(String((JSON.parse(d).present)||false));}catch{process.stdout.write('false');}")
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**If `CTX_GATE_PRESENT` != `true`:** skip entirely (non-Pareto project — fully inert).
|
|
19
|
+
|
|
20
|
+
**If `CTX_GATE_PRESENT` == `true` and `CTX_BLOCK_PRESENT` == `true`:** the client-context
|
|
21
|
+
block exists and is on the executor's read path. Surface a one-line confirmation
|
|
22
|
+
("Client context loaded from CLAUDE.md — Build will apply captured client patterns.") and
|
|
23
|
+
require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in
|
|
24
|
+
TEXT_MODE) before dispatching any executor. Advisory checkpoint, not a hard block.
|
|
25
|
+
|
|
26
|
+
**If `CTX_GATE_PRESENT` == `true` and `CTX_BLOCK_PRESENT` == `false`:** bindings indicate a
|
|
27
|
+
Pareto/client engagement but no client-context block was captured. Warn: "No
|
|
28
|
+
`## Client Context & Patterns` block found in CLAUDE.md — Build may proceed without client
|
|
29
|
+
patterns." Offer (`AskUserQuestion` / TEXT_MODE numbered list):
|
|
30
|
+
|
|
31
|
+
- **Capture now (recommended)** — pause and run `/pp-init` (its gated client-context step) to
|
|
32
|
+
write the block, then re-run `/pp-execute-phase`.
|
|
33
|
+
- **Proceed without** — continue knowingly; the executor builds without captured client
|
|
34
|
+
context. Requires an explicit `confirmed`.
|
|
35
|
+
|
|
36
|
+
`TEXT_MODE` follows the same rule as the host workflow (`--text` in `$ARGUMENTS`): replace
|
|
37
|
+
`AskUserQuestion` with a plain-text numbered prompt.
|
|
@@ -336,6 +336,10 @@ pp_run query state.begin-phase --phase "${PHASE_NUMBER}" --name "${PHASE_NAME}"
|
|
|
336
336
|
This updates Status, Last Activity, Current focus, Current Position, and plan counts in STATE.md so frontmatter and body text reflect the active phase immediately.
|
|
337
337
|
</step>
|
|
338
338
|
|
|
339
|
+
<step name="client_context_gate">
|
|
340
|
+
Read and execute `pp-core/workflows/execute-phase/steps/client-context-gate.md` — Pareto client-context gate (inert without `.platform-bindings.json`; confirms the Phase 9 CLAUDE.md block first).
|
|
341
|
+
</step>
|
|
342
|
+
|
|
339
343
|
<step name="discover_and_group_plans">
|
|
340
344
|
Load plan inventory with wave grouping in one call:
|
|
341
345
|
|