@polygraph/cursor-plugin 0.4.51
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/README.md +113 -0
- package/agents/polygraph-delegate-subagent.md +65 -0
- package/agents/polygraph-init-subagent.md +157 -0
- package/agents/session-debrief.md +28 -0
- package/bin/polygraph-cursor-plugin.mjs +192 -0
- package/hooks/agent-session-link.mjs +163 -0
- package/hooks/hooks.json +10 -0
- package/hooks/record-session-mapping.mjs +62 -0
- package/package.json +36 -0
- package/plugin.json +5 -0
- package/skills/adversarial-review/SKILL.md +15 -0
- package/skills/await-polygraph-ci/SKILL.md +206 -0
- package/skills/get-latest-ci/SKILL.md +150 -0
- package/skills/pack-and-copy/SKILL.md +129 -0
- package/skills/polygraph/SKILL.md +294 -0
- package/skills/polygraph/reference/ci-job-logs.md +38 -0
- package/skills/polygraph/reference/delegation.md +109 -0
- package/skills/polygraph/reference/publish-changes.md +153 -0
- package/skills/polygraph/reference/sandboxing.md +33 -0
- package/skills/polygraph/reference/session-by-commit.md +25 -0
- package/skills/polygraph/reference/session-description.md +111 -0
- package/skills/polygraph/reference/shallow-clone-history.md +9 -0
- package/skills/session-debrief/SKILL.md +57 -0
- package/skills/session-start/SKILL.md +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/nrwl/polygraph-skills/main/source/assets/polygraph-light.svg">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/nrwl/polygraph-skills/main/source/assets/polygraph.svg" alt="Polygraph Logo" width="140">
|
|
5
|
+
</picture>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<h1 align="center">Polygraph Skills</h1>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
AI agent skills and subagents for <a href="https://trypolygraph.com/">Polygraph</a> — the agent-agnostic meta-harness for maximum agentic autonomy, giving agents visibility across every repo and memory that survives every session.
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<img src="https://img.shields.io/badge/Codex-555?logo=openai&logoColor=white&style=flat" alt="Codex">
|
|
16
|
+
<img src="https://img.shields.io/badge/Claude_Code-555?logo=anthropic&logoColor=white&style=flat" alt="Claude Code">
|
|
17
|
+
<img src="https://img.shields.io/badge/GitHub_Copilot-555?logo=github&logoColor=white&style=flat" alt="GitHub Copilot">
|
|
18
|
+
<img src="https://img.shields.io/badge/Gemini-555?logo=google&logoColor=white&style=flat" alt="Gemini">
|
|
19
|
+
<img src="https://img.shields.io/badge/OpenCode-555?logo=terminal&logoColor=white&style=flat" alt="OpenCode">
|
|
20
|
+
<br>
|
|
21
|
+
<img src="https://img.shields.io/github/license/nrwl/polygraph-skills" alt="License">
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
## What is Polygraph?
|
|
25
|
+
|
|
26
|
+
Polygraph is the agent-agnostic meta-harness for maximum agentic autonomy. It works with the agents you already use and gives them what they're missing: visibility across every repo boundary, and memory that survives every session. Agents discover how repositories relate, coordinate changes across them, and hand off or resume work later with repos, branches, PRs, and logs all preserved.
|
|
27
|
+
|
|
28
|
+
## Setup
|
|
29
|
+
|
|
30
|
+
Run the interactive setup and follow the prompts:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
polygraph config
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
It detects your AI agent — Claude Code, Codex, OpenCode, and more — and installs the Polygraph skills and subagents for it. Re-run it any time to add another agent or update an existing install.
|
|
37
|
+
|
|
38
|
+
### Codex: raising the long-poll ceiling
|
|
39
|
+
|
|
40
|
+
The delegate subagent polls child agents with `show_agent(waitForTransitionMs: 300000)` — a single 5-minute wait instead of a stream of short polls, which is what keeps delegation cheap. Claude Code and OpenCode honor the full wait. Codex does not by default.
|
|
41
|
+
|
|
42
|
+
Codex caps every MCP tool call at `tool_timeout_sec = 60`, so long polls effectively cap at 50s. Nothing the plugin ships can change that: a plugin's `.mcp.json` has no timeout field, and `tool_timeout_sec` is only read from `~/.codex/config.toml`. Polling still works at 50s — the MCP resolves the real ceiling per client and returns early rather than erroring — you just pay for more round trips.
|
|
43
|
+
|
|
44
|
+
To get the full 5-minute wait under Codex, set **both**:
|
|
45
|
+
|
|
46
|
+
1. `tool_timeout_sec` in `~/.codex/config.toml`:
|
|
47
|
+
|
|
48
|
+
```toml
|
|
49
|
+
[mcp_servers.polygraph]
|
|
50
|
+
tool_timeout_sec = 360
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
2. `POLYGRAPH_MCP_MAX_WAIT_MS` in that server's env, if you launch it from the CLI:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
POLYGRAPH_MCP_MAX_WAIT_MS=300000
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Neither is required — they are a throughput optimization, not a correctness fix.
|
|
60
|
+
|
|
61
|
+
## Skills
|
|
62
|
+
|
|
63
|
+
- **polygraph** — Comprehensive guidance for Polygraph sessions: shared context, repository graph visibility, PR/CI state, delegation, and session management.
|
|
64
|
+
- **adversarial-review** — Second-opinion review by independent per-repo agents that presents and attaches one consolidated review artifact.
|
|
65
|
+
- **await-polygraph-ci** — Wait for CI pipelines to settle across all repos in a session, investigate failures, and present fix options.
|
|
66
|
+
- **get-latest-ci** — One-shot fetch of the latest CI pipeline execution for the current branch.
|
|
67
|
+
- **session-debrief** — Analyze the raw logs of past Polygraph sessions and produce structured, rank-ordered debriefs for use in a different session.
|
|
68
|
+
|
|
69
|
+
## Agents
|
|
70
|
+
|
|
71
|
+
- **polygraph-init-subagent** — Discovers candidate repositories and initializes a Polygraph session.
|
|
72
|
+
- **polygraph-delegate-subagent** — Delegates work to a child agent in another repository, polls for completion.
|
|
73
|
+
- **session-debrief** — Analyzes the raw logs of past Polygraph sessions and returns a structured, rank-ordered debrief for the current task.
|
|
74
|
+
|
|
75
|
+
## Development
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
# Install dependencies
|
|
79
|
+
npm install
|
|
80
|
+
|
|
81
|
+
# Regenerate generated artifacts
|
|
82
|
+
npm run sync-artifacts
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Estimate the compiled prompt cost of every skill and subagent for Claude Code,
|
|
86
|
+
Codex, and OpenCode:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
npm run report:token-costs
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The report uses four characters per estimated token by default. Override the
|
|
93
|
+
ratio when needed with `npm run report:token-costs -- --characters-per-token 3.5`.
|
|
94
|
+
Pull requests run the same report when opened or updated and keep the latest
|
|
95
|
+
results in a single collapsible comment.
|
|
96
|
+
|
|
97
|
+
## Releasing
|
|
98
|
+
|
|
99
|
+
Run the `Release PR` GitHub Actions workflow with a version bump (`patch`, `minor`, or `major`).
|
|
100
|
+
It opens a release PR against `main` instead of pushing directly.
|
|
101
|
+
When that PR is merged, the `Stage Release` workflow automatically tags the release and publishes the Claude, Codex, and OpenCode npm packages.
|
|
102
|
+
A maintainer must then review and approve each staged package with 2FA before it is published to the live registry.
|
|
103
|
+
|
|
104
|
+
Configure each npm package's trusted publisher to allow `npm stage publish` from `.github/workflows/publish.yml`.
|
|
105
|
+
For the strictest release flow, do not allow direct `npm publish` for the trusted publisher and disallow token-based publishing after the staged workflow has been verified.
|
|
106
|
+
|
|
107
|
+
## Learn More
|
|
108
|
+
|
|
109
|
+
- **[Polygraph](https://trypolygraph.com/)** — The agent-agnostic meta-harness for maximum agentic autonomy
|
|
110
|
+
- **[@polygraph/mcp](https://www.npmjs.com/package/@polygraph/mcp)** — The MCP server that powers Polygraph tools
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
License information is defined in the package metadata.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
|
|
3
|
+
name: polygraph-delegate-subagent
|
|
4
|
+
description: Waits for one Polygraph child agent (addressed by delegation id) to finish or need attention, then exits with a short fixed message. Never reads logs. Runs in the background.
|
|
5
|
+
is_background: true
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Polygraph Delegate Subagent
|
|
10
|
+
|
|
11
|
+
You wait for one Polygraph child agent to finish. You do not read its work.
|
|
12
|
+
|
|
13
|
+
The main agent already spawned the child via `spawn_agent` and received a delegation id. Your entire job is to poll that id until the child needs attention, then exit with a short fixed message. The main agent reads the child's result itself — every log line you echo is duplicated tokens, so you never fetch logs.
|
|
14
|
+
|
|
15
|
+
## Input (from the main agent)
|
|
16
|
+
|
|
17
|
+
| Parameter | Description |
|
|
18
|
+
| ----------- | ------------------------------------------------------------ |
|
|
19
|
+
| `sessionId` | The Polygraph session ID |
|
|
20
|
+
| `id` | The delegation id returned by `spawn_agent` (e.g. `frontend-1`) |
|
|
21
|
+
|
|
22
|
+
## Two ways to poll
|
|
23
|
+
|
|
24
|
+
| MCP tool | CLI equivalent |
|
|
25
|
+
| ------------ | ------------------------------------------------------------------------------------- |
|
|
26
|
+
| `show_agent` | `polygraph agent show --session <sessionId> --id <id> --wait-for-transition-ms 300000` |
|
|
27
|
+
|
|
28
|
+
Prefer the MCP tool. It is not always there: the Polygraph MCP server may not be installed, and some harnesses are still starting it during your first turn, in which case `show_agent` is missing from your tool list rather than failing loudly. Check your available tools before the first poll. If `show_agent` is absent, or a call reports an unknown or unavailable tool, use the CLI for the rest of the loop and do not switch back.
|
|
29
|
+
|
|
30
|
+
The CLI takes the same two identifiers, blocks the same way, and prints the same payload as JSON on stdout: `{ "success": true, "sessionId": "…", "children": [ … ] }`. Read `children[0]` from it exactly as you would from the tool response. Everything below applies to whichever one you are using.
|
|
31
|
+
|
|
32
|
+
## Loop
|
|
33
|
+
|
|
34
|
+
Call `show_agent` with exactly these arguments, repeatedly:
|
|
35
|
+
|
|
36
|
+
- `sessionId`: the session ID
|
|
37
|
+
- `id`: the delegation id
|
|
38
|
+
- `waitForTransitionMs`: 300000
|
|
39
|
+
|
|
40
|
+
Never pass `tail`. Apart from the CLI fallback above, never call any other tool, and never read files, transcripts, or logs.
|
|
41
|
+
|
|
42
|
+
Each call blocks up to 5 minutes, then returns the child's `status` on `children[0]`:
|
|
43
|
+
|
|
44
|
+
- `in-progress` or `created` → poll again with the same arguments.
|
|
45
|
+
- `completed`, `failed`, `cancelled`, `input-required`, or `permission-required` → stop looping and exit with the message below.
|
|
46
|
+
|
|
47
|
+
If a call errors, retry it once. If it errors again, exit with the error text plus the delegation id and stop.
|
|
48
|
+
|
|
49
|
+
## Exit message (fixed template)
|
|
50
|
+
|
|
51
|
+
Return exactly this, filled in from the last `show_agent` response — nothing more:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
Child agent <id> is done.
|
|
55
|
+
|
|
56
|
+
**Repo:** <repoFullName>
|
|
57
|
+
**Delegation id:** <id>
|
|
58
|
+
**Status:** <status>
|
|
59
|
+
|
|
60
|
+
Read the result with show_agent (id: "<id>").
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
For `input-required` or `permission-required`, replace "is done." with "needs attention." and keep everything else identical.
|
|
64
|
+
|
|
65
|
+
Do not summarize, quote, or describe the child's work. Do not include log lines. The main agent reads the result itself via `show_agent`.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
|
|
3
|
+
name: polygraph-init-subagent
|
|
4
|
+
description: Discovers candidate repositories or adds exact repository refs directly, initializes a Polygraph session, or fetches details of an existing session. Returns a structured summary of the session with repos, repository IDs, and session URL.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Polygraph Init Subagent
|
|
9
|
+
|
|
10
|
+
You are a Polygraph initialization subagent. Your job is to add exact repository refs directly when provided, discover candidate repositories when needed, initialize a Polygraph session, and return a structured summary.
|
|
11
|
+
|
|
12
|
+
## Available Tools
|
|
13
|
+
|
|
14
|
+
These tools are available via MCP and CLI. Use whichever is available in your environment.
|
|
15
|
+
|
|
16
|
+
| MCP Tool | CLI Equivalent | Description |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| `list_repos` | `polygraph repo list` | Discover candidate repositories. |
|
|
19
|
+
| `start_session` | `polygraph session start --repo <ids>` | Initialize a NEW session with selected repositories. Only use when no `sessionId` was provided. |
|
|
20
|
+
| `add_repo` | — | Attach repositories to an EXISTING session. Use when `sessionId` was provided and the session has no repos yet, or when the user wants to add more. |
|
|
21
|
+
| `show_session` | `polygraph session show <id> [--details]` | Get full session details including URL, and use details when session summary, repo IDs, PR URLs, and PR descriptions are needed |
|
|
22
|
+
|
|
23
|
+
## Input Parameters (from Main Agent)
|
|
24
|
+
|
|
25
|
+
The main agent provides these parameters in the prompt:
|
|
26
|
+
|
|
27
|
+
| Parameter | Description |
|
|
28
|
+
| ---------------------- | ----------------------------------------------------------------------- |
|
|
29
|
+
| `sessionId` | (Optional) If provided, use this session — never call `start_session`. If the session is empty, attach repos via `add_repo`. If it already has repos, just fetch details. |
|
|
30
|
+
| `userContext` | Description of what the user wants to do, to help select relevant repos |
|
|
31
|
+
| `selectedRepoIds` | (Optional) Pre-selected repository IDs or refs to include; skip repo selection |
|
|
32
|
+
|
|
33
|
+
Additionally, the main agent may pass in repos via **MCP resource syntax** (e.g. `polygraph://repos/org/repo-name`).
|
|
34
|
+
|
|
35
|
+
**Direct-add rule:** If `sessionId` is provided and the prompt names exact repositories to add by ID, short name, full name, GitHub `owner/repo` slug, URL-like slug, or MCP resource syntax, call `add_repo` directly with those refs in `repoIds`. Refs are not limited to organization repos — public open-source repos can be added by `owner/repo` slug or URL, even though they never appear in `list_repos`. Do NOT call `list_repos`, do NOT ask for candidates, and do NOT require candidate discovery first. Candidate discovery is account-repo-only; `list_repos` is only for discovery/filtering when the user does not know the exact repo or explicitly wants candidate selection.
|
|
36
|
+
|
|
37
|
+
## Workflow
|
|
38
|
+
|
|
39
|
+
### Decide which mode to run in
|
|
40
|
+
|
|
41
|
+
Pick one branch up front based on whether `sessionId` was provided:
|
|
42
|
+
|
|
43
|
+
1. **No `sessionId`** — create a new session. Run Step 1 → Step 2 → Step 3a (`start_session`) → Step 4 → Step 5.
|
|
44
|
+
2. **`sessionId` provided, session already has repos, and the user did not ask to add more** — just inspect. Skip directly to Step 4 (`show_session`) → Step 5. Do NOT call `list_repos`, `start_session`, or `add_repo`.
|
|
45
|
+
3. **`sessionId` provided, session has no repos, or user asked to add more** — attach repos to the existing session. First call `show_session` to confirm the current repo list. If exact repo refs were provided, skip Step 1 and Step 2, then call Step 3b (`add_repo`) directly with those refs. Otherwise run Step 1 → Step 2 → Step 3b (`add_repo`) → Step 4 → Step 5.
|
|
46
|
+
|
|
47
|
+
**Hard rule:** if `sessionId` is provided, NEVER call `start_session` — that would create a brand-new session and orphan the one the parent is already in. Use `add_repo` instead.
|
|
48
|
+
|
|
49
|
+
To distinguish modes 2 and 3, call `show_session(sessionId)` before deciding. If the session repository list is empty, or the parent agent explicitly asked you to add or discover more repos, proceed with mode 3; otherwise mode 2.
|
|
50
|
+
|
|
51
|
+
### Step 1: Discover Candidate Repos
|
|
52
|
+
|
|
53
|
+
**Skip this step** in mode 2 (existing session, already populated), or if repos were already provided via `selectedRepoIds`, exact repo refs, or MCP resource syntax and the user hasn't asked to discover more.
|
|
54
|
+
|
|
55
|
+
Call `list_repos` to discover available candidate repositories:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
list_repos()
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`list_repos` accepts these optional parameters; set whichever apply. Refer to the tool schema for each parameter.
|
|
62
|
+
|
|
63
|
+
- `connectedTo`: repo ID, name, or full name (e.g. `nrwl/ocean`); pair with `connectionType`
|
|
64
|
+
- `connectionType`: `directly-upstream` | `directly-downstream` | `directly-both` (default) | `upstream` | `downstream` | `both`
|
|
65
|
+
- `publishedPackages`, `consumedPackages`, `publishedApis`, `consumedApis`: arrays of package names / API paths
|
|
66
|
+
- `nameFilter`: array of repo name patterns (e.g. `nrwl/*`)
|
|
67
|
+
- `semanticQuery`: free-text description of the repositories you want
|
|
68
|
+
|
|
69
|
+
This returns:
|
|
70
|
+
|
|
71
|
+
- **`repos`**: Candidate account repositories, each with:
|
|
72
|
+
- `id`: Repository ID
|
|
73
|
+
- `name`: Repository name
|
|
74
|
+
- `repository`: Full repo name (e.g., `org/repo`)
|
|
75
|
+
- `provider`: VCS provider (e.g., `GITHUB`)
|
|
76
|
+
|
|
77
|
+
Candidate entries do not include repository descriptions. For natural-language discovery, pass the user's intent in `semanticQuery` so the service can apply semantic matching internally.
|
|
78
|
+
|
|
79
|
+
### Step 2: Select Relevant Repos
|
|
80
|
+
|
|
81
|
+
**Skip this step** in mode 2 (existing session, already populated).
|
|
82
|
+
|
|
83
|
+
If `selectedRepoIds` or exact repo refs were provided by the main agent, use those directly and skip selection.
|
|
84
|
+
|
|
85
|
+
Otherwise, analyze the candidates using the `userContext` to determine which repos are relevant:
|
|
86
|
+
|
|
87
|
+
1. Review each repo's `repository`, `name`, `provider`, and any relationship/filter metadata returned by the tool
|
|
88
|
+
2. Match those fields and any requested filters against the `userContext` to identify relevant repos
|
|
89
|
+
3. Select the repos that are relevant to the task
|
|
90
|
+
4. When uncertain, include all candidates
|
|
91
|
+
5. When the user described the task in natural language and the result is large, re-query with `semanticQuery` set to that description
|
|
92
|
+
|
|
93
|
+
### Step 3: Initialize Polygraph Session or Attach Repos
|
|
94
|
+
|
|
95
|
+
Pick the substep that matches the mode chosen above.
|
|
96
|
+
|
|
97
|
+
#### Step 3a — `start_session` (mode 1: no `sessionId`)
|
|
98
|
+
|
|
99
|
+
Call `start_session` to create a new session with the selected repositories:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
start_session(selectedRepoIds: [...])
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
If no repos were filtered and all candidates should be included, pass every candidate repository ID in `selectedRepoIds`.
|
|
106
|
+
|
|
107
|
+
#### Step 3b — `add_repo` (mode 3: existing empty session)
|
|
108
|
+
|
|
109
|
+
Call `add_repo` to attach the selected repositories to the existing session — do NOT call `start_session`:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
add_repo(sessionId: "<sessionId>", repoIds: [...])
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`repoIds` may be repository IDs from discovery, or exact refs provided by the user: short name, full name, GitHub `owner/repo` slug, URL-like slug, or MCP resource syntax — including repos outside the organization, such as public open-source repos. For exact user-provided refs, pass the strings directly and do not call `list_repos` first.
|
|
116
|
+
|
|
117
|
+
### Step 4: Get Session Details
|
|
118
|
+
|
|
119
|
+
Call `show_session` to retrieve full session information. When joining an existing session to inspect prior work, request details if the tool exposes that option so the response includes repo IDs and PR descriptions:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
show_session(sessionId: "<sessionId>", details: true)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Step 5: Return Summary
|
|
126
|
+
|
|
127
|
+
Return a structured summary in this format:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
## Polygraph Session Initialized
|
|
131
|
+
|
|
132
|
+
**Session ID:** <sessionId>
|
|
133
|
+
**Session URL:** <polygraphSessionUrl>
|
|
134
|
+
|
|
135
|
+
### Repositories in this session
|
|
136
|
+
|
|
137
|
+
| Repo | Repository ID | Relationship |
|
|
138
|
+
| --- | --- | --- |
|
|
139
|
+
| REPO_FULL_NAME | REPOSITORY_ID | DIRECTION (distance: N) |
|
|
140
|
+
|
|
141
|
+
### All Candidates Discovered
|
|
142
|
+
(Only include this section if `list_repos` was called)
|
|
143
|
+
|
|
144
|
+
| Repo | Repository ID | Selected |
|
|
145
|
+
| --- | --- | --- |
|
|
146
|
+
| REPO_FULL_NAME | REPOSITORY_ID | Yes/No |
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Important Notes
|
|
150
|
+
|
|
151
|
+
- Do NOT delegate work to repos — that is the main agent's responsibility
|
|
152
|
+
- Do NOT call `spawn_agent` — only initialize the session, attach repos, or fetch existing session details
|
|
153
|
+
- **NEVER call `start_session` when `sessionId` was provided.** Creating a new session would orphan the one the parent agent is operating in. Use `add_repo` to populate an empty existing session instead.
|
|
154
|
+
- If `sessionId` is provided and the session already has repos, skip discovery and selection unless the user asked to add more repos
|
|
155
|
+
- For exact repo refs, call `add_repo` directly and skip discovery
|
|
156
|
+
- If `start_session` or `add_repo` fails, return the error details so the main agent can handle it
|
|
157
|
+
- Always call `show_session` after init/add (or directly when joining an existing session) to get the session URL
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
|
|
3
|
+
name: session-debrief
|
|
4
|
+
description: Analyze the raw logs of one or more past Polygraph sessions and return a structured, rank-ordered debrief for the current task. Launch as a background agent with a ranked list of relevant Polygraph session IDs/lines and a one-paragraph statement of the current task; it invokes the session-debrief skill, pulls parent and child transcripts via the polygraph CLI, and returns one consolidated debrief. Read-only with respect to the inspected sessions.
|
|
5
|
+
is_background: true
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Session Debrief Subagent
|
|
10
|
+
|
|
11
|
+
You produce debriefs of PAST Polygraph sessions so a parent agent working on a NEW task can decide what context is relevant. You run in the background and speed matters — the parent keeps working while it waits and folds your debrief in whenever it lands.
|
|
12
|
+
|
|
13
|
+
You are READ-ONLY with respect to the inspected sessions: never resume them, never spawn agents into them, never push branches, create PRs, or update their descriptions.
|
|
14
|
+
|
|
15
|
+
## Input Parameters (from Main Agent)
|
|
16
|
+
|
|
17
|
+
The main agent provides these in the prompt:
|
|
18
|
+
|
|
19
|
+
| Parameter | Description |
|
|
20
|
+
| ------------- | ------------------------------------------------------------------------------------------------ |
|
|
21
|
+
| `sessions` | A ranked list of relevant Polygraph sessions (IDs/lines, most relevant first, with optional titles/URLs) |
|
|
22
|
+
| `currentTask` | A one-paragraph statement of the task the parent is currently working on |
|
|
23
|
+
|
|
24
|
+
## What to do
|
|
25
|
+
|
|
26
|
+
Invoke the `session-debrief` skill and follow its procedure and output template exactly. Pass through the ranked session list and the current-task statement you received. The skill is the single source of truth for how to pull transcripts via the polygraph CLI, how to fan out across multiple sessions, and how to format each debrief section — do not reinvent or duplicate that procedure here.
|
|
27
|
+
|
|
28
|
+
Return the consolidated, rank-ordered debrief as your final message.
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// source/cursor/lib/installer.mjs
|
|
4
|
+
import {
|
|
5
|
+
cpSync,
|
|
6
|
+
existsSync,
|
|
7
|
+
mkdirSync,
|
|
8
|
+
readFileSync,
|
|
9
|
+
rmSync
|
|
10
|
+
} from "node:fs";
|
|
11
|
+
import { homedir } from "node:os";
|
|
12
|
+
import { dirname, join, resolve } from "node:path";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
var PLUGIN_NAME = "polygraph";
|
|
15
|
+
var PAYLOAD_ENTRIES = [
|
|
16
|
+
"plugin.json",
|
|
17
|
+
"skills",
|
|
18
|
+
"agents",
|
|
19
|
+
"hooks",
|
|
20
|
+
"package.json",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
];
|
|
24
|
+
function getPackageRootFromMetaUrl(metaUrl) {
|
|
25
|
+
return resolve(dirname(fileURLToPath(metaUrl)), "..");
|
|
26
|
+
}
|
|
27
|
+
function resolveUserHome(env = process.env) {
|
|
28
|
+
const userHome = env.HOME?.trim() || homedir();
|
|
29
|
+
return resolve(expandHome(userHome, env));
|
|
30
|
+
}
|
|
31
|
+
function getPluginInstallPath(userHome) {
|
|
32
|
+
return join(userHome, ".polygraph", "plugins", "cursor", PLUGIN_NAME);
|
|
33
|
+
}
|
|
34
|
+
function expandHome(value, env) {
|
|
35
|
+
if (value === "~" || value.startsWith("~/")) {
|
|
36
|
+
const home = env.HOME?.trim() || homedir();
|
|
37
|
+
return join(home, value.slice(1));
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
function loadPackageMetadata(packageRoot) {
|
|
42
|
+
const packageJsonPath = join(packageRoot, "package.json");
|
|
43
|
+
const pluginManifestPath = join(packageRoot, "plugin.json");
|
|
44
|
+
if (!existsSync(packageJsonPath)) {
|
|
45
|
+
throw new Error(`Missing package.json at ${packageJsonPath}`);
|
|
46
|
+
}
|
|
47
|
+
if (!existsSync(pluginManifestPath)) {
|
|
48
|
+
throw new Error(`Missing Cursor plugin manifest at ${pluginManifestPath}`);
|
|
49
|
+
}
|
|
50
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
51
|
+
const pluginManifest = JSON.parse(readFileSync(pluginManifestPath, "utf8"));
|
|
52
|
+
if (pluginManifest.name !== PLUGIN_NAME) {
|
|
53
|
+
throw new Error(
|
|
54
|
+
`Expected plugin.json name to be "${PLUGIN_NAME}", received "${pluginManifest.name ?? "undefined"}"`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
if (!packageJson.version) {
|
|
58
|
+
throw new Error(`Missing package version in ${packageJsonPath}`);
|
|
59
|
+
}
|
|
60
|
+
return { version: packageJson.version };
|
|
61
|
+
}
|
|
62
|
+
function readInstalledVersion(pluginPath) {
|
|
63
|
+
try {
|
|
64
|
+
const pkg = JSON.parse(
|
|
65
|
+
readFileSync(join(pluginPath, "package.json"), "utf8")
|
|
66
|
+
);
|
|
67
|
+
return typeof pkg.version === "string" ? pkg.version : null;
|
|
68
|
+
} catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function isInstallComplete(pluginPath) {
|
|
73
|
+
return existsSync(join(pluginPath, "plugin.json")) && existsSync(join(pluginPath, "skills"));
|
|
74
|
+
}
|
|
75
|
+
function installPlugin({ packageRoot, env = process.env, force = false }) {
|
|
76
|
+
const { version } = loadPackageMetadata(packageRoot);
|
|
77
|
+
const userHome = resolveUserHome(env);
|
|
78
|
+
const pluginPath = getPluginInstallPath(userHome);
|
|
79
|
+
const installAlreadyPresent = existsSync(pluginPath);
|
|
80
|
+
const previousVersion = installAlreadyPresent ? readInstalledVersion(pluginPath) : null;
|
|
81
|
+
const complete = installAlreadyPresent && isInstallComplete(pluginPath);
|
|
82
|
+
const versionMismatch = installAlreadyPresent && previousVersion !== version;
|
|
83
|
+
const shouldCopy = !installAlreadyPresent || force || versionMismatch || !complete;
|
|
84
|
+
if (shouldCopy) {
|
|
85
|
+
rmSync(pluginPath, { recursive: true, force: true });
|
|
86
|
+
mkdirSync(pluginPath, { recursive: true });
|
|
87
|
+
for (const entry of PAYLOAD_ENTRIES) {
|
|
88
|
+
const src = join(packageRoot, entry);
|
|
89
|
+
if (existsSync(src)) {
|
|
90
|
+
cpSync(src, join(pluginPath, entry), { recursive: true });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
ok: true,
|
|
96
|
+
action: "install",
|
|
97
|
+
plugin: PLUGIN_NAME,
|
|
98
|
+
version,
|
|
99
|
+
previousVersion,
|
|
100
|
+
pluginPath,
|
|
101
|
+
copied: shouldCopy,
|
|
102
|
+
overwritten: installAlreadyPresent && force,
|
|
103
|
+
pluginUpdated: installAlreadyPresent && versionMismatch && !force
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function checkInstall({ packageRoot = null, env = process.env } = {}) {
|
|
107
|
+
const userHome = resolveUserHome(env);
|
|
108
|
+
const pluginPath = getPluginInstallPath(userHome);
|
|
109
|
+
const installed = existsSync(pluginPath) && isInstallComplete(pluginPath);
|
|
110
|
+
const installedVersion = installed ? readInstalledVersion(pluginPath) : null;
|
|
111
|
+
const packageVersion = packageRoot ? loadPackageMetadata(packageRoot).version : null;
|
|
112
|
+
return {
|
|
113
|
+
ok: installed,
|
|
114
|
+
plugin: PLUGIN_NAME,
|
|
115
|
+
pluginPath,
|
|
116
|
+
installed,
|
|
117
|
+
installedVersion,
|
|
118
|
+
packageVersion,
|
|
119
|
+
upToDate: installed && packageVersion !== null ? installedVersion === packageVersion : null
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// source/cursor/bin/polygraph-cursor-plugin.mjs
|
|
124
|
+
var usage = `Usage:
|
|
125
|
+
npx @polygraph/cursor-plugin
|
|
126
|
+
npx @polygraph/cursor-plugin install [--force] [--json]
|
|
127
|
+
npx @polygraph/cursor-plugin check [--json]
|
|
128
|
+
|
|
129
|
+
The install command materializes the plugin payload to a directory the
|
|
130
|
+
Polygraph CLI passes to cursor-agent via --plugin-dir on every launch.
|
|
131
|
+
Manual runs can load it the same way:
|
|
132
|
+
|
|
133
|
+
cursor-agent --plugin-dir <plugin path>`;
|
|
134
|
+
async function main() {
|
|
135
|
+
const args = process.argv.slice(2);
|
|
136
|
+
let command = "install";
|
|
137
|
+
let json = false;
|
|
138
|
+
let force = false;
|
|
139
|
+
for (const arg of args) {
|
|
140
|
+
if (arg === "--json") {
|
|
141
|
+
json = true;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (arg === "--force") {
|
|
145
|
+
force = true;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (arg === "install" || arg === "check") {
|
|
149
|
+
command = arg;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (arg === "--help" || arg === "-h") {
|
|
153
|
+
console.log(usage);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
throw new Error(`Unknown argument: ${arg}
|
|
157
|
+
|
|
158
|
+
${usage}`);
|
|
159
|
+
}
|
|
160
|
+
if (command === "check" && force) {
|
|
161
|
+
throw new Error("--force is only supported with the install command");
|
|
162
|
+
}
|
|
163
|
+
const packageRoot = getPackageRootFromMetaUrl(import.meta.url);
|
|
164
|
+
const result = command === "check" ? checkInstall({ packageRoot, env: process.env }) : installPlugin({ packageRoot, env: process.env, force });
|
|
165
|
+
if (json) {
|
|
166
|
+
console.log(JSON.stringify(result, null, 2));
|
|
167
|
+
} else if (command === "check") {
|
|
168
|
+
if (result.ok) {
|
|
169
|
+
console.log("Polygraph Cursor plugin is materialized.");
|
|
170
|
+
console.log(`Plugin path: ${result.pluginPath}`);
|
|
171
|
+
console.log(`Installed version: ${result.installedVersion ?? "unknown"}`);
|
|
172
|
+
} else {
|
|
173
|
+
console.error(
|
|
174
|
+
`Polygraph Cursor plugin check failed: no complete payload at ${result.pluginPath}.`
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
} else {
|
|
178
|
+
console.log(`Materialized Polygraph Cursor plugin ${result.version}.`);
|
|
179
|
+
console.log(`Plugin path: ${result.pluginPath}`);
|
|
180
|
+
console.log(
|
|
181
|
+
`The Polygraph CLI loads it automatically; manual runs: cursor-agent --plugin-dir ${result.pluginPath}`
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
if (command === "check" && !result.ok) {
|
|
185
|
+
process.exitCode = 1;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
main().catch((error) => {
|
|
189
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
190
|
+
console.error(`polygraph-cursor-plugin failed: ${message}`);
|
|
191
|
+
process.exitCode = 1;
|
|
192
|
+
});
|