@njuptlzf/mcp-adapter 2.29.0-0.0.1
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/CHANGELOG.md +1205 -0
- package/LICENSE +21 -0
- package/MAPPING.md +73 -0
- package/README.md +564 -0
- package/abort.ts +34 -0
- package/adapters/pi-renderer.ts +7 -0
- package/adapters/protocol-elicitation-forwarder.ts +164 -0
- package/adapters/protocol-sampling-forwarder.ts +108 -0
- package/adapters/universal-host.ts +213 -0
- package/agent-dir.ts +68 -0
- package/agent-plugin-loader.ts +377 -0
- package/app-bridge.bundle.js +67 -0
- package/banner.png +0 -0
- package/bin/mcp-server.ts +282 -0
- package/cli.js +392 -0
- package/commands.ts +735 -0
- package/config.ts +1284 -0
- package/consent-manager.ts +64 -0
- package/direct-tools.ts +619 -0
- package/dist/agent-dir.d.ts +10 -0
- package/dist/agent-dir.js +63 -0
- package/dist/agent-dir.js.map +1 -0
- package/dist/agent-plugin-loader.d.ts +8 -0
- package/dist/agent-plugin-loader.js +356 -0
- package/dist/agent-plugin-loader.js.map +1 -0
- package/dist/config.d.ts +123 -0
- package/dist/config.js +1087 -0
- package/dist/config.js.map +1 -0
- package/dist/metadata-cache.d.ts +19 -0
- package/dist/metadata-cache.js +319 -0
- package/dist/metadata-cache.js.map +1 -0
- package/dist/package-mcp-loader.d.ts +2 -0
- package/dist/package-mcp-loader.js +156 -0
- package/dist/package-mcp-loader.js.map +1 -0
- package/dist/resource-tools.d.ts +1 -0
- package/dist/resource-tools.js +15 -0
- package/dist/resource-tools.js.map +1 -0
- package/dist/types.d.ts +564 -0
- package/dist/types.js +287 -0
- package/dist/types.js.map +1 -0
- package/dist/ui-app-bridge-helpers.d.ts +6 -0
- package/dist/ui-app-bridge-helpers.js +37 -0
- package/dist/ui-app-bridge-helpers.js.map +1 -0
- package/dist/ui-stream-types.d.ts +104 -0
- package/dist/ui-stream-types.js +59 -0
- package/dist/ui-stream-types.js.map +1 -0
- package/dist/ui-tool-visibility.d.ts +4 -0
- package/dist/ui-tool-visibility.js +27 -0
- package/dist/ui-tool-visibility.js.map +1 -0
- package/dist/utils.d.ts +32 -0
- package/dist/utils.js +338 -0
- package/dist/utils.js.map +1 -0
- package/elicitation-handler.ts +348 -0
- package/error-signal.ts +21 -0
- package/errors.ts +223 -0
- package/failure-backoff.ts +23 -0
- package/glimpse-ui.ts +80 -0
- package/host-html-template.ts +461 -0
- package/index.ts +1291 -0
- package/init.ts +692 -0
- package/interfaces/agent-paths.ts +67 -0
- package/interfaces/host-types.ts +102 -0
- package/interfaces/sampling.ts +57 -0
- package/json-schema-validator.ts +69 -0
- package/lifecycle.ts +446 -0
- package/logger.ts +169 -0
- package/mcp-auth-flow.ts +1026 -0
- package/mcp-auth.ts +1000 -0
- package/mcp-bearer-store.ts +387 -0
- package/mcp-callback-server.ts +534 -0
- package/mcp-code.ts +360 -0
- package/mcp-keyring-helper.cjs +89 -0
- package/mcp-oauth-provider.ts +666 -0
- package/mcp-output-guard.ts +496 -0
- package/mcp-panel.ts +1044 -0
- package/mcp-probe.ts +201 -0
- package/mcp-references.ts +368 -0
- package/mcp-script-worker.mjs +130 -0
- package/mcp-server.mjs +2133 -0
- package/mcp-setup-panel.ts +667 -0
- package/mcp-status.ts +98 -0
- package/mcp-trace.ts +306 -0
- package/metadata-cache.ts +382 -0
- package/namespace-tools.ts +276 -0
- package/npx-resolver.ts +543 -0
- package/oauth-handler.ts +30 -0
- package/oauth.ts +48 -0
- package/onboarding-state.ts +76 -0
- package/package-mcp-loader.ts +168 -0
- package/package.json +225 -0
- package/panel-keys.ts +53 -0
- package/prompts.ts +353 -0
- package/proxy-modes.ts +1418 -0
- package/request-headers-command.ts +330 -0
- package/resource-tools.ts +17 -0
- package/runtime-owner.ts +91 -0
- package/sampling-handler.ts +284 -0
- package/search-ranking.ts +278 -0
- package/server-manager.ts +1318 -0
- package/session-recovery.ts +158 -0
- package/skills/README.md +64 -0
- package/skills/mcp-adapter/SKILL.md +332 -0
- package/skills/mcp-adapter/references/deploy-examples.md +259 -0
- package/skills/mcp-adapter/references/deploy.md +89 -0
- package/skills/mcp-adapter/references/generate.md +144 -0
- package/skills/mcp-adapter/references/resolver.md +105 -0
- package/skills/mcp-adapter/references/verify.md +157 -0
- package/skills/mcp-scripting/SKILL.md +38 -0
- package/skills/resolve-conflicts/SKILL.md +482 -0
- package/skills/resolve-conflicts/references/patterns.md +432 -0
- package/skills/resolve-conflicts/references/sample-plan.md +96 -0
- package/skills/resolve-conflicts/scripts/handle-deleted-modified.sh +183 -0
- package/skills/resolve-conflicts/scripts/validate-conflicts.sh +120 -0
- package/skills/upstream-merge/SKILL.md +486 -0
- package/skills/upstream-merge/references/pi-coupling-markers.md +129 -0
- package/skills/upstream-merge/references/special-cases.md +39 -0
- package/state.ts +60 -0
- package/tool-approval.ts +195 -0
- package/tool-metadata.ts +296 -0
- package/tool-registrar.ts +253 -0
- package/tool-result-renderer.ts +477 -0
- package/ts-shape.ts +149 -0
- package/types.ts +991 -0
- package/ui-app-bridge-helpers.ts +40 -0
- package/ui-resource-handler.ts +250 -0
- package/ui-server.ts +852 -0
- package/ui-session.ts +571 -0
- package/ui-stream-types.ts +89 -0
- package/ui-tool-visibility.ts +25 -0
- package/unix-socket-transport.ts +85 -0
- package/utils.ts +382 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Validates that all Git conflicts have been resolved
|
|
3
|
+
# Returns 0 if no conflicts remain, 1 otherwise
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
# Colors for output
|
|
8
|
+
RED='\033[0;31m'
|
|
9
|
+
GREEN='\033[0;32m'
|
|
10
|
+
YELLOW='\033[1;33m'
|
|
11
|
+
NC='\033[0m' # No Color
|
|
12
|
+
|
|
13
|
+
# Check if we're in a git repository
|
|
14
|
+
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
|
15
|
+
echo -e "${RED}Error: Not a git repository${NC}" >&2
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
# Function to check for conflict markers in files
|
|
20
|
+
check_conflict_markers() {
|
|
21
|
+
local files_with_markers=()
|
|
22
|
+
|
|
23
|
+
# Search for conflict markers in tracked files
|
|
24
|
+
while IFS= read -r file; do
|
|
25
|
+
if [[ -f "$file" ]] && grep -l '^<<<<<<<\|^=======\|^>>>>>>>' "$file" > /dev/null 2>&1; then
|
|
26
|
+
files_with_markers+=("$file")
|
|
27
|
+
fi
|
|
28
|
+
done < <(git diff --name-only --diff-filter=U 2>/dev/null || git ls-files)
|
|
29
|
+
|
|
30
|
+
if [[ ${#files_with_markers[@]} -gt 0 ]]; then
|
|
31
|
+
echo -e "${RED}✗ Found conflict markers in the following files:${NC}"
|
|
32
|
+
printf ' %s\n' "${files_with_markers[@]}"
|
|
33
|
+
return 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
return 0
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# Function to check for unmerged paths
|
|
40
|
+
check_unmerged_paths() {
|
|
41
|
+
local unmerged_files
|
|
42
|
+
unmerged_files=$(git diff --name-only --diff-filter=U 2>/dev/null || true)
|
|
43
|
+
|
|
44
|
+
if [[ -n "$unmerged_files" ]]; then
|
|
45
|
+
echo -e "${RED}✗ Found unmerged paths:${NC}"
|
|
46
|
+
echo "$unmerged_files" | sed 's/^/ /'
|
|
47
|
+
return 1
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
return 0
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# Function to check for both deleted and modified status
|
|
54
|
+
check_deleted_modified() {
|
|
55
|
+
local status
|
|
56
|
+
status=$(git status --porcelain 2>/dev/null || true)
|
|
57
|
+
|
|
58
|
+
# Look for DU (deleted by us) or UD (deleted by them) or DD (both deleted) status
|
|
59
|
+
local deleted_modified=$(echo "$status" | grep -E '^(DU|UD|DD|UA|AU|AA)' || true)
|
|
60
|
+
|
|
61
|
+
if [[ -n "$deleted_modified" ]]; then
|
|
62
|
+
echo -e "${YELLOW}⚠ Found files with delete/modify conflicts:${NC}"
|
|
63
|
+
echo "$deleted_modified" | sed 's/^/ /'
|
|
64
|
+
return 1
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
return 0
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# Function to check merge state
|
|
71
|
+
check_merge_state() {
|
|
72
|
+
if git rev-parse MERGE_HEAD > /dev/null 2>&1; then
|
|
73
|
+
echo -e "${YELLOW}⚠ Repository is still in merge state${NC}"
|
|
74
|
+
echo " Run 'git merge --continue' after resolving all conflicts"
|
|
75
|
+
return 1
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
if [[ -f .git/MERGE_HEAD ]]; then
|
|
79
|
+
echo -e "${YELLOW}⚠ MERGE_HEAD file exists${NC}"
|
|
80
|
+
return 1
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
return 0
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# Main validation
|
|
87
|
+
echo "🔍 Validating conflict resolution..."
|
|
88
|
+
echo ""
|
|
89
|
+
|
|
90
|
+
all_clear=true
|
|
91
|
+
|
|
92
|
+
if ! check_conflict_markers; then
|
|
93
|
+
all_clear=false
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
if ! check_unmerged_paths; then
|
|
97
|
+
all_clear=false
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
if ! check_deleted_modified; then
|
|
101
|
+
all_clear=false
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
if ! check_merge_state; then
|
|
105
|
+
all_clear=false
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
echo ""
|
|
109
|
+
if [[ "$all_clear" == true ]]; then
|
|
110
|
+
echo -e "${GREEN}✓ All conflicts resolved successfully!${NC}"
|
|
111
|
+
echo ""
|
|
112
|
+
echo "Next steps:"
|
|
113
|
+
echo " 1. Review changes: git diff --cached"
|
|
114
|
+
echo " 2. Run tests to validate"
|
|
115
|
+
echo " 3. Commit: git commit"
|
|
116
|
+
exit 0
|
|
117
|
+
else
|
|
118
|
+
echo -e "${RED}✗ Conflicts still exist. Please resolve them before continuing.${NC}"
|
|
119
|
+
exit 1
|
|
120
|
+
fi
|
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: upstream-merge
|
|
3
|
+
description: >
|
|
4
|
+
Fork-maintainer workflow for syncing https://github.com/nicobailon/pi-mcp-adapter
|
|
5
|
+
into njuptlzf/mcp-adapter. Two-step git flow: merge `upstream/main` into the
|
|
6
|
+
fork's `main` first (decision tree applies here), then propagate fork's
|
|
7
|
+
`main` into the working branch — skipped if already on `main`. Reads
|
|
8
|
+
`skills/upstream-merge/references/special-cases.md` for hand-curated special
|
|
9
|
+
cases AND runs `scripts/upstream-divergence.ts` for live cross-check against
|
|
10
|
+
`git diff upstream/main --name-status`; falls back to the 12-category per-file
|
|
11
|
+
default-resolution matrix (inlined in §4.2) for files not in the registry.
|
|
12
|
+
Applies ours/theirs/manual decisions per a 4-section decision tree. Triggers
|
|
13
|
+
the 5-step follow-up issue flow when Pi-coupling is re-introduced. Use when
|
|
14
|
+
user says "merge upstream", "sync fork", "upstream conflict",
|
|
15
|
+
"resolve upstream merge", or "/upstream-merge".
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Upstream Merge (fork-maintainer)
|
|
19
|
+
|
|
20
|
+
Drives the `njuptlzf/mcp-adapter` fork through a deterministic merge of
|
|
21
|
+
upstream `nicobailon/pi-mcp-adapter` changes. The flow has two layers:
|
|
22
|
+
|
|
23
|
+
- **§1 Two-step git branch flow** — the order of merges across branches.
|
|
24
|
+
Read this first to know where the decision tree runs.
|
|
25
|
+
- **§2–§5 Per-file decision tree** — invoked within Step 1 of the branch
|
|
26
|
+
flow. Look up the file, apply the decision, verify.
|
|
27
|
+
|
|
28
|
+
## 1. Two-step git merge flow
|
|
29
|
+
|
|
30
|
+
The fork has two long-lived branches that the upstream merge must handle
|
|
31
|
+
separately:
|
|
32
|
+
|
|
33
|
+
| Branch | Role | Notes |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `main` (fork's main) | **Upstream change buffer** | The decision tree in §4 runs here. Long-lived but rarely committed to directly. |
|
|
36
|
+
| `<working-branch>` (e.g., `v1.0`) | Active fork development | Long-diverged from `main` (e.g., 227 commits ahead in this fork). |
|
|
37
|
+
|
|
38
|
+
**The merge is a deterministic two-step process:**
|
|
39
|
+
|
|
40
|
+
0. **Create a feature branch from `main`** — `git checkout main && git checkout -b
|
|
41
|
+
upstream-merge/<upstream-version>`. **Never commit directly to `main`**
|
|
42
|
+
(enforced by `.githooks/pre-push` and the `no-direct-main-push` advisory CI —
|
|
43
|
+
see AGENTS.md "Branch Policy (HARD RULE)"). All Step 1 work happens on
|
|
44
|
+
this branch. The branch name MUST follow `upstream-merge/<upstream-version>`
|
|
45
|
+
(e.g., `upstream-merge/v2.10.0`) so the §5.5 PR template can auto-extract
|
|
46
|
+
the version.
|
|
47
|
+
1. **Fetch upstream** — `git fetch upstream` (GnuTLS workaround per the §2
|
|
48
|
+
note if needed).
|
|
49
|
+
2. **Run pre-flight** — `npm run upstream:check` (§3) to see live divergence.
|
|
50
|
+
3. **Step 1: `upstream/main` → `<feature-branch>`** — `git merge upstream/main`.
|
|
51
|
+
Resolve conflicts using the decision tree (§4). The merge commit lands on
|
|
52
|
+
the **feature branch, NOT on `main`**.
|
|
53
|
+
4. **§5.5 PR flow** — push the feature branch → open PR → wait for CI → merge
|
|
54
|
+
→ delete branch (per the §5.5 sub-flow at the end of this skill).
|
|
55
|
+
5. **Step 2: `<feature-branch>` → `<working-branch>`** (post-PR-merge) — `git
|
|
56
|
+
checkout <working-branch> && git merge main`. Generally a fast-forward or
|
|
57
|
+
small diff because the working branch is already ahead of `main` with
|
|
58
|
+
fork-specific work. The merge is now from main (the merged PR) to the
|
|
59
|
+
working branch.
|
|
60
|
+
6. **Short-circuit** — if `<working-branch> == main` and the §5.5 PR has
|
|
61
|
+
already merged to main, skip step 5. The flow ends at step 4.
|
|
62
|
+
|
|
63
|
+
**Anti-pattern (do not):** Running `git merge upstream/main` directly on
|
|
64
|
+
`<working-branch>`. This creates a large blast radius of conflicts between
|
|
65
|
+
the long-diverged working branch and upstream — the working branch has
|
|
66
|
+
hundreds of commits the upstream never saw. The two-step flow exists to
|
|
67
|
+
confine the conflict surface to the smaller `main` branch.
|
|
68
|
+
|
|
69
|
+
**Anti-pattern (do not):** Committing the merge directly to `main` (even if
|
|
70
|
+
`pre-push` hook is somehow disabled). This bypasses the §5.5 PR flow, which
|
|
71
|
+
means no `pr-divergence-check` CI, no review checkpoint, no squash-merge
|
|
72
|
+
cleanup. The hook exists for a reason; respect it.
|
|
73
|
+
|
|
74
|
+
## 2. When to invoke
|
|
75
|
+
|
|
76
|
+
The decision tree (§4) is invoked within Step 1 of the two-step flow, at
|
|
77
|
+
any of three points:
|
|
78
|
+
|
|
79
|
+
- **(a) Pre-flight**, after `git fetch upstream` and before `git merge
|
|
80
|
+
upstream/main`. Run `npm run upstream:check` (§3) to surface live
|
|
81
|
+
divergence, then walk the per-file decision tree before any conflict
|
|
82
|
+
appears.
|
|
83
|
+
- **(b) In-flight**, after `git pull upstream main` produces a merge
|
|
84
|
+
conflict. Look up each conflicting file's `Default Resolution` in the
|
|
85
|
+
manifest, and apply the decision (run the §4.1 grep for `assess` rows
|
|
86
|
+
first).
|
|
87
|
+
- **(c) Targeted cherry-pick**, before `git cherry-pick <upstream-sha>`.
|
|
88
|
+
Same flow as (b), scoped to the files touched by the cherry-picked
|
|
89
|
+
commit.
|
|
90
|
+
|
|
91
|
+
After Step 1's merge commit lands and passes the §5 Checklist, run Step 2
|
|
92
|
+
(`git merge main` on the working branch) to propagate upstream changes.
|
|
93
|
+
If on `main` already, the flow ends at Step 1.
|
|
94
|
+
|
|
95
|
+
> **GnuTLS workaround:** If `git fetch upstream` fails with GnuTLS / SSL
|
|
96
|
+
> errors in this environment, use `GIT_SSL_NO_VERIFY=1 git -c
|
|
97
|
+
> http.sslVerify=false fetch upstream --tags` (verbatim from
|
|
98
|
+
> `08-LEARNINGS.md` L-4).
|
|
99
|
+
|
|
100
|
+
## 3. Read the special-cases registry and run the divergence check
|
|
101
|
+
|
|
102
|
+
Two inputs are required before any merge decision: (1) read `references/special-cases.md` for the 15-17 hand-curated cases (Phase 8 manifest footnotes + expansion), and (2) run `npm run upstream:check` to see live divergence against `upstream/main`. The script replaces the Phase 8 "manifest freshness" check: instead of comparing manifest row counts to `git diff` output, it classifies each diverged file as `registered` / `diverged-but-not-registered` / `stale` against the registry.
|
|
103
|
+
|
|
104
|
+
**How to look up a file in the registry:**
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# By file path (quote the path with backticks to match the table cell)
|
|
108
|
+
grep -F '`init.ts`' skills/upstream-merge/references/special-cases.md
|
|
109
|
+
|
|
110
|
+
# By status (returns all rows in that bucket)
|
|
111
|
+
grep -E '^\| `.*` \| (fork-only|decoupled-wrapper|deleted-in-fork|sibling-config|framing-divergence)' skills/upstream-merge/references/special-cases.md
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Run the divergence check** (script replaces the Phase 8 `git diff ... | wc -l` + `grep -cE '^\| `'` sanity check):
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Default: ANSI color when stdout is a tty
|
|
118
|
+
npm run upstream:check
|
|
119
|
+
|
|
120
|
+
# Grep-friendly output (no escape sequences, suitable for piping / CI logs)
|
|
121
|
+
npx tsx scripts/upstream-divergence.ts --no-color
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Interpreting the script output:**
|
|
125
|
+
|
|
126
|
+
- **Exit 0** — no stale entries. The `diverged-but-not-registered` count is a warning (per D-34: treated as `assess` by the 12-category matrix in §4.2); proceed with the merge.
|
|
127
|
+
- **Exit 1** — stale entries present (registry lists a file that is no longer in `git diff upstream/main --name-status`). STOP and clean stale registry entries before merging.
|
|
128
|
+
- **Exit 2** — fatal: `git fetch upstream` failed AND the GnuTLS workaround also failed, OR the registry parse produced 0 entries. Investigate before proceeding (the GnuTLS workaround per L-4 is `GIT_SSL_NO_VERIFY=1 git -c http.sslVerify=false fetch upstream --tags`; the script retries with it automatically).
|
|
129
|
+
|
|
130
|
+
Files NOT in the registry are resolved by the 12-category per-file default-resolution matrix inlined in §4.2 below — no need to add them to the registry.
|
|
131
|
+
|
|
132
|
+
### 3.5 Conflict resolution: delegate to `resolve-conflicts` skill (v3.2)
|
|
133
|
+
|
|
134
|
+
When `git merge upstream/main` produces conflicts, **do not resolve them manually with custom rules**. Instead, delegate to the `resolve-conflicts` skill:
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
Skill /resolve-conflicts
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The `resolve-conflicts` skill provides a professional, plan-first conflict resolution framework with:
|
|
141
|
+
- 7 conflict type patterns (imports, tests, generated files, config, code logic, structs, deleted-modified)
|
|
142
|
+
- Structured resolution plan + user approval before executing
|
|
143
|
+
- Decision tracking (remember user choices, apply to similar conflicts)
|
|
144
|
+
- Validation scripts (`validate-conflicts.sh`, `handle-deleted-modified.sh`)
|
|
145
|
+
- One-line explanation for every conflict resolved
|
|
146
|
+
|
|
147
|
+
**upstream-merge's role**: After resolve-conflicts resolves the conflicts, run §4.1 Pi-coupling grep (advisory) + §5 Checklist to validate the merge result from a fork-specific perspective.
|
|
148
|
+
|
|
149
|
+
> **Removed in v3.2** (2026-07-01): The previous §3.5 "Conflict hunk independence check" (awk-based 4-category classification + "保留两侧" conditions) and §4.4 "Same-function 5-step protocol" were custom conflict resolution rules that duplicated `resolve-conflicts` skill's functionality. They have been removed in favor of the professional skill.
|
|
150
|
+
|
|
151
|
+
## 4. Decision tree
|
|
152
|
+
|
|
153
|
+
Walk these steps in order, branching on the manifest row for each changed file.
|
|
154
|
+
|
|
155
|
+
**Step 1 — Identify Category.** Read the `Category` column (adapter / interface / source / skill / test / docs / config / planning / agents_meta / other). This alone answers ~70% of cases (see "Fast-path summary" below).
|
|
156
|
+
|
|
157
|
+
**Step 2 — Branch on `Default Resolution`:**
|
|
158
|
+
|
|
159
|
+
| Default Resolution | Action |
|
|
160
|
+
|--------------------|--------|
|
|
161
|
+
| `ours` | `git checkout --ours <path>`; mark "ours" in the merge commit body; jump to §5 Checklist |
|
|
162
|
+
| `theirs` | `git checkout --theirs <path>`; run `npx tsc --noEmit`; jump to §5 Checklist |
|
|
163
|
+
| `assess` | **遇到冲突时委托给 `resolve-conflicts` skill** (§3.5). After conflicts are resolved, run §4.1 Pi-coupling grep (advisory only — record hit count in commit body, not blocking). |
|
|
164
|
+
| `manual` | Open the editor; for each hunk, prefer upstream if generic, prefer ours if Pi-coupled; see §4.3 rule of thumb |
|
|
165
|
+
|
|
166
|
+
**Fast-path summary by Category** (covers `ours` / `theirs` rows without grep):
|
|
167
|
+
|
|
168
|
+
- `adapters/<agent>/*`, `adapters/entry.ts`, `skills/*`, `.planning/*`, `AGENTS.md`, `CLAUDE.md`, `.claude/*` → **always `ours`** (fork-only or agent-specific).
|
|
169
|
+
- `interfaces/*` (agent-api.ts, agent-paths.ts, sampling.ts, etc.) → **`manual`** (line-by-line; upstream remains Pi-specific per D-01..D-03).
|
|
170
|
+
- `package.json`, `vitest.config.ts`, `tsconfig.json`, `.gitignore`, `.npmignore` → **`manual`** (line-by-line, prefer fork's structural choices).
|
|
171
|
+
- `__tests__/*`, `tests/*`, `examples/*`, `types.ts`, `utils.ts`, `errors.ts`, `logger.ts` → **`assess`** (run §4.1 grep).
|
|
172
|
+
- Core MCP source (`init.ts`, `mcp-*.ts`, `lifecycle.ts`, `proxy-modes.ts`, `direct-tools.ts`, `commands.ts`, `state.ts`, `oauth-handler.ts`, `elicitation-handler.ts`, `sampling-handler.ts`, `tool-result-renderer.ts`) → **`assess`** (run §4.1 grep).
|
|
173
|
+
- `types/pi-*.d.ts` → **`ours`** (fork-side type declarations for Pi per D-21; declarations ≠ coupling).
|
|
174
|
+
- `README.md`, `MAPPING.md`, `CHANGELOG.md`, `OAUTH.md` → **`assess` via intent alignment** (preserve "Universal MCP Adapter" framing per D-18/D-19/D-20).
|
|
175
|
+
|
|
176
|
+
**Step 3 — Special cases:**
|
|
177
|
+
|
|
178
|
+
- File is `new` (Status column) + Category ∈ {adapter, interface, skill, planning} → `--ours` (we own the directory; upstream shouldn't add files here).
|
|
179
|
+
- File is `deleted` in upstream + still referenced locally → keep ours, add `// deprecated: removed in upstream; kept for fork back-compat` JSDoc (the `panel-keys.ts` precedent from Plan 08-01).
|
|
180
|
+
|
|
181
|
+
### 4.1 Pi-coupling marker grep (corrected template)
|
|
182
|
+
|
|
183
|
+
Run the **5 sub-commands** below against the changed files. Each covers a distinct marker class. The `\b` word boundaries and the `types/pi-*.d.ts` exclusion are the corrections from RESEARCH Dimension 3 — without them, every `agentapi.X` call in this fork produces a systematic false positive (CONTEXT's original 8 `pi.X` patterns are DELETED for exactly this reason; see `references/pi-coupling-markers.md` §"DELETED markers").
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
# === 1. Type / class markers (HIGH precision) ===
|
|
187
|
+
git diff upstream/main --name-only -- '*.ts' | xargs grep -nE \
|
|
188
|
+
'\bExtensionAPI\b|\bExtensionContext\b|\bExtensionUIContext\b|\
|
|
189
|
+
\bAgentToolResult\b|\bAgentToolUpdateCallback\b' \
|
|
190
|
+
2>/dev/null
|
|
191
|
+
|
|
192
|
+
# === 2. Package markers (HIGH precision, exclude .d.ts declarations) ===
|
|
193
|
+
git diff upstream/main --name-only -- '*.ts' '*.json' | xargs grep -nE \
|
|
194
|
+
'@earendil-works/pi-(coding-agent|ai|tui)' \
|
|
195
|
+
2>/dev/null | grep -vE 'types/pi-(ai|coding-agent|tui)\.d\.ts:'
|
|
196
|
+
|
|
197
|
+
# === 3. Env var marker (HIGH precision) ===
|
|
198
|
+
git diff upstream/main --name-only -- '*.ts' | xargs grep -nE \
|
|
199
|
+
'PI_CODING_AGENT_DIR' 2>/dev/null
|
|
200
|
+
|
|
201
|
+
# === 4. UI surface (MEDIUM precision — generic ctx.ui but Pi-style API) ===
|
|
202
|
+
git diff upstream/main --name-only -- '*.ts' | xargs grep -nE \
|
|
203
|
+
'\bctx\.ui\.(notify|form|custom|theme)' 2>/dev/null
|
|
204
|
+
|
|
205
|
+
# === 5. ToolInfo (must filter by import path) ===
|
|
206
|
+
# Flag only ToolInfo from @earendil-works/pi-coding-agent or pi-ai;
|
|
207
|
+
# the generic one in interfaces/agent-api.ts is fork-owned.
|
|
208
|
+
git diff upstream/main --name-only -- '*.ts' | xargs grep -nE \
|
|
209
|
+
'from .*pi-coding-agent.*ToolInfo|from .*pi-ai.*ToolInfo' 2>/dev/null
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Decision rule:** Sub-commands 1-3, 5 → 0 hits means Pi-coupling-free (accept `--theirs`). Sub-command 4 (`ctx.ui.X`) is a MEDIUM marker; hits in `commands.ts` are expected and are **not** a follow-up trigger — `ctx.ui` is this fork's generic `UISystem` interface (D-04 / Phase 3). See `references/pi-coupling-markers.md` for the full per-marker inventory and rationale.
|
|
213
|
+
|
|
214
|
+
> **Note:** The 8 `pi.<method>` call patterns from the original CONTEXT-03-B draft (8 entries enumerated in `references/pi-coupling-markers.md` §"DELETED markers") are **DELETED** — they produce systematic false positives on `agentapi.X` generic adapter calls. They are catalogued only in `references/pi-coupling-markers.md` §"DELETED markers" so future maintainers can see why they are absent. Do NOT reintroduce them in the §4.1 template without re-verifying against the latest codebase.
|
|
215
|
+
|
|
216
|
+
### 4.2 Per-file default resolution (12-category matrix) and 5-step follow-up flow
|
|
217
|
+
|
|
218
|
+
#### 4.2a Per-category default resolution
|
|
219
|
+
|
|
220
|
+
The 12-category per-file default-resolution matrix (sourced from D-23; inlined here per **D-35** so the fast-path and the slow-path special-cases registry are visible in one place). Every diverged file not in `references/special-cases.md` defaults to the action in this table; the special-cases registry overrides only when a file genuinely cannot be resolved by category rules.
|
|
221
|
+
|
|
222
|
+
| Category | Default | Rationale | Source |
|
|
223
|
+
|---|---|---|---|
|
|
224
|
+
| `adapters/<agent>/*` | `ours` | Fork-only; upstream doesn't add adapters | D-21 |
|
|
225
|
+
| `adapters/entry.ts` | `ours` | Frozen signature per D-07 | D-07 |
|
|
226
|
+
| `skills/*` | `ours` | Fork-only skill additions | D-21 |
|
|
227
|
+
| `interfaces/*` | `manual` | Fork-generic; upstream remains Pi-specific | D-01..D-03 |
|
|
228
|
+
| `package.json` / `vitest.config.ts` / `tsconfig.json` | `manual` | Line-by-line; prefer fork structural choices | D-21 |
|
|
229
|
+
| `.gitignore` / `.npmignore` | `manual` | Line-by-line; prefer fork structural choices | D-21 |
|
|
230
|
+
| `__tests__/*` / `tests/*` | `assess` | Run §4.1 grep; mostly legal but watch for new test fixtures | D-24 |
|
|
231
|
+
| Core MCP source (`init.ts`, `mcp-*.ts`, ...) | `assess` | Always run §4.1 grep; check D-04 wrapper boundaries | D-24, D-04 |
|
|
232
|
+
| `bin/*` | `ours` | Fork-only bin entries; upstream has no `bin/` directory | D-21 |
|
|
233
|
+
| `types.ts` / `utils.ts` / `errors.ts` / `logger.ts` | `assess` | Universal utility files; Pi-coupling unlikely but check | D-24 |
|
|
234
|
+
| `README.md` / `MAPPING.md` / `CHANGELOG.md` / `OAUTH.md` | `assess` (intent) | Preserve "Universal MCP Adapter" framing | D-18..D-20 |
|
|
235
|
+
| `AGENTS.md` / `CLAUDE.md` / `.claude/*` | `ours` | Fork-specific | D-21 |
|
|
236
|
+
| `.planning/*` | `ours` | Planning artifacts are fork-specific | D-21 |
|
|
237
|
+
| `types/pi-*.d.ts` | `ours` | Fork-side type declarations for Pi (declarations ≠ coupling) | D-21 |
|
|
238
|
+
|
|
239
|
+
This matrix covers ~70% of files; the remaining ~10% are the special cases in `references/special-cases.md`. The §4.1 grep runs on `assess` rows before any `--theirs` decision.
|
|
240
|
+
|
|
241
|
+
#### 4.2b Pi-coupling soft follow-up (advisory, non-blocking) (v3.1)
|
|
242
|
+
|
|
243
|
+
When the §4.1 grep returns ≥1 hit in core source, the merge is **not blocked**. Best-effort follow-up:
|
|
244
|
+
|
|
245
|
+
1. **Conflicts resolved by `resolve-conflicts` skill** (§3.5) — accept the resolution result.
|
|
246
|
+
2. **Optionally open a follow-up issue** (best-effort, only if `gh` CLI authenticated). Skip if `gh` not authenticated.
|
|
247
|
+
|
|
248
|
+
> **Removed from v1** (2026-07-01, Phase 13): steps "Stage a follow-up commit that refactors the Pi-coupling out", "Open a follow-up issue" (now optional), and "Reference the issue number in the merge commit body" are removed from the mandatory path. Rationale: fork is downstream, not adversarial. The adapter layer (`adapters/pi-adapter.ts`) provides runtime isolation; Pi-coupling in core is log-only. See `docs/upstream-merge-retrospective.md` §2.1.3 for the full rationale.
|
|
249
|
+
|
|
250
|
+
### 4.3 `manual` review rule of thumb
|
|
251
|
+
|
|
252
|
+
For `manual` rows, accept upstream hunks unless they touch a function signature that generic code depends on — the canonical example is `createMcpAdapter(agentapi, ctx, config, cache)` in `adapters/entry.ts`; that signature is frozen per D-07 and any upstream change to it is rejected (`git checkout --ours`).
|
|
253
|
+
|
|
254
|
+
### 4.4 Conflict resolution: delegate to `resolve-conflicts` skill (v3.2)
|
|
255
|
+
|
|
256
|
+
When conflicts occur during `git merge upstream/main`, **delegate to the `resolve-conflicts` skill** instead of using custom resolution rules:
|
|
257
|
+
|
|
258
|
+
```
|
|
259
|
+
Skill /resolve-conflicts
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
The `resolve-conflicts` skill handles all conflict types professionally:
|
|
263
|
+
- **Imports**: Merge all unique imports, group by module
|
|
264
|
+
- **Tests**: Keep all tests unless identical, merge fixtures
|
|
265
|
+
- **Generated files**: Regenerate from source
|
|
266
|
+
- **Config**: Merge all keys, choose appropriate values
|
|
267
|
+
- **Code logic**: Analyze intent, merge if orthogonal, choose one if conflicting
|
|
268
|
+
- **Structs**: Include all fields from both branches
|
|
269
|
+
- **Deleted-modified**: Backup, analyze, apply to new location
|
|
270
|
+
|
|
271
|
+
> **Removed in v3.2**: The previous §4.4 "Same-function 5-step protocol" (extract ours/theirs → classify merge mode → document decision) was a custom conflict resolution rule. It has been removed in favor of `resolve-conflicts` skill's Step 4 "Execute Resolution Plan" which provides the same functionality with a more comprehensive framework (7 patterns, decision tracking, user approval flow).
|
|
272
|
+
|
|
273
|
+
## 5. Checklist
|
|
274
|
+
|
|
275
|
+
Run all 7 checks before declaring the upstream-merge flow complete. Each is a single command the agent can execute and inspect. Steps (a)–(f) gate the Step 1 merge commit on `main`; step (g) gates the Step 2 propagation into the working branch. A merge is not done until every item is recorded with PASS / N/A / FAIL.
|
|
276
|
+
|
|
277
|
+
- **(a) All conflicts resolved** — `git diff --name-only --diff-filter=U | wc -l` returns 0. If > 0, there are still unresolved hunks; re-walk the decision tree.
|
|
278
|
+
- **(b) Pi-coupling markers advisory log (no longer blocking)** — re-run the 5 sub-commands from §4.1 against the post-merge working tree; record the total hit count in the merge commit body. The only acceptable hits are inside `adapters/`, `types/`, or `__tests__/` (legal coupling zones); any hit outside these zones is acceptable (advisory) but should be tracked for the next Pi-coupling reduction cycle. Per v3.1 Phase 13 policy change (2026-07-01), this check no longer blocks the merge — see §4.2b and `docs/upstream-merge-retrospective.md` §2.1.3.
|
|
279
|
+
- **(c) TypeScript compiles** — `npx tsc --noEmit` exits 0.
|
|
280
|
+
- **(d) Tests are green** — `npm test` (which runs `test:prebuild` then the full vitest suite) exits 0. The quick alternative is `npx vitest run __tests__/adapter-contract.test.ts` for the parametric adapter contract.
|
|
281
|
+
- **(e) Divergence check passes — `npm run upstream:check` exits 0** (no stale registry entries; `diverged-but-not-registered` warnings are acceptable, see §4.2a category defaults). The cross-check script replaces the Phase 8 manifest-gap ≤ 10 check; per D-34, exit 1 means stale entries require registry cleanup before the merge commit.
|
|
282
|
+
- **(f) Commit message prefix is `upstream-merge:`** — e.g., `upstream-merge: sync v2.10.0 (N files, M conflicts resolved)`. The body should list `ours` / `theirs` / `assess` row counts and any `Refs #N` follow-up issue links.
|
|
283
|
+
- **(g) Step 2 propagation complete (skipped if working branch is `main`)** — `git checkout <working-branch> && git merge main` succeeds as a fast-forward or a clean small merge. The working branch now contains the upstream changes from Step 1; if conflicts appear, they are fork-vs-fork, not upstream-vs-fork, and the resolution strategy is the fork's own (consult the relevant Phase plan, not the §4 decision tree). After Step 2, re-run (c) and (d) on the working branch to confirm the propagated state still builds and tests pass.
|
|
284
|
+
|
|
285
|
+
When steps (a)–(f) PASS, the merge is locally complete on the feature branch. **Do NOT push directly to `main`** — proceed to the §5.5 PR sub-flow below. When step (g) also PASS (post-PR-merge), the upstream-merge flow is fully complete on both `main` and the working branch.
|
|
286
|
+
|
|
287
|
+
## 5.5 PR sub-flow (mandatory — bridges local merge to merged `main`)
|
|
288
|
+
|
|
289
|
+
Per the project-wide rule "**绝对不允许直接提交到main分支**" (enforced by `.githooks/pre-push` and `.github/workflows/no-direct-main-push.yml`, see AGENTS.md "Branch Policy (HARD RULE)"), every upstream-merge MUST go through a PR. This sub-flow replaces the previous single-line "push the merge branch and open a PR" instruction with a deterministic 5-step procedure.
|
|
290
|
+
|
|
291
|
+
**Naming contract**: the feature branch MUST be `upstream-merge/<upstream-version>` (e.g., `upstream-merge/v2.10.0`). This is what the PR template and the `pr-divergence-check` CI match against. If you deviated from this naming in §1 step 0, rename with `git branch -M upstream-merge/<correct-version>` before continuing.
|
|
292
|
+
|
|
293
|
+
### 5.5.1 Push the feature branch
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
git push -u origin upstream-merge/<version>
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
`pre-push` will NOT intercept (it only blocks `refs/heads/main`/`refs/heads/master`). If the hook fires anyway, you pushed the wrong ref — abort and re-check `git rev-parse --abbrev-ref HEAD`.
|
|
300
|
+
|
|
301
|
+
### 5.5.2 Open the PR
|
|
302
|
+
|
|
303
|
+
Use the body template at `references/pi-coupling-markers.md §"PR template"`. Auto-generate from §5 checklist values:
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
gh pr create \
|
|
307
|
+
--base main \
|
|
308
|
+
--head upstream-merge/<version> \
|
|
309
|
+
--title "upstream-merge: sync <version> (<N> commits, <M> files diverged)" \
|
|
310
|
+
--body "$(cat <<'EOF'
|
|
311
|
+
## Upstream merge <short-sha>
|
|
312
|
+
|
|
313
|
+
- Base ref: upstream/main @ <upstream-sha>
|
|
314
|
+
- Files merged: <N> (ours: <a> / theirs: <b> / assess: <c> / manual: <d>)
|
|
315
|
+
- Conflicts resolved: <M>
|
|
316
|
+
- Pi-coupling re-introductions: <K>
|
|
317
|
+
- Follow-up issues: #<N>, #<N>
|
|
318
|
+
- Manifest staleness: |raw - manifest| = <Δ> (acceptable ≤ 10)
|
|
319
|
+
- Checklist: 6/6 PASS
|
|
320
|
+
|
|
321
|
+
Refs: <list of follow-up issues>
|
|
322
|
+
EOF
|
|
323
|
+
)"
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
If `gh` CLI is not authenticated, log in first: `gh auth login` (or use a Personal Access Token via `GH_TOKEN`). If `gh` is unavailable (some sandboxed environments), push the branch and create the PR manually via the GitHub web UI, citing the body template above.
|
|
327
|
+
|
|
328
|
+
### 5.5.3 Wait for CI
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
gh pr checks --watch
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Required CI workflows (per `.github/workflows/`):
|
|
335
|
+
|
|
336
|
+
- `pr-divergence-check.yml` — runs `npm run upstream:check` on the PR. **MUST be green.**
|
|
337
|
+
- `no-direct-main-push.yml` — advisory; should not fire on a PR (the merge happens via `gh pr merge`, not `git push`).
|
|
338
|
+
|
|
339
|
+
If `pr-divergence-check` fails: it means the registry gained new stale entries between PR open and the check. Update `references/special-cases.md`, **amend the merge commit** on the feature branch (`git commit --amend --no-edit`), force-push (`git push --force-with-lease`), and re-run.
|
|
340
|
+
|
|
341
|
+
If the check is still in progress after 5 minutes, do not panic — the script does its own `git fetch upstream` which can be slow. Re-run `gh pr checks` periodically.
|
|
342
|
+
|
|
343
|
+
### 5.5.4 Merge the PR
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
gh pr merge --squash --delete-branch
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
- `--squash`: collapses the merge commit + any follow-up commits into a single commit on `main`. The squash commit message is auto-populated from the PR title; the body becomes the merge commit body (preserves the §5 checklist summary).
|
|
350
|
+
- `--delete-branch`: removes both remote (`origin/upstream-merge/<version>`) and local feature branch (cleanup step).
|
|
351
|
+
|
|
352
|
+
If the PR is a fast-forward (no merge commit on the feature branch — rare for upstream-merge but possible for tiny patches), use `--merge` or `--rebase` instead of `--squash`.
|
|
353
|
+
|
|
354
|
+
If `gh pr merge` is blocked by branch protection (e.g., "Reviews required"), request a review first (`gh pr review --approve` if you have permission, or use the GitHub web UI).
|
|
355
|
+
|
|
356
|
+
### 5.5.5 Verify and clean up
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
# Confirm main now has the merge
|
|
360
|
+
git fetch origin && git log --oneline origin/main -5
|
|
361
|
+
# Confirm local branch is gone (--delete-branch handles this)
|
|
362
|
+
git branch | grep upstream-merge # should be empty
|
|
363
|
+
# Confirm working tree is clean
|
|
364
|
+
git status
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
If anything looks wrong (missing commits, wrong files, CI failure surfaced post-merge), `git revert` the PR merge commit on `main` and investigate. **Do NOT push a fix commit directly to `main`** — branch, fix, and PR (per AGENTS.md Branch Policy).
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## 6. Fork architecture principles (NEW, v3.1)
|
|
372
|
+
|
|
373
|
+
> **Purpose**: Prevent future merge conflicts at the source, not just resolve them better.
|
|
374
|
+
> Source: User insight 2026-07-01 ("fork 引入的代码,如果是独立的,应该独立成文件") + retrospective §3.2.1 L1/L2/L3 decision matrix.
|
|
375
|
+
|
|
376
|
+
### 6.1 Core principle
|
|
377
|
+
|
|
378
|
+
**When introducing fork-only code, ALWAYS prefer "独立文件" over "修改 upstream 文件".**
|
|
379
|
+
|
|
380
|
+
The conflict resolution cost grows with granularity:
|
|
381
|
+
|
|
382
|
+
| 粒度 | 冲突表现 | 解决成本 |
|
|
383
|
+
|------|---------|---------|
|
|
384
|
+
| 文件级 | 整个文件 conflict | 🟢 1 行 |
|
|
385
|
+
| 段落级 | 文件内某段 conflict | 🟡 需 §4.4 5 步 |
|
|
386
|
+
| 函数级 | 同一函数内 conflict | 🟠 需 §4.4 5 步 |
|
|
387
|
+
| 行级大块 | 同一函数 343 行同时被改 | 🔴 灾难 |
|
|
388
|
+
|
|
389
|
+
**Target: 把所有 fork 引入的独立代码推到"文件级"粒度。**
|
|
390
|
+
|
|
391
|
+
### 6.2 L1/L2/L3 decision matrix (for current fork state)
|
|
392
|
+
|
|
393
|
+
> Full matrix in `docs/upstream-merge-retrospective.md` §3.2.1.
|
|
394
|
+
|
|
395
|
+
| Layer | Category | Action |
|
|
396
|
+
|-------|----------|--------|
|
|
397
|
+
| **L1** | REPLACEMENTS(9 个 Phase 3 抽象改造)| **接受冲突**——撤回 = 撤销 universal 目标 |
|
|
398
|
+
| **L2** | ADDITIONS(8 个 fork 加 universal 段)| 大部分已优化(Phase 12 删除 per-agent);剩余不值得抽 |
|
|
399
|
+
| **L3** | TESTS(~10 个 fork universal 测试)| 按 Plan 14-04 拆 init-elicitation |
|
|
400
|
+
|
|
401
|
+
### 6.3 Future-proofing rules (apply to all new fork code)
|
|
402
|
+
|
|
403
|
+
When adding new fork-only functionality:
|
|
404
|
+
|
|
405
|
+
1. **New agent adapter** → create `adapters/<new-agent>.ts`, NOT modify `adapters/entry.ts`
|
|
406
|
+
2. **New test scenario** → create `__tests__/<new-scenario>.test.ts`, NOT extend existing `__tests__/init-*.test.ts`
|
|
407
|
+
3. **New abstract type** → extend `interfaces/agent-api.ts`, NOT import Pi types directly in core
|
|
408
|
+
4. **New universal helper** → create `adapters/<helper>.ts` or `utils/<helper>.ts`, NOT add as inline closure in `entry.ts`
|
|
409
|
+
5. **New fork-only documentation** → create `docs/<new-topic>.md`, NOT extend `docs/upstream-merge-retrospective.md` in place (use references + cross-links)
|
|
410
|
+
|
|
411
|
+
**Anti-pattern**: Adding a new `registerCommand` or `registerTool` call inline in `adapters/entry.ts` `createMcpAdapter` body. This creates future merge conflict at the function level (243-line function body).
|
|
412
|
+
|
|
413
|
+
**Correct pattern**: Create a new file like `adapters/commands/<new-command>.ts` exporting a `setup<NewCommand>(agentapi, getState, getInitPromise)` function, then call that function from `createMcpAdapter`.
|
|
414
|
+
|
|
415
|
+
### 6.4 Pre-commit guardrail (CI in Phase 15)
|
|
416
|
+
|
|
417
|
+
Phase 15 P2-3 will add a CI check that runs:
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
# Count: new files vs modified files in this PR
|
|
421
|
+
new_files=$(git diff --name-only --diff-filter=A origin/main...HEAD | wc -l)
|
|
422
|
+
modified_files=$(git diff --name-only --diff-filter=M origin/main...HEAD | wc -l)
|
|
423
|
+
|
|
424
|
+
# Warn if too many modifications relative to new files
|
|
425
|
+
# (suggests inline additions rather than new file extractions)
|
|
426
|
+
ratio=$(echo "scale=2; $modified_files / ($new_files + 1)" | bc)
|
|
427
|
+
if (( $(echo "$ratio > 2.0" | bc -l) )); then
|
|
428
|
+
echo "⚠ High modify-to-new ratio: $ratio. Consider extracting independent code to new files."
|
|
429
|
+
fi
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
**Target ratio**: ≤ 2.0 modifications per new file. If exceeded, PR review should consider whether fork code could be extracted to a new file.
|
|
433
|
+
|
|
434
|
+
### 6.5 Cross-references
|
|
435
|
+
|
|
436
|
+
- `docs/upstream-merge-retrospective.md` §3.2.1 — full L1/L2/L3 matrix with empirical data (249 fork-only commits, 278 diverged files)
|
|
437
|
+
- `docs/upstream-merge-retrospective.md` §2.4 — multi-perspective reflection on conflict granularity
|
|
438
|
+
- SKILL.md §1 — Two-step git merge flow (the merge strategy that this principle supports)
|
|
439
|
+
|
|
440
|
+
### 6.6 Code structure optimization: how to reduce future conflicts (v3.2)
|
|
441
|
+
|
|
442
|
+
Based on the 2026-07-01 first merge attempt (11 conflicts, 249 fork-only commits, 278 diverged files), the following code structure changes would reduce future conflict frequency:
|
|
443
|
+
|
|
444
|
+
**1. Fork-only code in independent files (not modify upstream files)**
|
|
445
|
+
|
|
446
|
+
When adding new fork-only functionality, create new files — do NOT add code to upstream files that upstream will also modify:
|
|
447
|
+
|
|
448
|
+
- ✅ New agent adapter → `adapters/<new-agent>.ts` (not modify `adapters/entry.ts`)
|
|
449
|
+
- ✅ New test scenario → `__tests__/<new-scenario>.test.ts` (not extend `__tests__/init-*.test.ts`)
|
|
450
|
+
- ✅ New abstract type → extend `interfaces/agent-api.ts` (not import Pi types in core)
|
|
451
|
+
- ✅ New universal helper → `adapters/<helper>.ts` or `utils/<helper>.ts` (not inline in `entry.ts`)
|
|
452
|
+
- ✅ New fork-only doc → `docs/<new-topic>.md` (not extend `docs/upstream-merge-retrospective.md` in place)
|
|
453
|
+
|
|
454
|
+
**2. Avoid large functions that both sides will modify** (REVISED 2026-07-02: heuristic, not absolute)
|
|
455
|
+
|
|
456
|
+
The 2026-07-01 attempt showed `adapters/entry.ts` `createMcpAdapter` (324 lines) as the hardest conflict — both fork and upstream modify the same function body. Break large functions into smaller, independently-modifiable units:
|
|
457
|
+
|
|
458
|
+
- ❌ One 324-line function → ✅ 4 small functions (~80 lines each) + thin orchestrator
|
|
459
|
+
- ❌ Inline session lifecycle in `createMcpAdapter` → ✅ Extract to `setupSessionHandlers()`
|
|
460
|
+
- ❌ Inline command registration → ✅ Extract to `registerCommands()`
|
|
461
|
+
|
|
462
|
+
> **Heuristic, not absolute rule** (REVISED 2026-07-02): "Large function" is not well-defined — 30 lines of pure logic is large, but 300+ lines of YAML/JSON/case-statement config may be reasonable. Use `npm run check:large-functions` (default 300 lines) as a **heuristic indicator**, not an absolute threshold. A function being detected as "large" does NOT automatically mean it should be refactored — **refactor only if**:
|
|
463
|
+
>
|
|
464
|
+
> 1. The function is in a file that both fork and upstream actively modify (verify with `git log upstream/main..main -- <file>` + `git log main..upstream/main -- <file>`)
|
|
465
|
+
> 2. AND the function has been the source of past merge conflicts (check retrospective)
|
|
466
|
+
> 3. AND the function's body is "structurally simple" (not just long due to data tables/cases)
|
|
467
|
+
>
|
|
468
|
+
> If any of the above conditions is false, the line count is not a merge-conflict risk — leave it alone. **The root cause of merge conflicts is "both sides modify the same function", not "the function is long".**
|
|
469
|
+
|
|
470
|
+
**3. Keep import sections stable**
|
|
471
|
+
|
|
472
|
+
Import conflicts are the easiest to resolve but still cost time. Minimize import churn:
|
|
473
|
+
|
|
474
|
+
- Use `interfaces/agent-api.ts` abstractions instead of direct Pi type imports (fork-specific imports don't conflict with upstream Pi imports)
|
|
475
|
+
- Group imports consistently (std → external → internal → relative)
|
|
476
|
+
- When adding a new dependency, add it in a new file, not in an existing core file
|
|
477
|
+
|
|
478
|
+
**4. Separate fork-only config from upstream config**
|
|
479
|
+
|
|
480
|
+
- ✅ Fork config in `.planning/` (fork-only, never conflicts)
|
|
481
|
+
- ✅ Fork CI in `.github/workflows/` (fork-only, never conflicts)
|
|
482
|
+
- ❌ Fork config inline in `package.json` or `tsconfig.json` (shared with upstream, will conflict)
|
|
483
|
+
|
|
484
|
+
**5. Run `npm run upstream:check` before every PR**
|
|
485
|
+
|
|
486
|
+
The `--json` mode (CI-02) provides machine-readable divergence data. Use it to detect new divergence early.
|