@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.
Files changed (131) hide show
  1. package/CHANGELOG.md +1205 -0
  2. package/LICENSE +21 -0
  3. package/MAPPING.md +73 -0
  4. package/README.md +564 -0
  5. package/abort.ts +34 -0
  6. package/adapters/pi-renderer.ts +7 -0
  7. package/adapters/protocol-elicitation-forwarder.ts +164 -0
  8. package/adapters/protocol-sampling-forwarder.ts +108 -0
  9. package/adapters/universal-host.ts +213 -0
  10. package/agent-dir.ts +68 -0
  11. package/agent-plugin-loader.ts +377 -0
  12. package/app-bridge.bundle.js +67 -0
  13. package/banner.png +0 -0
  14. package/bin/mcp-server.ts +282 -0
  15. package/cli.js +392 -0
  16. package/commands.ts +735 -0
  17. package/config.ts +1284 -0
  18. package/consent-manager.ts +64 -0
  19. package/direct-tools.ts +619 -0
  20. package/dist/agent-dir.d.ts +10 -0
  21. package/dist/agent-dir.js +63 -0
  22. package/dist/agent-dir.js.map +1 -0
  23. package/dist/agent-plugin-loader.d.ts +8 -0
  24. package/dist/agent-plugin-loader.js +356 -0
  25. package/dist/agent-plugin-loader.js.map +1 -0
  26. package/dist/config.d.ts +123 -0
  27. package/dist/config.js +1087 -0
  28. package/dist/config.js.map +1 -0
  29. package/dist/metadata-cache.d.ts +19 -0
  30. package/dist/metadata-cache.js +319 -0
  31. package/dist/metadata-cache.js.map +1 -0
  32. package/dist/package-mcp-loader.d.ts +2 -0
  33. package/dist/package-mcp-loader.js +156 -0
  34. package/dist/package-mcp-loader.js.map +1 -0
  35. package/dist/resource-tools.d.ts +1 -0
  36. package/dist/resource-tools.js +15 -0
  37. package/dist/resource-tools.js.map +1 -0
  38. package/dist/types.d.ts +564 -0
  39. package/dist/types.js +287 -0
  40. package/dist/types.js.map +1 -0
  41. package/dist/ui-app-bridge-helpers.d.ts +6 -0
  42. package/dist/ui-app-bridge-helpers.js +37 -0
  43. package/dist/ui-app-bridge-helpers.js.map +1 -0
  44. package/dist/ui-stream-types.d.ts +104 -0
  45. package/dist/ui-stream-types.js +59 -0
  46. package/dist/ui-stream-types.js.map +1 -0
  47. package/dist/ui-tool-visibility.d.ts +4 -0
  48. package/dist/ui-tool-visibility.js +27 -0
  49. package/dist/ui-tool-visibility.js.map +1 -0
  50. package/dist/utils.d.ts +32 -0
  51. package/dist/utils.js +338 -0
  52. package/dist/utils.js.map +1 -0
  53. package/elicitation-handler.ts +348 -0
  54. package/error-signal.ts +21 -0
  55. package/errors.ts +223 -0
  56. package/failure-backoff.ts +23 -0
  57. package/glimpse-ui.ts +80 -0
  58. package/host-html-template.ts +461 -0
  59. package/index.ts +1291 -0
  60. package/init.ts +692 -0
  61. package/interfaces/agent-paths.ts +67 -0
  62. package/interfaces/host-types.ts +102 -0
  63. package/interfaces/sampling.ts +57 -0
  64. package/json-schema-validator.ts +69 -0
  65. package/lifecycle.ts +446 -0
  66. package/logger.ts +169 -0
  67. package/mcp-auth-flow.ts +1026 -0
  68. package/mcp-auth.ts +1000 -0
  69. package/mcp-bearer-store.ts +387 -0
  70. package/mcp-callback-server.ts +534 -0
  71. package/mcp-code.ts +360 -0
  72. package/mcp-keyring-helper.cjs +89 -0
  73. package/mcp-oauth-provider.ts +666 -0
  74. package/mcp-output-guard.ts +496 -0
  75. package/mcp-panel.ts +1044 -0
  76. package/mcp-probe.ts +201 -0
  77. package/mcp-references.ts +368 -0
  78. package/mcp-script-worker.mjs +130 -0
  79. package/mcp-server.mjs +2133 -0
  80. package/mcp-setup-panel.ts +667 -0
  81. package/mcp-status.ts +98 -0
  82. package/mcp-trace.ts +306 -0
  83. package/metadata-cache.ts +382 -0
  84. package/namespace-tools.ts +276 -0
  85. package/npx-resolver.ts +543 -0
  86. package/oauth-handler.ts +30 -0
  87. package/oauth.ts +48 -0
  88. package/onboarding-state.ts +76 -0
  89. package/package-mcp-loader.ts +168 -0
  90. package/package.json +225 -0
  91. package/panel-keys.ts +53 -0
  92. package/prompts.ts +353 -0
  93. package/proxy-modes.ts +1418 -0
  94. package/request-headers-command.ts +330 -0
  95. package/resource-tools.ts +17 -0
  96. package/runtime-owner.ts +91 -0
  97. package/sampling-handler.ts +284 -0
  98. package/search-ranking.ts +278 -0
  99. package/server-manager.ts +1318 -0
  100. package/session-recovery.ts +158 -0
  101. package/skills/README.md +64 -0
  102. package/skills/mcp-adapter/SKILL.md +332 -0
  103. package/skills/mcp-adapter/references/deploy-examples.md +259 -0
  104. package/skills/mcp-adapter/references/deploy.md +89 -0
  105. package/skills/mcp-adapter/references/generate.md +144 -0
  106. package/skills/mcp-adapter/references/resolver.md +105 -0
  107. package/skills/mcp-adapter/references/verify.md +157 -0
  108. package/skills/mcp-scripting/SKILL.md +38 -0
  109. package/skills/resolve-conflicts/SKILL.md +482 -0
  110. package/skills/resolve-conflicts/references/patterns.md +432 -0
  111. package/skills/resolve-conflicts/references/sample-plan.md +96 -0
  112. package/skills/resolve-conflicts/scripts/handle-deleted-modified.sh +183 -0
  113. package/skills/resolve-conflicts/scripts/validate-conflicts.sh +120 -0
  114. package/skills/upstream-merge/SKILL.md +486 -0
  115. package/skills/upstream-merge/references/pi-coupling-markers.md +129 -0
  116. package/skills/upstream-merge/references/special-cases.md +39 -0
  117. package/state.ts +60 -0
  118. package/tool-approval.ts +195 -0
  119. package/tool-metadata.ts +296 -0
  120. package/tool-registrar.ts +253 -0
  121. package/tool-result-renderer.ts +477 -0
  122. package/ts-shape.ts +149 -0
  123. package/types.ts +991 -0
  124. package/ui-app-bridge-helpers.ts +40 -0
  125. package/ui-resource-handler.ts +250 -0
  126. package/ui-server.ts +852 -0
  127. package/ui-session.ts +571 -0
  128. package/ui-stream-types.ts +89 -0
  129. package/ui-tool-visibility.ts +25 -0
  130. package/unix-socket-transport.ts +85 -0
  131. 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.