@pareto4/pp-core 1.6.0 → 1.7.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/agents/pp-code-fixer.md +3 -3
- package/bin/install.js +0 -6
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/pp-core/bin/lib/agent-install-check.cjs +1 -1
- package/pp-core/bin/lib/audit-command-router.cjs +3 -3
- package/pp-core/bin/lib/audit.cjs +1 -1
- package/pp-core/bin/lib/capability-activation.cjs +1 -1
- package/pp-core/bin/lib/capability-registry.cjs +177 -4
- package/pp-core/bin/lib/capability-state.cjs +1 -1
- package/pp-core/bin/lib/capability-writer.cjs +1 -1
- package/pp-core/bin/lib/check-command-router.cjs +82 -8
- package/pp-core/bin/lib/cjs-command-router-adapter.cjs +1 -1
- package/pp-core/bin/lib/code-review-flags.cjs +1 -1
- package/pp-core/bin/lib/config-loader.cjs +1 -1
- package/pp-core/bin/lib/config.cjs +1 -1
- package/pp-core/bin/lib/context-utilization.cjs +1 -1
- package/pp-core/bin/lib/docs.cjs +1 -1
- package/pp-core/bin/lib/frontmatter.cjs +1 -1
- package/pp-core/bin/lib/git-base-branch.cjs +2 -2
- package/pp-core/bin/lib/graphify-command-router.cjs +4 -4
- package/pp-core/bin/lib/graphify.cjs +1 -1
- package/pp-core/bin/lib/gsd2-import.cjs +1 -1
- package/pp-core/bin/lib/init-command-router.cjs +1 -1
- package/pp-core/bin/lib/init.cjs +1 -1
- package/pp-core/bin/lib/intel-command-router.cjs +5 -5
- package/pp-core/bin/lib/intel.cjs +1 -1
- package/pp-core/bin/lib/io.cjs +2 -2
- package/pp-core/bin/lib/loop-resolver.cjs +1 -1
- package/pp-core/bin/lib/phase-command-router.cjs +1 -1
- package/pp-core/bin/lib/phases-command-router.cjs +1 -1
- package/pp-core/bin/lib/plan-drift-guard.cjs +1 -1
- package/pp-core/bin/lib/platform-bindings.cjs +13 -0
- package/pp-core/bin/lib/prohibition-enforcement.cjs +2 -2
- package/pp-core/bin/lib/roadmap-command-router.cjs +2 -2
- package/pp-core/bin/lib/roadmap-parser.cjs +1 -1
- package/pp-core/bin/lib/state-command-router.cjs +1 -1
- package/pp-core/bin/lib/state.cjs +2 -2
- package/pp-core/bin/lib/validate-command-router.cjs +1 -1
- package/pp-core/bin/lib/vault-command-router.cjs +56 -0
- package/pp-core/bin/lib/vault.cjs +686 -0
- package/pp-core/bin/lib/verify-command-router.cjs +1 -1
- package/pp-core/bin/lib/verify.cjs +1 -1
- package/pp-core/bin/lib/worktree-base-ref.cjs +2 -2
- package/pp-core/bin/lib/worktree-safety.cjs +1 -1
- package/pp-core/bin/pp-tools.cjs +21 -21
- package/pp-core/bin/shared/config-defaults.manifest.json +2 -2
- package/pp-core/references/planning-config.md +10 -10
- package/pp-core/workflows/execute-phase/steps/vault-fetch.md +25 -0
- package/pp-core/workflows/execute-phase/steps/vault-load-gate.md +119 -0
- package/pp-core/workflows/plan-phase.md +12 -0
- package/pp-core/workflows/settings-advanced.md +4 -4
- package/scripts/lint-test-file-count.allowlist.json +9 -0
- package/assets/gsd-logo-2000-transparent.png +0 -0
- package/assets/gsd-logo-2000-transparent.svg +0 -17
- package/assets/gsd-logo-2000.png +0 -0
- package/assets/gsd-logo-2000.svg +0 -21
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* Manifest-backed verify subcommand router.
|
|
4
|
-
* Keeps
|
|
4
|
+
* Keeps pp-tools.cjs thin while preserving existing command semantics.
|
|
5
5
|
*
|
|
6
6
|
* ADR-457 build-at-publish: the hand-written bin/lib/verify-command-router.cjs
|
|
7
7
|
* collapsed to a TypeScript source of truth. Behaviour is preserved byte-for-behaviour
|
|
@@ -1432,7 +1432,7 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
1432
1432
|
getMilestoneFromPhaseId: getMilestoneFromPhaseId,
|
|
1433
1433
|
});
|
|
1434
1434
|
for (const mm of mismatches) {
|
|
1435
|
-
addIssue('warning', 'W021', `Phase ${mm.phaseId}: integer prefix implies ${mm.expectedMilestone} but listed under ${mm.foundInMilestone}`, 'Run `
|
|
1435
|
+
addIssue('warning', 'W021', `Phase ${mm.phaseId}: integer prefix implies ${mm.expectedMilestone} but listed under ${mm.foundInMilestone}`, 'Run `pp-tools roadmap upgrade --convention milestone-prefixed` to migrate (dry-run by default)');
|
|
1436
1436
|
}
|
|
1437
1437
|
}
|
|
1438
1438
|
}
|
|
@@ -94,9 +94,9 @@ function parseJsonc(text) {
|
|
|
94
94
|
}
|
|
95
95
|
// ─── Message constants (verbatim — downstream docs/tests depend on these) ─────
|
|
96
96
|
function buildMsgDiverged(headSha, forkRef, forkSha) {
|
|
97
|
-
return `⚠ Worktree base mismatch: HEAD (${shortSha(headSha)}) differs from ${forkRef} (${shortSha(forkSha)}). Running this phase sequentially on the main working tree. To keep parallel worktrees, set worktree.baseRef:"head" in .claude/settings.local.json (or run:
|
|
97
|
+
return `⚠ Worktree base mismatch: HEAD (${shortSha(headSha)}) differs from ${forkRef} (${shortSha(forkSha)}). Running this phase sequentially on the main working tree. To keep parallel worktrees, set worktree.baseRef:"head" in .claude/settings.local.json (or run: pp-tools worktree set-baseref). See #683.`;
|
|
98
98
|
}
|
|
99
|
-
const MSG_UNKNOWN = `⚠ Cannot determine the worktree fork base (origin/HEAD unresolved). Running this phase sequentially on the main working tree to avoid a base mismatch. To keep parallel worktrees, set worktree.baseRef:"head" in .claude/settings.local.json (or run:
|
|
99
|
+
const MSG_UNKNOWN = `⚠ Cannot determine the worktree fork base (origin/HEAD unresolved). Running this phase sequentially on the main working tree to avoid a base mismatch. To keep parallel worktrees, set worktree.baseRef:"head" in .claude/settings.local.json (or run: pp-tools worktree set-baseref). See #683.`;
|
|
100
100
|
// ─── Exports ──────────────────────────────────────────────────────────────────
|
|
101
101
|
/**
|
|
102
102
|
* Returns the first 8 characters of a SHA, or '' if null/empty.
|
|
@@ -958,7 +958,7 @@ function pruneOrphanedWorktrees(repoRoot) {
|
|
|
958
958
|
const plan = planWorktreePrune(repoRoot, { allowDestructive: false }, { parseWorktreePorcelain });
|
|
959
959
|
const pruneResult = executeWorktreePrunePlan(plan);
|
|
960
960
|
if (pruneResult && pruneResult.timedOut) {
|
|
961
|
-
process.stderr.write('[
|
|
961
|
+
process.stderr.write('[pp-tools] WARNING: worktree health check degraded' +
|
|
962
962
|
' — git worktree prune timed out after 10s.' +
|
|
963
963
|
' Orphaned worktree metadata may remain until the next successful run.\n');
|
|
964
964
|
}
|
package/pp-core/bin/pp-tools.cjs
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Replaces repetitive inline bash patterns across ~50 GSD command/workflow/agent files.
|
|
7
7
|
* Centralizes: config parsing, model resolution, phase lookup, git commits, summary verification.
|
|
8
8
|
*
|
|
9
|
-
* Usage: node
|
|
9
|
+
* Usage: node pp-tools.cjs <command> [args] [--raw] [--pick <field>]
|
|
10
10
|
*
|
|
11
11
|
* Atomic Commands:
|
|
12
12
|
* state load Load project config + state
|
|
@@ -253,7 +253,7 @@ const profileOutput = require('./lib/profile-output.cjs');
|
|
|
253
253
|
* @param {object} opts
|
|
254
254
|
* @param {string} opts.registryCommand - legacy bridge placeholder
|
|
255
255
|
* @param {string[]} opts.registryArgs - legacy bridge placeholder
|
|
256
|
-
* @param {string} opts.legacyCommand - original
|
|
256
|
+
* @param {string} opts.legacyCommand - original pp-tools command name
|
|
257
257
|
* @param {string[]} opts.legacyArgs - original args
|
|
258
258
|
* @param {string} opts.cwd - project dir
|
|
259
259
|
* @param {boolean} opts.raw - raw output mode
|
|
@@ -293,7 +293,7 @@ function _dispatchNonFamily({ registryCommand, registryArgs, legacyCommand, lega
|
|
|
293
293
|
* before requiring — defense-in-depth against corrupted/hand-edited registry entries.
|
|
294
294
|
*
|
|
295
295
|
* @param {object} opts
|
|
296
|
-
* @param {string} opts.command The command name (top-level
|
|
296
|
+
* @param {string} opts.command The command name (top-level pp-tools command)
|
|
297
297
|
* @param {string[]} opts.args Remaining args passed to the router
|
|
298
298
|
* @param {string} opts.cwd Project working directory
|
|
299
299
|
* @param {boolean} opts.raw Raw output mode flag
|
|
@@ -487,7 +487,7 @@ async function main() {
|
|
|
487
487
|
let command = args[0];
|
|
488
488
|
|
|
489
489
|
// Accept `query` as a meta-prefix for canonical dotted/spaced commands.
|
|
490
|
-
// Workflows may call `node
|
|
490
|
+
// Workflows may call `node pp-tools.cjs query <command>` directly.
|
|
491
491
|
if (command === 'query') {
|
|
492
492
|
args.shift();
|
|
493
493
|
command = args[0];
|
|
@@ -512,13 +512,13 @@ async function main() {
|
|
|
512
512
|
}
|
|
513
513
|
}
|
|
514
514
|
|
|
515
|
-
// Top-level usage string — emitted by `
|
|
516
|
-
// `
|
|
515
|
+
// Top-level usage string — emitted by `pp-tools` (no args) and by
|
|
516
|
+
// `pp-tools --help` / any `--help` request below.
|
|
517
517
|
// CR feedback: the command list must enumerate every top-level command
|
|
518
518
|
// supported by the dispatcher so `--help` is actually useful for
|
|
519
519
|
// discovery; previously it was a partial subset that didn't include
|
|
520
520
|
// phase / roadmap / milestone / progress / etc.
|
|
521
|
-
const TOP_LEVEL_USAGE = 'Usage:
|
|
521
|
+
const TOP_LEVEL_USAGE = 'Usage: pp-tools <command> [args] [--raw] [--pick <field>] [--cwd <path>] [--ws <name>] [--json-errors]\n' +
|
|
522
522
|
'Commands: agent, agent-skills, audit-open, audit-uat, check, check-commit, commit, commit-to-subrepo, ' +
|
|
523
523
|
'config-ensure-section, config-get, config-new-project, config-path, config-set, migrate-config, ' +
|
|
524
524
|
'current-timestamp, detect-custom-files, docs-init, drift-guard, effort, extract-messages, find-phase, ' +
|
|
@@ -534,7 +534,7 @@ async function main() {
|
|
|
534
534
|
' --ws <name> Override active workstream (or set GSD_WORKSTREAM)\n' +
|
|
535
535
|
' --json-errors Emit structured JSON error objects on stderr (or set GSD_JSON_ERRORS=1)\n\n' +
|
|
536
536
|
'For command-specific argument requirements, invoke the command without args ' +
|
|
537
|
-
'(e.g. `
|
|
537
|
+
'(e.g. `pp-tools phase add`) — the resulting error lists what is required.';
|
|
538
538
|
|
|
539
539
|
if (!command) {
|
|
540
540
|
error(TOP_LEVEL_USAGE);
|
|
@@ -558,7 +558,7 @@ async function main() {
|
|
|
558
558
|
const NEVER_VALID_FLAGS = new Set(['--version', '-v']);
|
|
559
559
|
for (const arg of args) {
|
|
560
560
|
if (NEVER_VALID_FLAGS.has(arg)) {
|
|
561
|
-
error(`Unknown flag: ${arg}\
|
|
561
|
+
error(`Unknown flag: ${arg}\npp-tools does not accept version flags. Run "pp-tools" with no arguments for usage.`, ERROR_REASON.USAGE);
|
|
562
562
|
}
|
|
563
563
|
}
|
|
564
564
|
|
|
@@ -1537,18 +1537,18 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1537
1537
|
} else if (subcommand === 'query') {
|
|
1538
1538
|
const tagIdx = args.indexOf('--tag');
|
|
1539
1539
|
const tag = tagIdx !== -1 ? args[tagIdx + 1] : null;
|
|
1540
|
-
if (!tag) error('Usage:
|
|
1540
|
+
if (!tag) error('Usage: pp-tools learnings query --tag <tag>', ERROR_REASON.USAGE);
|
|
1541
1541
|
learnings.cmdLearningsQuery(tag, raw);
|
|
1542
1542
|
} else if (subcommand === 'copy') {
|
|
1543
1543
|
learnings.cmdLearningsCopy(cwd, raw);
|
|
1544
1544
|
} else if (subcommand === 'prune') {
|
|
1545
1545
|
const olderIdx = args.indexOf('--older-than');
|
|
1546
1546
|
const olderThan = olderIdx !== -1 ? args[olderIdx + 1] : null;
|
|
1547
|
-
if (!olderThan) error('Usage:
|
|
1547
|
+
if (!olderThan) error('Usage: pp-tools learnings prune --older-than <duration>', ERROR_REASON.USAGE);
|
|
1548
1548
|
learnings.cmdLearningsPrune(olderThan, raw);
|
|
1549
1549
|
} else if (subcommand === 'delete') {
|
|
1550
1550
|
const id = args[2];
|
|
1551
|
-
if (!id) error('Usage:
|
|
1551
|
+
if (!id) error('Usage: pp-tools learnings delete <id>', ERROR_REASON.USAGE);
|
|
1552
1552
|
learnings.cmdLearningsDelete(id, raw);
|
|
1553
1553
|
} else {
|
|
1554
1554
|
error('Unknown learnings subcommand. Available: list, query, copy, prune, delete', ERROR_REASON.SDK_UNKNOWN_COMMAND);
|
|
@@ -1587,7 +1587,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1587
1587
|
const configDirIdx = args.indexOf('--config-dir');
|
|
1588
1588
|
const configDir = configDirIdx !== -1 ? args[configDirIdx + 1] : null;
|
|
1589
1589
|
if (!configDir) {
|
|
1590
|
-
error('Usage:
|
|
1590
|
+
error('Usage: pp-tools detect-custom-files --config-dir <path>', ERROR_REASON.USAGE);
|
|
1591
1591
|
}
|
|
1592
1592
|
const resolvedConfigDir = path.resolve(configDir);
|
|
1593
1593
|
if (!fs.existsSync(resolvedConfigDir)) {
|
|
@@ -1896,7 +1896,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1896
1896
|
if (subcommand === 'get') {
|
|
1897
1897
|
const key = args[2];
|
|
1898
1898
|
if (!key || key.startsWith('--')) {
|
|
1899
|
-
error('Usage:
|
|
1899
|
+
error('Usage: pp-tools research-store get <key> [--kind <k>]', ERROR_REASON.USAGE);
|
|
1900
1900
|
}
|
|
1901
1901
|
if (!researchStore.isValidResearchKey(key)) {
|
|
1902
1902
|
error('research-store: <key> must be a 64-char sha256 hex (use research-plan to obtain keys)', ERROR_REASON.USAGE);
|
|
@@ -1907,7 +1907,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1907
1907
|
} else if (subcommand === 'put') {
|
|
1908
1908
|
const key = args[2];
|
|
1909
1909
|
if (!key || key.startsWith('--')) {
|
|
1910
|
-
error('Usage:
|
|
1910
|
+
error('Usage: pp-tools research-store put <key> --content <str> --source <s> --provider <p> --confidence <c> --kind <k>', ERROR_REASON.USAGE);
|
|
1911
1911
|
}
|
|
1912
1912
|
if (!researchStore.isValidResearchKey(key)) {
|
|
1913
1913
|
error('research-store: <key> must be a 64-char sha256 hex (use research-plan to obtain keys)', ERROR_REASON.USAGE);
|
|
@@ -1932,7 +1932,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1932
1932
|
const confidence = getFlagValue(confidenceIdx, '--confidence');
|
|
1933
1933
|
const kind = getFlagValue(kindIdx, '--kind');
|
|
1934
1934
|
if (!content || !source || !provider || !confidence || !kind) {
|
|
1935
|
-
error('Usage:
|
|
1935
|
+
error('Usage: pp-tools research-store put <key> --content <str> --source <s> --provider <p> --confidence <c> --kind <k>', ERROR_REASON.USAGE);
|
|
1936
1936
|
}
|
|
1937
1937
|
const entry = researchStore.putResearch(cwd, key, { content, source, provider, confidence, kind }, { homeDir });
|
|
1938
1938
|
output(entry, raw);
|
|
@@ -1953,7 +1953,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1953
1953
|
const inputIdx = args.indexOf('--input');
|
|
1954
1954
|
const inputPath = inputIdx !== -1 ? args[inputIdx + 1] : null;
|
|
1955
1955
|
if (!inputPath || inputPath.startsWith('--')) {
|
|
1956
|
-
error('Usage:
|
|
1956
|
+
error('Usage: pp-tools research-plan --input <path>', ERROR_REASON.USAGE);
|
|
1957
1957
|
}
|
|
1958
1958
|
let planInput;
|
|
1959
1959
|
try {
|
|
@@ -1987,7 +1987,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1987
1987
|
const providerIdx = args.indexOf('--provider');
|
|
1988
1988
|
const provider = providerIdx !== -1 ? args[providerIdx + 1] : null;
|
|
1989
1989
|
if (!provider || provider.startsWith('--')) {
|
|
1990
|
-
error('Usage:
|
|
1990
|
+
error('Usage: pp-tools query classify-confidence --provider <id> [--package <name> --ecosystem <npm|pypi|crates>] [--verified]', ERROR_REASON.USAGE);
|
|
1991
1991
|
}
|
|
1992
1992
|
const verified = args.includes('--verified');
|
|
1993
1993
|
const pkgIdx = args.indexOf('--package');
|
|
@@ -1998,7 +1998,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1998
1998
|
if (pkg && (!pkg.startsWith('--'))) {
|
|
1999
1999
|
const VALID_ECOSYSTEMS = new Set(['npm', 'pypi', 'crates']);
|
|
2000
2000
|
if (!ecosystem || ecosystem.startsWith('--') || !VALID_ECOSYSTEMS.has(ecosystem)) {
|
|
2001
|
-
error('Usage:
|
|
2001
|
+
error('Usage: pp-tools query classify-confidence --provider <id> [--package <name> --ecosystem <npm|pypi|crates>] [--verified]', ERROR_REASON.USAGE);
|
|
2002
2002
|
}
|
|
2003
2003
|
const pkgLegitimacy = require('./lib/package-legitimacy.cjs');
|
|
2004
2004
|
const results = await pkgLegitimacy.checkPackages({ ecosystem, packages: [pkg] }, {});
|
|
@@ -2026,7 +2026,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
2026
2026
|
const ecosystem = ecoIdx !== -1 ? args[ecoIdx + 1] : null;
|
|
2027
2027
|
const VALID_ECOSYSTEMS = new Set(['npm', 'pypi', 'crates']);
|
|
2028
2028
|
if (!ecosystem || !VALID_ECOSYSTEMS.has(ecosystem)) {
|
|
2029
|
-
error('Usage:
|
|
2029
|
+
error('Usage: pp-tools package-legitimacy check --ecosystem <npm|pypi|crates> <pkg1> ...', ERROR_REASON.USAGE);
|
|
2030
2030
|
}
|
|
2031
2031
|
// Collect positional package names.
|
|
2032
2032
|
// Only --ecosystem takes a value. Every non-flag arg is a package name.
|
|
@@ -2041,7 +2041,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
2041
2041
|
packages.push(a);
|
|
2042
2042
|
}
|
|
2043
2043
|
if (packages.length === 0) {
|
|
2044
|
-
error('Usage:
|
|
2044
|
+
error('Usage: pp-tools package-legitimacy check --ecosystem <eco> <pkg1> <pkg2> ...', ERROR_REASON.USAGE);
|
|
2045
2045
|
}
|
|
2046
2046
|
let pkgResults;
|
|
2047
2047
|
try {
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"branching_strategy": "none",
|
|
19
19
|
"create_tag": true,
|
|
20
20
|
"base_branch": null,
|
|
21
|
-
"phase_branch_template": "
|
|
22
|
-
"milestone_branch_template": "
|
|
21
|
+
"phase_branch_template": "pp/phase-{phase}-{slug}",
|
|
22
|
+
"milestone_branch_template": "pp/{milestone}-{slug}",
|
|
23
23
|
"quick_branch_template": null
|
|
24
24
|
},
|
|
25
25
|
"workflow": {
|
|
@@ -11,8 +11,8 @@ Configuration options for `.planning/` directory behavior.
|
|
|
11
11
|
"git": {
|
|
12
12
|
"branching_strategy": "none",
|
|
13
13
|
"base_branch": null,
|
|
14
|
-
"phase_branch_template": "
|
|
15
|
-
"milestone_branch_template": "
|
|
14
|
+
"phase_branch_template": "pp/phase-{phase}-{slug}",
|
|
15
|
+
"milestone_branch_template": "pp/{milestone}-{slug}",
|
|
16
16
|
"quick_branch_template": null
|
|
17
17
|
},
|
|
18
18
|
"manager": {
|
|
@@ -31,8 +31,8 @@ Configuration options for `.planning/` directory behavior.
|
|
|
31
31
|
| `git.branching_strategy` | `"none"` | Git branching approach: `"none"`, `"phase"`, or `"milestone"` |
|
|
32
32
|
| `git.base_branch` | `null` (auto-detect) | Target branch for PRs and merges (e.g. `"master"`, `"develop"`). When `null`, auto-detects from `git symbolic-ref refs/remotes/origin/HEAD`, falling back to `"main"`. |
|
|
33
33
|
| `git.create_tag` | `true` | Create git tags on milestone completion |
|
|
34
|
-
| `git.phase_branch_template` | `"
|
|
35
|
-
| `git.milestone_branch_template` | `"
|
|
34
|
+
| `git.phase_branch_template` | `"pp/phase-{phase}-{slug}"` | Branch template for phase strategy |
|
|
35
|
+
| `git.milestone_branch_template` | `"pp/{milestone}-{slug}"` | Branch template for milestone strategy |
|
|
36
36
|
| `git.quick_branch_template` | `null` | Optional branch template for quick-task runs |
|
|
37
37
|
| `workflow.use_worktrees` | `true` | Whether executor agents run in isolated git worktrees. Set to `false` to disable worktrees — agents execute sequentially on the main working tree instead. Recommended for solo developers or when worktree merges cause issues. Note: if your branch is ahead of `origin/HEAD` (a diverged milestone or feature branch), pp-core auto-degrades to sequential and prints a warning; set `worktree.baseRef:"head"` in `.claude/settings.local.json` to restore parallel execution. See the branch-divergence note below. |
|
|
38
38
|
| `workflow.subagent_timeout` | `300000` | Timeout in milliseconds for parallel subagent tasks (e.g. codebase mapping). Increase for large codebases or slower models. Default: 300000 (5 minutes). |
|
|
@@ -144,14 +144,14 @@ To use uncommitted mode:
|
|
|
144
144
|
|
|
145
145
|
**When `git.branching_strategy: "phase"`:**
|
|
146
146
|
- `execute-phase` creates/switches to a branch before execution
|
|
147
|
-
- Branch name from `phase_branch_template` (e.g., `
|
|
147
|
+
- Branch name from `phase_branch_template` (e.g., `pp/phase-03-authentication`)
|
|
148
148
|
- All plan commits go to that branch
|
|
149
149
|
- User merges branches manually after phase completion
|
|
150
150
|
- `complete-milestone` offers to merge all phase branches
|
|
151
151
|
|
|
152
152
|
**When `git.branching_strategy: "milestone"`:**
|
|
153
153
|
- First `execute-phase` of milestone creates the milestone branch
|
|
154
|
-
- Branch name from `milestone_branch_template` (e.g., `
|
|
154
|
+
- Branch name from `milestone_branch_template` (e.g., `pp/v1.0-mvp`)
|
|
155
155
|
- All phases in milestone commit to same branch
|
|
156
156
|
- `complete-milestone` offers to merge milestone branch to main
|
|
157
157
|
|
|
@@ -292,8 +292,8 @@ Set via `git.*` namespace (e.g., `"git": { "branching_strategy": "phase" }`).
|
|
|
292
292
|
| `git.branching_strategy` | string | `"none"` | `"none"`, `"phase"`, `"milestone"` | Git branching approach for phase/milestone isolation |
|
|
293
293
|
| `git.base_branch` | string\|null | `null` (auto-detect) | Any branch name | Target branch for PRs and merges; auto-detects from `origin/HEAD` when `null` |
|
|
294
294
|
| `git.create_tag` | boolean | `true` | `true`, `false` | Create git tags on milestone completion |
|
|
295
|
-
| `git.phase_branch_template` | string | `"
|
|
296
|
-
| `git.milestone_branch_template` | string | `"
|
|
295
|
+
| `git.phase_branch_template` | string | `"pp/phase-{phase}-{slug}"` | Template with `{phase}`, `{slug}` | Branch naming template for `phase` strategy |
|
|
296
|
+
| `git.milestone_branch_template` | string | `"pp/{milestone}-{slug}"` | Template with `{milestone}`, `{slug}` | Branch naming template for `milestone` strategy |
|
|
297
297
|
| `git.quick_branch_template` | string\|null | `null` | Template with `{slug}` | Optional branch template for quick-task runs |
|
|
298
298
|
|
|
299
299
|
### Search & API Fields
|
|
@@ -420,7 +420,7 @@ Several config fields affect each other or trigger special behavior:
|
|
|
420
420
|
"git": {
|
|
421
421
|
"branching_strategy": "phase",
|
|
422
422
|
"base_branch": "develop",
|
|
423
|
-
"phase_branch_template": "
|
|
423
|
+
"phase_branch_template": "pp/phase-{phase}-{slug}"
|
|
424
424
|
},
|
|
425
425
|
"workflow": {
|
|
426
426
|
"research": true,
|
|
@@ -452,7 +452,7 @@ Several config fields affect each other or trigger special behavior:
|
|
|
452
452
|
"phase_naming": "sequential",
|
|
453
453
|
"git": {
|
|
454
454
|
"branching_strategy": "milestone",
|
|
455
|
-
"milestone_branch_template": "
|
|
455
|
+
"milestone_branch_template": "pp/{milestone}-{slug}"
|
|
456
456
|
},
|
|
457
457
|
"workflow": {
|
|
458
458
|
"research": true,
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# plan:pre vault fetch + summary (bespoke step dispatch — a0)
|
|
2
|
+
|
|
3
|
+
Capability-driven dispatch for an active plan:pre step hook where `kind == "step"` and `capId == "vault"`. Runs `vault fetch` then `vault summary` so `.planning/vault/SUMMARY.md` exists on the researcher and planner read paths before the researcher Agent() spawn. The generic step contract dispatches only `ref.skill`/`ref.agent` hooks — not `ref.command` — so this bespoke block owns the `vault fetch` command run. The registry evaluates `when: vault.enabled`; an inert capability yields no hook. `onError: skip` — any failure logs a warning and planning continues; never hard-fails.
|
|
4
|
+
|
|
5
|
+
Read the active plan:pre step hook from `PLAN_PRE_HOOKS_JSON` (in-context) where `kind == "step"` and `capId == "vault"`.
|
|
6
|
+
|
|
7
|
+
**If no active vault step hook exists:** skip (non-Pareto project, `vault.enabled` false, or vault bindings absent).
|
|
8
|
+
|
|
9
|
+
**If an active vault step hook exists** (recognizable by `capId == "vault"` + `ref.command == "vault fetch"`):
|
|
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
|
+
# vault fetch: populates .planning/vault/ cache + manifest
|
|
14
|
+
if ! pp_run vault fetch 2>&1; then
|
|
15
|
+
echo "⚠ vault fetch failed — continuing without vault context (onError:skip)" >&2
|
|
16
|
+
else
|
|
17
|
+
# vault summary: writes .planning/vault/SUMMARY.md — the bounded index
|
|
18
|
+
# that planner, researcher, and executor pointers reference.
|
|
19
|
+
if ! pp_run vault summary 2>&1; then
|
|
20
|
+
echo "⚠ vault summary failed — SUMMARY.md may be absent (onError:skip)" >&2
|
|
21
|
+
else
|
|
22
|
+
echo "✓ vault fetch + summary complete: .planning/vault/SUMMARY.md"
|
|
23
|
+
fi
|
|
24
|
+
fi
|
|
25
|
+
```
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Vault load gate — advisory (plan:pre + execute:pre)
|
|
2
|
+
|
|
3
|
+
Advisory gate that confirms vault load state before planning or build. The host sets
|
|
4
|
+
`VAULT_GATE_POINT` to `plan` (for plan:pre) or `execute` (for execute:pre) before
|
|
5
|
+
executing this step — **one file serves both call sites** (D-05). The §8 message table
|
|
6
|
+
(design §8) column is selected by this parameter.
|
|
7
|
+
|
|
8
|
+
Gated entirely on `.platform-bindings.json`: when no bindings file is present, this gate
|
|
9
|
+
is a **no-op** — fully inert for non-Pareto projects. The verdict is read from
|
|
10
|
+
`pp_run check vault.status --raw` — a pure manifest read that never fetches, never errors,
|
|
11
|
+
and degrades to `{"present":false}` on any problem (D-02).
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
_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
|
|
15
|
+
VAULT_GATE_PRESENT=$(pp_run query platform-bindings --pick present 2>/dev/null || echo false)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**If `VAULT_GATE_PRESENT` != `true`:** skip entirely (non-Pareto project — fully inert).
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
VAULT_VERDICT=$(pp_run check vault.status --raw 2>/dev/null || echo '{"present":false}')
|
|
22
|
+
VAULT_STATUS=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{process.stdout.write(JSON.parse(d).status||'miss');}catch{process.stdout.write('miss');}")
|
|
23
|
+
VAULT_TIER=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{process.stdout.write(JSON.parse(d).tier||'');}catch{process.stdout.write('');}")
|
|
24
|
+
VAULT_FALLBACK_REASON=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{process.stdout.write(JSON.parse(d).fallbackReason||'');}catch{process.stdout.write('');}")
|
|
25
|
+
VAULT_REPO=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const p=JSON.parse(d);process.stdout.write(p.repo||p.source||'');}catch{process.stdout.write('');}")
|
|
26
|
+
VAULT_REF=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{process.stdout.write(JSON.parse(d).ref||'');}catch{process.stdout.write('');}")
|
|
27
|
+
VAULT_SHA=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const s=JSON.parse(d).resolvedSha||'';process.stdout.write(s.slice(0,8));}catch{process.stdout.write('');}")
|
|
28
|
+
VAULT_FILE_COUNT=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{process.stdout.write(String(JSON.parse(d).fileCount??0));}catch{process.stdout.write('0');}")
|
|
29
|
+
VAULT_STALE=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{process.stdout.write(String(!!JSON.parse(d).stale));}catch{process.stdout.write('false');}")
|
|
30
|
+
VAULT_FETCHED_AT=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{process.stdout.write(JSON.parse(d).fetchedAt||'');}catch{process.stdout.write('');}")
|
|
31
|
+
# Compute human-readable cache age when stale
|
|
32
|
+
VAULT_AGE=""
|
|
33
|
+
if [ "$VAULT_STALE" = "true" ] && [ -n "$VAULT_FETCHED_AT" ]; then
|
|
34
|
+
VAULT_AGE=$(VAULT_FETCHED_AT="$VAULT_FETCHED_AT" node -e "const ms=Date.now()-new Date(process.env.VAULT_FETCHED_AT).getTime();const d=Math.floor(ms/86400000);const h=Math.floor((ms%86400000)/3600000);process.stdout.write(d>0?d+'d':h+'h');")
|
|
35
|
+
fi
|
|
36
|
+
# Detect --auto / --chain in host $ARGUMENTS (non-interactive pipeline mode — D-08)
|
|
37
|
+
AUTO_MODE=false
|
|
38
|
+
if echo "${ARGUMENTS:-}" | grep -qE -- '--auto|--chain'; then AUTO_MODE=true; fi
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Select message based on `VAULT_STATUS`, `VAULT_TIER`, and `VAULT_GATE_POINT`, then handle confirmation.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## §8 Message table — plan:pre column (`VAULT_GATE_POINT` == `plan`)
|
|
46
|
+
|
|
47
|
+
**`fetched` + `tier: client`:**
|
|
48
|
+
|
|
49
|
+
> Client vault loaded from `` `${VAULT_REPO}@${VAULT_REF}` `` (`` `${VAULT_FILE_COUNT}` `` files, sha `` `${VAULT_SHA}` ``). Planning will apply client standards.
|
|
50
|
+
|
|
51
|
+
Surface this message and require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in TEXT_MODE). Advisory checkpoint, not a hard block.
|
|
52
|
+
|
|
53
|
+
**`fetched` + `tier: fallback` (intentionally more prominent — design §8):**
|
|
54
|
+
|
|
55
|
+
> ℹ Loaded **shared Pareto vault** `` `${VAULT_REPO}@${VAULT_REF}` `` (`` `${VAULT_FILE_COUNT}` `` files) — *${VAULT_FALLBACK_REASON}*. Planning will apply Pareto defaults, not client-specific standards. Proceed?
|
|
56
|
+
|
|
57
|
+
Surface this message and require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in TEXT_MODE). The fallback confirmation is deliberately more prominent than the client tier: proceeding on Pareto defaults instead of the client's own standards is a state the user should consciously acknowledge.
|
|
58
|
+
|
|
59
|
+
**`cache` (all tiers failed, using cached copy):**
|
|
60
|
+
|
|
61
|
+
> ⚠ Could not reach client or shared vault — using cached copy from `` `${VAULT_FETCHED_AT}` `` (tier `` `${VAULT_TIER}` ``, may be stale). Proceed?
|
|
62
|
+
|
|
63
|
+
Surface this warning and require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in TEXT_MODE).
|
|
64
|
+
|
|
65
|
+
**`miss` (no vault reachable, no cached copy):**
|
|
66
|
+
|
|
67
|
+
> ⚠ No vault reachable (client or shared) and no cached copy. Planning will proceed WITHOUT vault context.
|
|
68
|
+
|
|
69
|
+
Surface this warning and require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in TEXT_MODE).
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## §8 Message table — execute:pre column (`VAULT_GATE_POINT` == `execute`)
|
|
74
|
+
|
|
75
|
+
**`fetched` + `tier: client`:**
|
|
76
|
+
|
|
77
|
+
> Client vault present (`` `${VAULT_REPO}@${VAULT_REF}` ``). Build will apply client patterns.
|
|
78
|
+
|
|
79
|
+
Surface this message and require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in TEXT_MODE). Advisory checkpoint, not a hard block.
|
|
80
|
+
|
|
81
|
+
**`fetched` + `tier: fallback` (intentionally more prominent — design §8):**
|
|
82
|
+
|
|
83
|
+
> ℹ Using shared Pareto vault — *${VAULT_FALLBACK_REASON}*. Build applies Pareto defaults. Proceed?
|
|
84
|
+
|
|
85
|
+
Surface this message and require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in TEXT_MODE). The fallback confirmation is deliberately more prominent than the client tier.
|
|
86
|
+
|
|
87
|
+
**`cache` (all tiers failed, using cached copy):**
|
|
88
|
+
|
|
89
|
+
> ⚠ Could not reach client or shared vault — using cached copy from `` `${VAULT_FETCHED_AT}` `` (tier `` `${VAULT_TIER}` ``, may be stale). Proceed?
|
|
90
|
+
|
|
91
|
+
Surface this warning and require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in TEXT_MODE).
|
|
92
|
+
|
|
93
|
+
**`miss` (no vault reachable, no cached copy):**
|
|
94
|
+
|
|
95
|
+
> ⚠ No vault reachable (client or shared) and no cached copy. Build will proceed WITHOUT vault context.
|
|
96
|
+
|
|
97
|
+
Surface this warning and require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in TEXT_MODE).
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Stale suffix (applies to all statuses)
|
|
102
|
+
|
|
103
|
+
When `VAULT_STALE` is `true`, append ` (cache is \`${VAULT_AGE}\` old)` to the selected message before surfacing it to the user.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## --auto / --chain behavior (D-08)
|
|
108
|
+
|
|
109
|
+
When `AUTO_MODE` is `true`: **do not display an interactive prompt**. Instead, print the selected message (including stale suffix when applicable) as a log line, then continue without requiring `confirmed`. This ensures a non-interactive pipeline run leaves an auditable record that Pareto defaults / cache / miss were in effect — especially important for the `tier: fallback`, `cache`, and `miss` cases. Never hard-blocks.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Confirmation (interactive mode)
|
|
114
|
+
|
|
115
|
+
When `AUTO_MODE` is `false`:
|
|
116
|
+
|
|
117
|
+
Use `AskUserQuestion` to surface the selected message and await `confirmed`. In TEXT_MODE (`--text` in `$ARGUMENTS`), replace `AskUserQuestion` with a plain-text prompt and accept a typed `confirmed`. This is an advisory checkpoint only — the gate **never hard-blocks**; proceeding after `confirmed` (or with a timeout / empty input) is always allowed.
|
|
118
|
+
|
|
119
|
+
`TEXT_MODE` follows the same rule as the host workflow (`--text` in `$ARGUMENTS`): replace `AskUserQuestion` with a plain-text numbered prompt.
|
|
@@ -512,6 +512,14 @@ if [ -z "${PLAN_PRE_HOOKS_JSON:-}" ]; then
|
|
|
512
512
|
fi
|
|
513
513
|
```
|
|
514
514
|
|
|
515
|
+
### plan:pre vault fetch + summary
|
|
516
|
+
|
|
517
|
+
With `PLAN_PRE_HOOKS_JSON` already loaded, Read and execute `pp-core/workflows/execute-phase/steps/vault-fetch.md` — the bespoke plan:pre vault fetch + summary dispatch (active only for a `capId == "vault"` step hook; produces `.planning/vault/SUMMARY.md` for the researcher/planner read paths; `onError:skip`). Skip silently when none.
|
|
518
|
+
|
|
519
|
+
### into:researcher contributions
|
|
520
|
+
|
|
521
|
+
In `PLAN_PRE_HOOKS_JSON`, read active plan:pre entries where `kind == "contribution"` and `into == "researcher"` (in array order). If none, inject nothing. If present, append each entry's `fragment.inline` verbatim to `filled_research_hook_fragment` (or add it as a `<files_to_read>`/context line in the researcher prompt) — typically a pointer to `.planning/vault/SUMMARY.md` (the bounded vault index). Inject verbatim — do not paraphrase.
|
|
522
|
+
|
|
515
523
|
Find the active `research` step hook in `PLAN_PRE_HOOKS_JSON`. Use the hook's `fragment.inline` as the prompt template and substitute the phase fields below before spawning its declared `ref.agent`.
|
|
516
524
|
|
|
517
525
|
```markdown
|
|
@@ -693,6 +701,10 @@ Also available:
|
|
|
693
701
|
|
|
694
702
|
**Exit the plan-phase workflow. Do not continue.**
|
|
695
703
|
|
|
704
|
+
### Advisory plan:pre vault gate dispatch
|
|
705
|
+
|
|
706
|
+
In `PLAN_PRE_HOOKS_JSON` (already loaded), find active plan:pre entries where `kind == "gate"` and `check.query == "vault.status"` (`blocking:false`). If none, skip silently to step 6. If present, set `VAULT_GATE_POINT=plan` and Read and execute `pp-core/workflows/execute-phase/steps/vault-load-gate.md` — the parameterized advisory vault gate (surfaces the §8 message for the load state fetched/fallback/cache/miss, requires an explicit `confirmed`, or logs in --auto/--chain). Advisory, `onError:skip` — never blocks planning; proceed to step 6 after it resolves.
|
|
707
|
+
|
|
696
708
|
## 6. Check Existing Plans
|
|
697
709
|
|
|
698
710
|
```bash
|
|
@@ -68,8 +68,8 @@ Cross-AI Execution:
|
|
|
68
68
|
|
|
69
69
|
Git Customization:
|
|
70
70
|
- `git.base_branch` (default: `main`)
|
|
71
|
-
- `git.phase_branch_template` (default: `
|
|
72
|
-
- `git.milestone_branch_template` (default: `
|
|
71
|
+
- `git.phase_branch_template` (default: `pp/phase-{phase}-{slug}`)
|
|
72
|
+
- `git.milestone_branch_template` (default: `pp/{milestone}-{slug}`)
|
|
73
73
|
|
|
74
74
|
Runtime / Output:
|
|
75
75
|
- `response_language` (default: `null`)
|
|
@@ -274,7 +274,7 @@ AskUserQuestion([
|
|
|
274
274
|
]
|
|
275
275
|
},
|
|
276
276
|
{
|
|
277
|
-
question: "Phase branch template? (current: <value or
|
|
277
|
+
question: "Phase branch template? (current: <value or pp/phase-{phase}-{slug}>)",
|
|
278
278
|
header: "Phase Template",
|
|
279
279
|
multiSelect: false,
|
|
280
280
|
options: [
|
|
@@ -283,7 +283,7 @@ AskUserQuestion([
|
|
|
283
283
|
]
|
|
284
284
|
},
|
|
285
285
|
{
|
|
286
|
-
question: "Milestone branch template? (current: <value or
|
|
286
|
+
question: "Milestone branch template? (current: <value or pp/{milestone}-{slug}>)",
|
|
287
287
|
header: "Milestone Template",
|
|
288
288
|
multiSelect: false,
|
|
289
289
|
options: [
|
|
@@ -176,6 +176,15 @@
|
|
|
176
176
|
"external-job-waiting.test.cjs"
|
|
177
177
|
],
|
|
178
178
|
"issue": "#1165"
|
|
179
|
+
},
|
|
180
|
+
"vault": {
|
|
181
|
+
"files": [
|
|
182
|
+
"vault-read-path.test.cjs",
|
|
183
|
+
"vault-security.test.cjs",
|
|
184
|
+
"vault-status-check.test.cjs",
|
|
185
|
+
"vault.test.cjs"
|
|
186
|
+
],
|
|
187
|
+
"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)"
|
|
179
188
|
}
|
|
180
189
|
}
|
|
181
190
|
}
|
|
Binary file
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000" width="2000" height="2000">
|
|
2
|
-
<defs>
|
|
3
|
-
<style>
|
|
4
|
-
.logo { font-family: 'SF Mono', 'Fira Code', 'JetBrains Mono', 'Courier New', monospace; fill: #7dcfff; }
|
|
5
|
-
</style>
|
|
6
|
-
</defs>
|
|
7
|
-
|
|
8
|
-
<!-- GSD ASCII Logo - centered -->
|
|
9
|
-
<g transform="translate(1000, 1000)">
|
|
10
|
-
<text class="logo" font-size="108" text-anchor="middle" y="-225" xml:space="preserve"> ██████╗ ███████╗██████╗ </text>
|
|
11
|
-
<text class="logo" font-size="108" text-anchor="middle" y="-105" xml:space="preserve"> ██╔════╝ ██╔════╝██╔══██╗</text>
|
|
12
|
-
<text class="logo" font-size="108" text-anchor="middle" y="15" xml:space="preserve"> ██║ ███╗███████╗██║ ██║</text>
|
|
13
|
-
<text class="logo" font-size="108" text-anchor="middle" y="135" xml:space="preserve"> ██║ ██║╚════██║██║ ██║</text>
|
|
14
|
-
<text class="logo" font-size="108" text-anchor="middle" y="255" xml:space="preserve"> ╚██████╔╝███████║██████╔╝</text>
|
|
15
|
-
<text class="logo" font-size="108" text-anchor="middle" y="375" xml:space="preserve"> ╚═════╝ ╚══════╝╚═════╝ </text>
|
|
16
|
-
</g>
|
|
17
|
-
</svg>
|
package/assets/gsd-logo-2000.png
DELETED
|
Binary file
|
package/assets/gsd-logo-2000.svg
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000" width="2000" height="2000">
|
|
2
|
-
<defs>
|
|
3
|
-
<style>
|
|
4
|
-
.bg { fill: #1a1b26; }
|
|
5
|
-
.logo { font-family: 'SF Mono', 'Fira Code', 'JetBrains Mono', 'Courier New', monospace; fill: #7dcfff; }
|
|
6
|
-
</style>
|
|
7
|
-
</defs>
|
|
8
|
-
|
|
9
|
-
<!-- Background -->
|
|
10
|
-
<rect class="bg" width="2000" height="2000"/>
|
|
11
|
-
|
|
12
|
-
<!-- GSD ASCII Logo - centered -->
|
|
13
|
-
<g transform="translate(1000, 1000)">
|
|
14
|
-
<text class="logo" font-size="108" text-anchor="middle" y="-225" xml:space="preserve"> ██████╗ ███████╗██████╗ </text>
|
|
15
|
-
<text class="logo" font-size="108" text-anchor="middle" y="-105" xml:space="preserve"> ██╔════╝ ██╔════╝██╔══██╗</text>
|
|
16
|
-
<text class="logo" font-size="108" text-anchor="middle" y="15" xml:space="preserve"> ██║ ███╗███████╗██║ ██║</text>
|
|
17
|
-
<text class="logo" font-size="108" text-anchor="middle" y="135" xml:space="preserve"> ██║ ██║╚════██║██║ ██║</text>
|
|
18
|
-
<text class="logo" font-size="108" text-anchor="middle" y="255" xml:space="preserve"> ╚██████╔╝███████║██████╔╝</text>
|
|
19
|
-
<text class="logo" font-size="108" text-anchor="middle" y="375" xml:space="preserve"> ╚═════╝ ╚══════╝╚═════╝ </text>
|
|
20
|
-
</g>
|
|
21
|
-
</svg>
|