@polygraph/claude-plugin 0.4.21
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 +12 -0
- package/.mcp.json +11 -0
- package/README.md +127 -0
- package/agents/polygraph-delegate-subagent.md +183 -0
- package/agents/polygraph-init-subagent.md +165 -0
- package/hooks/hooks.json +15 -0
- package/hooks/remind-subagents.mjs +17 -0
- package/package.json +33 -0
- package/skills/await-polygraph-ci/SKILL.md +182 -0
- package/skills/get-latest-ci/SKILL.md +160 -0
- package/skills/pack-and-copy/SKILL.md +136 -0
- package/skills/polygraph/SKILL.md +681 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: await-polygraph-ci
|
|
3
|
+
description: Wait for CI to settle across all repos in a Polygraph session, then report results and investigate failures. USE WHEN user says "await polygraph", "wait for polygraph ci", "polygraph ci status", "check polygraph ci", "watch polygraph session", "monitor polygraph".
|
|
4
|
+
|
|
5
|
+
user-invocable: true
|
|
6
|
+
allowed-tools:
|
|
7
|
+
- Bash
|
|
8
|
+
- Read
|
|
9
|
+
- Task
|
|
10
|
+
- AskUserQuestion
|
|
11
|
+
- mcp__plugin_polygraph_polygraph-mcp
|
|
12
|
+
- mcp__plugin_nx_nx-mcp
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Await Polygraph CI
|
|
17
|
+
|
|
18
|
+
Wait for all CI pipelines in a Polygraph session to reach a stable state (succeeded, failed, etc.), then produce a unified summary. If any pipelines failed, investigate via child agents and present fix options.
|
|
19
|
+
|
|
20
|
+
Some Polygraph tools have both MCP and CLI equivalents — use whichever is available in your environment. See the polygraph skill's tool table for the full mapping.
|
|
21
|
+
|
|
22
|
+
## Phase 1: Session Setup
|
|
23
|
+
|
|
24
|
+
Fetch the Polygraph session using `show_session`.
|
|
25
|
+
|
|
26
|
+
**Parameters:**
|
|
27
|
+
|
|
28
|
+
- `sessionId` (required): The Polygraph session ID
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
show_session(sessionId: "<session-id>")
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
1. Record `monitorStartedAt` = current timestamp (epoch millis).
|
|
35
|
+
2. Build a tracking table of all repos with PRs. For each PR, record:
|
|
36
|
+
- `repo`: repository name
|
|
37
|
+
- `prUrl`: PR URL
|
|
38
|
+
- `prStatus`: DRAFT / OPEN / MERGED / CLOSED
|
|
39
|
+
- `ciStatus`: from session (may already be a terminal status from a previous run)
|
|
40
|
+
- `cipeUrl`: CI pipeline URL (null if none)
|
|
41
|
+
- `cipeCompletedAt`: `completedAt` from session (epoch millis, null if CIPE is active or absent)
|
|
42
|
+
- `selfHealingStatus`: self-healing fix status (null if none)
|
|
43
|
+
- `firstSeenAt`: current timestamp
|
|
44
|
+
3. If no PRs found, report "No PRs in session" and exit.
|
|
45
|
+
4. **Stale detection**: For each PR, determine if its CI status is **stale** — meaning it reflects a previous run, not a current one. A PR's CI status is stale if:
|
|
46
|
+
- `cipeCompletedAt` is non-null AND `cipeCompletedAt < monitorStartedAt` (the CIPE finished before the monitor started)
|
|
47
|
+
- Mark these PRs as `stale: true`
|
|
48
|
+
5. Display the initial status table, annotating stale PRs:
|
|
49
|
+
```
|
|
50
|
+
backend: SUCCEEDED (stale) | frontend: SUCCEEDED (stale) | shared-lib: NOT_STARTED
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Phase 2: Polling Loop
|
|
54
|
+
|
|
55
|
+
**Configuration:**
|
|
56
|
+
|
|
57
|
+
- Timeout: 30 minutes total
|
|
58
|
+
- Backoff: 60s → 90s → 120s (cap)
|
|
59
|
+
- Circuit breaker: exit after 5 consecutive polls with no status change
|
|
60
|
+
|
|
61
|
+
**Each poll iteration:**
|
|
62
|
+
|
|
63
|
+
1. Call `show_session(sessionId: <session-id>)`
|
|
64
|
+
2. Update each tracked PR from the session response: `ciStatus`, `cipeUrl`, `cipeCompletedAt`, and `selfHealingStatus`
|
|
65
|
+
3. **Clear stale flag**: If a PR was marked `stale: true` and its `cipeCompletedAt` has changed (or become null, meaning a new CIPE is active), clear the stale flag — this PR now has fresh CI data.
|
|
66
|
+
4. Display status update:
|
|
67
|
+
```
|
|
68
|
+
[await-polygraph-ci] Poll #N | Elapsed: Xm | Repos: Y total, Z completed
|
|
69
|
+
backend: SUCCEEDED | frontend: FAILED (self-healing: PENDING) | shared-lib: SUCCEEDED (stale)
|
|
70
|
+
```
|
|
71
|
+
Include `selfHealingStatus` inline when non-null. Annotate stale PRs.
|
|
72
|
+
5. Check exclusion rule: if a PR has `prStatus: DRAFT` and `ciStatus: NOT_STARTED` for more than 5 minutes since `firstSeenAt`, mark it as `EXCLUDED` (DRAFT PRs may not trigger CI)
|
|
73
|
+
6. Check terminal conditions — a PR is terminal when:
|
|
74
|
+
- It is NOT stale, AND:
|
|
75
|
+
- CI status is `SUCCEEDED`, `CANCELED`, or `TIMED_OUT`, OR
|
|
76
|
+
- CI status is `FAILED` AND there is no active self-healing (i.e., `selfHealingStatus` is null or a final state like `APPLIED`, `REJECTED`, `FAILED`)
|
|
77
|
+
- A `FAILED` PR with `selfHealingStatus` indicating an in-progress fix (e.g., `PENDING`, `IN_PROGRESS`) is NOT terminal — keep polling to track the self-healing outcome
|
|
78
|
+
- A **stale** PR is NOT terminal — keep polling until it gets a fresh CIPE or is excluded
|
|
79
|
+
7. **Stale timeout**: If a stale PR remains stale for more than 5 minutes, assume no new CI is expected for it. Clear the stale flag and treat its current status as final.
|
|
80
|
+
8. If all non-excluded PRs are terminal → proceed to Phase 3
|
|
81
|
+
9. If timeout or circuit breaker hit → proceed to Phase 3 with partial results
|
|
82
|
+
10. Otherwise → wait with backoff, then poll again
|
|
83
|
+
|
|
84
|
+
## Phase 3: Results Analysis
|
|
85
|
+
|
|
86
|
+
Categorize repos into: succeeded, failed, canceled, timed_out, excluded, in_progress (if timed out).
|
|
87
|
+
|
|
88
|
+
Display final summary table. When showing self-healing status, distinguish clearly between these states:
|
|
89
|
+
|
|
90
|
+
- `COMPLETED` = a fix was **generated and verified**, but **NOT yet applied**. Display as `fix available`.
|
|
91
|
+
- `APPLIED` = the fix was **applied** by the user or agent. Display as `fix applied, awaiting re-run`.
|
|
92
|
+
- `IN_PROGRESS` / `PENDING` = the fix is still being generated. Display as `in progress`.
|
|
93
|
+
- `REJECTED` = the fix was rejected. Display as `fix rejected`.
|
|
94
|
+
- `FAILED` = self-healing failed to produce a fix. Display as `fix failed`.
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
[await-polygraph-ci] Final Results | Elapsed: Xm
|
|
98
|
+
SUCCEEDED: backend, shared-lib
|
|
99
|
+
FAILED: frontend (self-healing: fix available)
|
|
100
|
+
EXCLUDED: docs (DRAFT, no CI)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Include self-healing status for any repo that has one.
|
|
104
|
+
|
|
105
|
+
- If all succeeded → report success and exit
|
|
106
|
+
- If any failed with `selfHealingStatus: APPLIED`, inform the user that the fix was applied and a CI re-run may be in progress or needed
|
|
107
|
+
- If any failed with `selfHealingStatus: COMPLETED`, inform the user that a fix is **available but not yet applied**, and offer to apply it
|
|
108
|
+
- If any failed → proceed to Phase 4
|
|
109
|
+
|
|
110
|
+
## Phase 4: Failure Investigation (Child Agent Delegation)
|
|
111
|
+
|
|
112
|
+
For each repo with `ciStatus: FAILED`, first check the CI data source from `ciStatus[prId]`:
|
|
113
|
+
|
|
114
|
+
- **If `cipeUrl` is non-null** → CIPE is authoritative. Delegate investigation using `ci_information`.
|
|
115
|
+
- **If `cipeUrl` is null but `externalCIRuns` exists** → external CI only. Examine failed jobs from `externalCIRuns` in the session data and use `get_ci_logs` for log retrieval.
|
|
116
|
+
|
|
117
|
+
1. Display known info from the session data before delegating:
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
Repository: frontend
|
|
121
|
+
CI Source: <CIPE or External CI (GitHub Actions)>
|
|
122
|
+
CI Pipeline: <cipeUrl from session, or GitHub Actions run URL>
|
|
123
|
+
Self-healing: <selfHealingStatus from session, or "None">
|
|
124
|
+
Investigating failure details...
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
2. **Delegate investigation** (non-blocking) — call `spawn_agent` for each failed repo:
|
|
128
|
+
|
|
129
|
+
- `sessionId`: the session ID
|
|
130
|
+
- `repo`: the repository name
|
|
131
|
+
- `instruction` (when CIPE exists): Use the `ci_information` tool to investigate the CI failure on this branch. Return a structured summary with: (1) list of failed task IDs with a one-line error summary each, (2) failure category (Build / Test / Lint / E2E / Infra / Other).
|
|
132
|
+
- `instruction` (when no CIPE, external CI only): The session data shows external CI failures with these failed jobs: [list jobId + name from `externalCIRuns[].jobs` where `conclusion` is `failure`]. Use `get_ci_logs(sessionId, repoId, jobId)` to save the log for each failed job to a local file, then use the `Read` tool to examine the log file contents. Return a structured summary with: (1) one-line error summary per failed job, (2) failure category (Build / Test / Lint / E2E / Infra / Other), (3) relevant log excerpts.
|
|
133
|
+
- `context`: Polygraph session monitoring — investigating CI failure for unified summary. The repository ID for this repo is available from the session data.
|
|
134
|
+
|
|
135
|
+
Since `spawn_agent` is non-blocking, you can delegate to multiple failed repos in parallel.
|
|
136
|
+
|
|
137
|
+
3. **Monitor investigation progress** — poll `show_agent` to wait for each child agent to complete:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
show_agent(sessionId: "<session-id>", repo: "frontend")
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Poll until the child agent's status indicates completion. Use the `tail` parameter to retrieve recent output lines containing the investigation results.
|
|
144
|
+
|
|
145
|
+
4. Collect each child agent's response from the status output. If a child agent fails or gets stuck, use `stop_agent` to terminate it and skip that repo.
|
|
146
|
+
|
|
147
|
+
5. Display failure summary for each repo:
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
Repository: frontend
|
|
151
|
+
CI Pipeline: <cipeUrl>
|
|
152
|
+
Failed Tasks (2):
|
|
153
|
+
- frontend:build → TypeScript error in src/app.tsx:42
|
|
154
|
+
- frontend:test → 3 test suites failed
|
|
155
|
+
Category: Build + Test failures
|
|
156
|
+
Self-healing: <selfHealingStatus>
|
|
157
|
+
Job Logs: <number of logs retrieved, if any>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
If CI job logs were retrieved via `get_ci_logs`, include relevant excerpts (error messages, stack traces) in the summary. Keep excerpts concise — only the most relevant lines.
|
|
161
|
+
|
|
162
|
+
## Phase 5: Fix Planning
|
|
163
|
+
|
|
164
|
+
1. Group failures by category (Build, Test, Lint, E2E, Infra)
|
|
165
|
+
2. Identify cross-repo dependency issues (e.g., shared-lib build failure blocking frontend)
|
|
166
|
+
3. Suggest fix order based on dependency graph (upstream repos first)
|
|
167
|
+
4. Present next actions to the user based on self-healing status:
|
|
168
|
+
- If any repo has `selfHealingStatus` with an available fix → offer to **apply self-healing** via `update_self_healing_fix(action: "APPLY")` or **reject** it
|
|
169
|
+
- If self-healing was already applied → offer to **resume monitoring** to watch the re-triggered CI
|
|
170
|
+
- **Delegate fixes**: use Polygraph to send fix instructions to child agents (for repos without self-healing or where self-healing was rejected/failed)
|
|
171
|
+
- **Get more details**: drill into a specific repo's failure
|
|
172
|
+
- **Exit**: done monitoring
|
|
173
|
+
|
|
174
|
+
## Notes
|
|
175
|
+
|
|
176
|
+
- This skill does NOT push code directly. The only write action it may take is applying/rejecting a self-healing fix via `update_self_healing_fix`, which is an Nx Cloud operation (not a local code change).
|
|
177
|
+
- Both `ci_information` and `update_self_healing_fix` responses include a `hints` array with contextual guidance (e.g., disclaimers about which CI Attempt was retrieved). Always check and surface non-empty hints.
|
|
178
|
+
- All heavy CI data inspection happens in child agents via `spawn_agent` to keep this context window clean.
|
|
179
|
+
|
|
180
|
+
- Child agents can use `get_ci_logs` to save CI job logs to local files, but ONLY when no CIPE exists for the PR (`ciStatus[prId].cipeUrl` is null). When a CIPE exists, logs come from the CIPE system via `ci_information`. Job IDs come from `ciStatus[prId].externalCIRuns[].jobs[].jobId` in the `show_session` response. The tool returns a file path (`logFile`) and size (`sizeBytes`) — use the `Read` tool to examine the log content. Logs can be large (100KB+), so only fetch logs for failed or relevant jobs.
|
|
181
|
+
- `spawn_agent` is **non-blocking** — it starts the child agent and returns immediately. Use `show_agent` to poll for results and `stop_agent` to terminate stuck agents.
|
|
182
|
+
- The `show_session` response is compact and safe to poll from the main agent.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: get-latest-ci
|
|
3
|
+
description: Fetch the latest CI pipeline execution for the current branch. Returns the most recent CIPE which may be completed, in progress, or null. Use when you need to review CI status, check failures, or inspect CI state.
|
|
4
|
+
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- mcp__plugin_nx_nx-mcp
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Get Latest CI Information
|
|
11
|
+
|
|
12
|
+
Fetch the latest CI pipeline execution for the current branch. This is a **one-shot fetch** — return results immediately. Do NOT poll, loop, or wait for status changes.
|
|
13
|
+
|
|
14
|
+
## Context
|
|
15
|
+
|
|
16
|
+
- **Current Branch:** !`git branch --show-current`
|
|
17
|
+
- **Current Commit:** !`git rev-parse --short HEAD`
|
|
18
|
+
|
|
19
|
+
## Step 1: Fetch CI Status via Subagent
|
|
20
|
+
|
|
21
|
+
Spawn a `general-purpose` subagent using the Task tool. The subagent will call the MCP tool and return results. Do NOT attempt to fetch CI information yourself — always delegate to the subagent.
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
Task(
|
|
25
|
+
subagent_type: "general-purpose",
|
|
26
|
+
description: "Fetch latest CI status",
|
|
27
|
+
prompt: "Fetch the latest CI pipeline execution status. Do NOT use Bash for this.
|
|
28
|
+
|
|
29
|
+
Use the ci_information tool from the nx MCP server with these parameters:
|
|
30
|
+
select: 'cipeStatus,cipeUrl,branch,commitSha,selfHealingStatus,verificationStatus,userAction,failedTaskIds,verifiedTaskIds,selfHealingEnabled,failureClassification,couldAutoApplyTasks,shortLink,confidence,confidenceReasoning,hints'
|
|
31
|
+
|
|
32
|
+
Return ALL fields from the response as-is. Do not summarize or omit any fields.
|
|
33
|
+
|
|
34
|
+
If cipeStatus is FAILED and selfHealingStatus is COMPLETED or FAILED and there are failedTaskIds, make a SECOND call to the same tool with:
|
|
35
|
+
select: 'taskOutputSummary,suggestedFix,suggestedFixReasoning,suggestedFixDescription'
|
|
36
|
+
|
|
37
|
+
Return those fields too. Only return the first page — do not paginate."
|
|
38
|
+
)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Step 2: Report Results
|
|
42
|
+
|
|
43
|
+
Based on the subagent's response, report to the user. Always include the CIPE URL when available.
|
|
44
|
+
|
|
45
|
+
If the response contains a non-empty `hints` array, include those hints in the output to the user.
|
|
46
|
+
|
|
47
|
+
### No CIPE found (null/empty response)
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
[get-latest-ci] No CI pipeline execution found for branch '<branch>'.
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### CI Succeeded
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
[get-latest-ci] CI passed!
|
|
57
|
+
[get-latest-ci] URL: <cipeUrl>
|
|
58
|
+
[get-latest-ci] Commit: <commitSha>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### CI In Progress / Not Started
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
[get-latest-ci] CI is <IN_PROGRESS|NOT_STARTED>.
|
|
65
|
+
[get-latest-ci] URL: <cipeUrl>
|
|
66
|
+
[get-latest-ci] Commit: <commitSha>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
If self-healing is also in progress, add:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
[get-latest-ci] Self-healing: <selfHealingStatus> | Verification: <verificationStatus>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### CI Failed — With Self-Healing Fix Available
|
|
76
|
+
|
|
77
|
+
When `cipeStatus == 'FAILED'` AND `selfHealingStatus == 'COMPLETED'` AND `suggestedFix != null`:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
[get-latest-ci] CI failed.
|
|
81
|
+
[get-latest-ci] URL: <cipeUrl>
|
|
82
|
+
[get-latest-ci] Commit: <commitSha>
|
|
83
|
+
[get-latest-ci] Failed tasks: <failedTaskIds>
|
|
84
|
+
[get-latest-ci]
|
|
85
|
+
[get-latest-ci] Self-healing fix available!
|
|
86
|
+
[get-latest-ci] Short link: <shortLink>
|
|
87
|
+
[get-latest-ci] Confidence: <confidence> — <confidenceReasoning>
|
|
88
|
+
[get-latest-ci] Verification: <verificationStatus>
|
|
89
|
+
[get-latest-ci] Auto-apply eligible: <couldAutoApplyTasks>
|
|
90
|
+
[get-latest-ci]
|
|
91
|
+
[get-latest-ci] Fix description: <suggestedFixDescription>
|
|
92
|
+
[get-latest-ci] Fix reasoning: <suggestedFixReasoning> (truncated to first page)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### CI Failed — Self-Healing In Progress
|
|
96
|
+
|
|
97
|
+
When `cipeStatus == 'FAILED'` AND `selfHealingStatus == 'IN_PROGRESS'`:
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
[get-latest-ci] CI failed. Self-healing is generating a fix...
|
|
101
|
+
[get-latest-ci] URL: <cipeUrl>
|
|
102
|
+
[get-latest-ci] Commit: <commitSha>
|
|
103
|
+
[get-latest-ci] Failed tasks: <failedTaskIds>
|
|
104
|
+
[get-latest-ci]
|
|
105
|
+
[get-latest-ci] Use /monitor-ci to wait for the fix and apply it.
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### CI Failed — Self-Healing Failed or Not Available
|
|
109
|
+
|
|
110
|
+
When `cipeStatus == 'FAILED'` AND (`selfHealingStatus` is `FAILED`, `NOT_EXECUTABLE`, or `null`):
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
[get-latest-ci] CI failed.
|
|
114
|
+
[get-latest-ci] URL: <cipeUrl>
|
|
115
|
+
[get-latest-ci] Commit: <commitSha>
|
|
116
|
+
[get-latest-ci] Failed tasks: <failedTaskIds>
|
|
117
|
+
[get-latest-ci] Self-healing: <selfHealingStatus or "not available">
|
|
118
|
+
[get-latest-ci] Classification: <failureClassification>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
If `taskOutputSummary` was fetched, include a brief summary of failures.
|
|
122
|
+
|
|
123
|
+
### CI Failed — Environment Issue
|
|
124
|
+
|
|
125
|
+
When `failureClassification == 'ENVIRONMENT_STATE'`:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
[get-latest-ci] CI failed due to environment issue.
|
|
129
|
+
[get-latest-ci] URL: <cipeUrl>
|
|
130
|
+
[get-latest-ci] Classification: ENVIRONMENT_STATE
|
|
131
|
+
[get-latest-ci]
|
|
132
|
+
[get-latest-ci] Use /monitor-ci to request an environment rerun.
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### CI Canceled / Timed Out
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
[get-latest-ci] CI was <CANCELED|TIMED_OUT>.
|
|
139
|
+
[get-latest-ci] URL: <cipeUrl>
|
|
140
|
+
[get-latest-ci] Commit: <commitSha>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### CI Failed — No Tasks Recorded
|
|
144
|
+
|
|
145
|
+
When `cipeStatus == 'FAILED'` AND `failedTaskIds` is empty AND `selfHealingStatus` is null:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
[get-latest-ci] CI failed but no Nx tasks were recorded (likely infrastructure issue).
|
|
149
|
+
[get-latest-ci] URL: <cipeUrl>
|
|
150
|
+
[get-latest-ci] Check CI provider logs for details.
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Important
|
|
154
|
+
|
|
155
|
+
- This skill is **read-only**. Do NOT apply fixes, push code, or modify anything.
|
|
156
|
+
|
|
157
|
+
- Always delegate the MCP call to a subagent. Do NOT call ci_information yourself.
|
|
158
|
+
|
|
159
|
+
- If the user wants to act on the results (apply a fix, monitor, etc.), suggest `/monitor-ci`.
|
|
160
|
+
- If the subagent returns an error, report it and suggest the user check their Nx Cloud connection.
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pack-and-copy
|
|
3
|
+
description: Validate a publisher package change against consumer repos by building + packing the publisher and installing the tarballs into each consumer, so consumer CI can run against the unmerged change. USE WHEN a publisher repo (e.g. a design system, shared library, SDK) has a pending change that needs to be tested in downstream repos before its version is merged and published. TRIGGER when user says "pack and copy", "pre-release test in consumers", "test this package change in <consumer>", "install the unreleased version into the apps", or "validate this change against <consumer repo>".
|
|
4
|
+
|
|
5
|
+
user-invocable: true
|
|
6
|
+
allowed-tools:
|
|
7
|
+
- Bash
|
|
8
|
+
- Read
|
|
9
|
+
- Task
|
|
10
|
+
- AskUserQuestion
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Pack and Copy
|
|
15
|
+
|
|
16
|
+
Validate a publisher package change against its consumer repos **before** the publisher's version bump is merged and published. The flow is:
|
|
17
|
+
|
|
18
|
+
1. Build the publisher package(s) — repo-specific, not automatable.
|
|
19
|
+
2. Run `polygraph _pack-and-copy` (or the `pack_and_copy` MCP tool) to pack them and install the tarballs into each consumer, rewriting `package.json` to a `file:` dependency.
|
|
20
|
+
3. Commit the consumer changes, including `.polygraph-packages/*.tgz`, to a branch, open a PR, and let consumer CI validate the change.
|
|
21
|
+
|
|
22
|
+
This skill covers **steps 1 and 2**. PR creation / CI monitoring is left to the `polygraph` and `await-polygraph-ci` skills.
|
|
23
|
+
|
|
24
|
+
## Available Tools
|
|
25
|
+
|
|
26
|
+
Pack-and-copy functionality is available via both an MCP tool and a CLI command. Use whichever is available in your current environment.
|
|
27
|
+
|
|
28
|
+
| MCP Tool | CLI Equivalent | Description |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| `pack_and_copy` | `polygraph _pack-and-copy` | Pack publisher packages and install tarballs into consumer repos for pre-release validation. |
|
|
31
|
+
|
|
32
|
+
Session discovery / inspection tools (`show_session`, `list_repos`, etc.) come from the `polygraph` skill — see that skill's tool table for the full mapping.
|
|
33
|
+
|
|
34
|
+
## Prerequisites
|
|
35
|
+
|
|
36
|
+
- An active Polygraph session that includes the publisher repo and one or more consumer repos. If you don't have a session yet, run the `polygraph` skill first to create one.
|
|
37
|
+
- The publisher repo's built artifacts are **packable** — i.e. running `npm pack` in the package directory produces a tarball that, when installed, Just Works. If the publisher needs to be built first, you'll need to do that explicitly.
|
|
38
|
+
|
|
39
|
+
## Phase 1: Identify Publishers and Consumers
|
|
40
|
+
|
|
41
|
+
Determine which packages are being changed in the publisher, and which consumer repos need to validate the change.
|
|
42
|
+
|
|
43
|
+
**If the user specified them**, skip to Phase 2.
|
|
44
|
+
|
|
45
|
+
**Otherwise**, inspect the session and the publisher's change:
|
|
46
|
+
|
|
47
|
+
1. Call `show_session(sessionId)` to enumerate the repos in the session and their local paths.
|
|
48
|
+
2. The **publisher** is usually the current repo (where the change is being made). Look at its `package.json` files to find the packages being shipped — the one being changed, or all packages in a monorepo package tree.
|
|
49
|
+
3. The **consumers** are the other repos in the session. Only repos that actually depend on one of the publisher's packages are relevant — the command will auto-skip the rest, but listing them up front keeps the user informed.
|
|
50
|
+
|
|
51
|
+
Before proceeding, print a short table:
|
|
52
|
+
|
|
53
|
+
| Publisher package | Publisher path | Consumer repo | Consumer path |
|
|
54
|
+
| ----------------- | ----------------------- | ------------- | ----------------- |
|
|
55
|
+
| @org/tokens | /path/to/ds/packages/tokens | web-app | /path/to/web-app |
|
|
56
|
+
| @org/button | /path/to/ds/packages/button | web-app | /path/to/web-app |
|
|
57
|
+
|
|
58
|
+
and confirm with the user using `AskUserQuestion` if anything is ambiguous.
|
|
59
|
+
|
|
60
|
+
## Phase 2: Build the Publisher Packages
|
|
61
|
+
|
|
62
|
+
**This step is not automatable.** Build commands vary per repo and per package. Ask the user how to build, or inspect the repo for conventions.
|
|
63
|
+
|
|
64
|
+
Common hints to surface to the user:
|
|
65
|
+
|
|
66
|
+
- A root-level `package.json` with a `build` script that builds all packages (e.g. `npm run build`, `nx run-many -t build`, `pnpm -r build`).
|
|
67
|
+
- Per-package `build` scripts (check each publisher's `package.json`).
|
|
68
|
+
- A `prepack` script — if one exists, `npm pack` will run it automatically and you don't need a separate build step.
|
|
69
|
+
|
|
70
|
+
Run the build. Verify the `dist/` or equivalent output exists in each publisher package directory before proceeding.
|
|
71
|
+
|
|
72
|
+
**If the build fails**, surface the error to the user and stop. Do not attempt to pack a broken package.
|
|
73
|
+
|
|
74
|
+
## Phase 3: Pack and Copy
|
|
75
|
+
|
|
76
|
+
Run `polygraph _pack-and-copy` (or the `pack_and_copy` MCP tool), passing a `--pair` for every (publisher, consumer) combination the user wants to test. The command is deterministic: it computes a unique pre-release version, runs `npm pack` in each publisher, copies the tarballs into each consumer's `.polygraph-packages/` directory, rewrites the consumer's `package.json` deps to point at the tarballs via `file:`, and POSTs a summary of published and consumed packages to the Polygraph session so the UI reflects what was packed where.
|
|
77
|
+
|
|
78
|
+
CLI form:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
polygraph _pack-and-copy \
|
|
82
|
+
--session <session-id> \
|
|
83
|
+
--pair <publisher-path>=<consumer-path> \
|
|
84
|
+
[--pair <publisher-path>=<consumer-path> ...] \
|
|
85
|
+
--json
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
MCP tool form — call `pack_and_copy` with:
|
|
89
|
+
|
|
90
|
+
- `sessionId` (string, required): the Polygraph session ID
|
|
91
|
+
- `pairs` (array, required): one `{ publisherPath, consumerPath }` object per (publisher, consumer) combination
|
|
92
|
+
- `runScripts` (boolean, optional): enable npm lifecycle scripts during `npm pack` (off by default)
|
|
93
|
+
|
|
94
|
+
**Notes:**
|
|
95
|
+
|
|
96
|
+
- `<publisher-path>` / `publisherPath` is the directory containing the publisher package's `package.json` (not necessarily the repo root — for monorepos, this is `packages/<name>/`).
|
|
97
|
+
- `<consumer-path>` / `consumerPath` is the consumer repo's root (where its `package.json` lives).
|
|
98
|
+
- If a consumer doesn't declare a dependency on a publisher's package, that pair is silently skipped for that consumer — the tarball is still produced but not installed there.
|
|
99
|
+
- The command creates a new unique version on each run, but package managers can still keep stale `file:` dependency contents in `node_modules`. Use a forced install on reruns if the consumer still sees old package contents.
|
|
100
|
+
- Consumers' `.polygraph-packages/*.tgz` files **must be tracked and committed** with the consumer branch. Fresh CI clones need those tarballs to install the `file:` dependencies.
|
|
101
|
+
|
|
102
|
+
Parse the JSON output to get the `published` and `consumed` summaries. Print them back to the user:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
Packed:
|
|
106
|
+
- @org/tokens 1.4.2 -> 1.4.3-pg.<session>.<timestamp>
|
|
107
|
+
- @org/button 2.1.0 -> 2.1.1-pg.<session>.<timestamp>
|
|
108
|
+
|
|
109
|
+
Installed into:
|
|
110
|
+
- web-app: @org/tokens, @org/button
|
|
111
|
+
- docs: @org/tokens
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Phase 4: Install in Consumers and Commit
|
|
115
|
+
|
|
116
|
+
For each consumer that received a tarball:
|
|
117
|
+
|
|
118
|
+
1. Run the consumer's package manager install command, e.g. `npm install`, `pnpm install`, or `yarn install`, so the lockfile and `node_modules/` reflect the new `file:` dep. On reruns in the same worktree, use `npm install --force`, `pnpm install --force`, or `yarn install --force` if the consumer still sees old package contents.
|
|
119
|
+
2. Commit the `package.json`, lockfile, and `.polygraph-packages/*.tgz` changes on a dedicated branch.
|
|
120
|
+
|
|
121
|
+
3. Push the branch and open a draft PR using the `polygraph` skill's `push_branch` + `create_pr` flow — **not** directly. The PR description should explain that this is validating an unmerged publisher change.
|
|
122
|
+
|
|
123
|
+
4. Once CI results come in (see the `await-polygraph-ci` skill), report back. Do **not** merge any consumer PR opened via this flow — these PRs are for validation only and should be closed once the publisher's real version lands.
|
|
124
|
+
|
|
125
|
+
## Common Pitfalls
|
|
126
|
+
|
|
127
|
+
- **Forgetting to build**: `npm pack` packs whatever the package's `files` field points at. If `dist/` is stale or missing, the tarball will be broken. Always rebuild before packing unless a `prepack` script does it.
|
|
128
|
+
- **Stale `file:` installs**: package managers may keep old extracted contents for local tarball dependencies after reruns. Use `install --force` if a consumer still sees old package contents.
|
|
129
|
+
- **Peer dependency mismatches**: if the publisher bumps a peer dep, consumers that don't satisfy it may fail to install. Surface this to the user.
|
|
130
|
+
- **Lockfile churn**: installing after a `file:` swap will change the lockfile. That's expected and should be committed alongside the `package.json` and tarball changes.
|
|
131
|
+
- **Multiple publishers in one repo**: pass one `--pair` per publisher package, using the same consumer path. They'll all be bundled into the same `.polygraph-packages/` dir.
|
|
132
|
+
|
|
133
|
+
## Related Skills
|
|
134
|
+
|
|
135
|
+
- `polygraph` — session setup, branch push, PR creation.
|
|
136
|
+
- `await-polygraph-ci` — monitor consumer CI after the PRs are opened.
|