@polygraph/claude-plugin 0.4.50 → 0.4.52
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
CHANGED
|
@@ -61,7 +61,7 @@ Neither is required — they are a throughput optimization, not a correctness fi
|
|
|
61
61
|
## Skills
|
|
62
62
|
|
|
63
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
|
|
64
|
+
- **adversarial-review** — Second-opinion review by independent per-repo agents that presents and attaches one consolidated review artifact.
|
|
65
65
|
- **await-polygraph-ci** — Wait for CI pipelines to settle across all repos in a session, investigate failures, and present fix options.
|
|
66
66
|
- **get-latest-ci** — One-shot fetch of the latest CI pipeline execution for the current branch.
|
|
67
67
|
- **session-debrief** — Analyze the raw logs of past Polygraph sessions and produce structured, rank-ordered debriefs for use in a different session.
|
|
@@ -82,6 +82,18 @@ npm install
|
|
|
82
82
|
npm run sync-artifacts
|
|
83
83
|
```
|
|
84
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
|
+
|
|
85
97
|
## Releasing
|
|
86
98
|
|
|
87
99
|
Run the `Release PR` GitHub Actions workflow with a version bump (`patch`, `minor`, or `major`).
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
name: session-debrief
|
|
4
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
|
+
model: haiku
|
|
5
6
|
|
|
6
7
|
---
|
|
7
8
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { appendFileSync, mkdirSync, renameSync, statSync } from 'node:fs';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
|
-
import { join } from 'node:path';
|
|
3
|
+
import { basename, join } from 'node:path';
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
5
5
|
|
|
6
6
|
const HOOK_LOG_MAX_BYTES = 5 * 1024 * 1024;
|
|
7
7
|
|
|
8
|
-
const AGENT_TYPES = new Set(['claude', 'codex', 'opencode']);
|
|
8
|
+
const AGENT_TYPES = new Set(['claude', 'codex', 'opencode', 'cursor']);
|
|
9
9
|
const COMMAND_HOOK_TOOL = /^mcp__(?:plugin_polygraph_)?polygraph[-_]mcp__/;
|
|
10
10
|
const OPENCODE_TOOL = /^polygraph(?:(?:-|_)mcp)?_/;
|
|
11
11
|
|
|
@@ -56,6 +56,17 @@ export function buildLinkAgentSessionArgs({
|
|
|
56
56
|
return args;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Node runtime for the JS-entry fallback. This shim also runs inside
|
|
61
|
+
* non-Node hosts (the opencode plugin executes it in-process, and opencode
|
|
62
|
+
* is a compiled Bun binary), where process.execPath is not a Node
|
|
63
|
+
* executable — fall back to PATH resolution there.
|
|
64
|
+
*/
|
|
65
|
+
function nodeRuntime() {
|
|
66
|
+
const base = basename(process.execPath).toLowerCase();
|
|
67
|
+
return base === 'node' || base === 'node.exe' ? process.execPath : 'node';
|
|
68
|
+
}
|
|
69
|
+
|
|
59
70
|
export function linkAgentSession(claim, spawn = spawnSync, env = process.env) {
|
|
60
71
|
if (isManagedChildEnvironment(env)) return false;
|
|
61
72
|
|
|
@@ -67,11 +78,22 @@ export function linkAgentSession(claim, spawn = spawnSync, env = process.env) {
|
|
|
67
78
|
delete commandEnv.POLYGRAPH_CAPTURE_TOKEN;
|
|
68
79
|
}
|
|
69
80
|
|
|
70
|
-
const
|
|
81
|
+
const spawnOptions = {
|
|
71
82
|
encoding: 'utf8',
|
|
72
83
|
env: commandEnv,
|
|
73
84
|
stdio: ['ignore', 'ignore', 'pipe'],
|
|
74
|
-
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
let result = spawn(command, args, spawnOptions);
|
|
88
|
+
|
|
89
|
+
// POLYGRAPH_CLI may point at a plain JS entry that cannot be spawned
|
|
90
|
+
// directly: a dev build without the executable bit, or a platform that
|
|
91
|
+
// cannot exec scripts. A spawn that failed to LAUNCH ran nothing, so the
|
|
92
|
+
// retry under a Node runtime is side-effect free — and anything that
|
|
93
|
+
// spawns directly today keeps its exact behavior.
|
|
94
|
+
if (result?.error && /\.[cm]?js$/i.test(command)) {
|
|
95
|
+
result = spawn(nodeRuntime(), [command, ...args], spawnOptions);
|
|
96
|
+
}
|
|
75
97
|
|
|
76
98
|
if (result?.error) throw result.error;
|
|
77
99
|
if (result?.status !== 0) {
|
|
@@ -89,18 +111,30 @@ export function buildCommandHookLink(payload, agentType, env = process.env) {
|
|
|
89
111
|
if (!payload || typeof payload !== 'object') return undefined;
|
|
90
112
|
if (isManagedChildEnvironment(env)) return undefined;
|
|
91
113
|
|
|
92
|
-
|
|
114
|
+
// Cursor payloads carry the id in both session_id and conversation_id;
|
|
115
|
+
// the fallback keeps the link working if one of them disappears.
|
|
116
|
+
const agentSessionId =
|
|
117
|
+
nonEmptyString(payload.session_id) ?? nonEmptyString(payload.conversation_id);
|
|
93
118
|
if (!agentSessionId) return undefined;
|
|
94
119
|
|
|
120
|
+
// Cursor has no top-level cwd; workspace_roots[0] is the launch directory.
|
|
121
|
+
const workspaceRoot = Array.isArray(payload.workspace_roots)
|
|
122
|
+
? nonEmptyString(payload.workspace_roots[0])
|
|
123
|
+
: undefined;
|
|
124
|
+
|
|
95
125
|
const common = {
|
|
96
126
|
agentType,
|
|
97
127
|
agentSessionId,
|
|
98
|
-
cwd: nonEmptyString(payload.cwd),
|
|
128
|
+
cwd: nonEmptyString(payload.cwd) ?? workspaceRoot,
|
|
99
129
|
transcriptPath: nonEmptyString(payload.transcript_path),
|
|
100
130
|
source: 'hook',
|
|
101
131
|
};
|
|
102
132
|
|
|
103
|
-
|
|
133
|
+
// Claude and Codex send PascalCase event names; cursor sends camelCase.
|
|
134
|
+
if (
|
|
135
|
+
payload.hook_event_name === 'SessionStart' ||
|
|
136
|
+
payload.hook_event_name === 'sessionStart'
|
|
137
|
+
) {
|
|
104
138
|
const polygraphSessionId = nonEmptyString(env.POLYGRAPH_SESSION_ID);
|
|
105
139
|
if (polygraphSessionId) return { ...common, polygraphSessionId };
|
|
106
140
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: adversarial-review
|
|
3
|
-
description:
|
|
3
|
+
description: Review a Polygraph session with independent per-repo reviewers and attach one consolidated review artifact.
|
|
4
4
|
|
|
5
5
|
user-invocable: true
|
|
6
6
|
allowed-tools:
|
|
@@ -14,10 +14,10 @@ allowed-tools:
|
|
|
14
14
|
|
|
15
15
|
# Adversarial Review
|
|
16
16
|
|
|
17
|
-
1.
|
|
17
|
+
1. Skip this step entirely if a reviewer agent was already named — by the user, or in the instruction that launched you (e.g. from `polygraph session review --adversarial`); in that case use that agent and do not ask. Otherwise, **pick the agent**: Ask which should review—`claude`, `codex`, or `opencode` for `spawn_agent`'s `agent` parameter. If the user names a model, pass it via `spawn_agent`'s optional `model` parameter; don't ask about models.
|
|
18
18
|
2. **Get the session description.**
|
|
19
|
-
3. **Get each repo's plan.**
|
|
20
|
-
4. **Delegate one reviewer per repo** in parallel,
|
|
21
|
-
5. **Summarize.**
|
|
22
|
-
6. **Ask what next.** Address
|
|
19
|
+
3. **Get each repo's plan.**
|
|
20
|
+
4. **Delegate one reviewer per repo** in parallel, `role: "reviewer"`. Ask to review, identify issues. Do the delegation even for the "initiator" repo.
|
|
21
|
+
5. **Summarize and attach.** Consolidate reviews into one consolidated Markdown review with per-repo sections and present it to the user. Then call `upload_artifact` once with `sessionId`, that review as `content`, `kind: "review"`, `format: "markdown"`, name `adversarial-review-YYYY-MM-DDTHH-mm-ssZ.md`. If the upload fails, report that separately without suppressing the review.
|
|
22
|
+
6. **Ask what next.** Address feedback or continue. Skip if the user already said.
|
|
23
23
|
7. If the user selects "address the feedback", pass each repo's feedback to the repo default agent (not the reviewer). The initiator should fix things itself without delegating.
|
|
@@ -20,10 +20,14 @@ spawn_agent(
|
|
|
20
20
|
repo: "<org/repo-name>",
|
|
21
21
|
instruction: "<the task instruction>",
|
|
22
22
|
role: "<optional role>",
|
|
23
|
-
context: "<optional context>"
|
|
23
|
+
context: "<optional context>",
|
|
24
|
+
agent: "<optional: claude | codex | opencode>",
|
|
25
|
+
model: "<optional model override>"
|
|
24
26
|
)
|
|
25
27
|
```
|
|
26
28
|
|
|
29
|
+
`agent` picks the child's harness and `model` overrides its default model; include either only when the user named one.
|
|
30
|
+
|
|
27
31
|
Write the instruction as if to a competent engineer who cannot see your conversation: state the goal, the constraints, and what "done" looks like. The child has its own repo and its own context; it inherits nothing from yours.
|
|
28
32
|
|
|
29
33
|
Delegate to several repos in parallel by calling `spawn_agent` once per repo before waiting on any of them.
|
|
@@ -37,6 +41,11 @@ For each id, launch one background poller subagent whose entire job is to block
|
|
|
37
41
|
- **Claude Code** — a background `Task` with `subagent_type: "polygraph:polygraph-delegate-subagent"`, `run_in_background: true`, and description `Delegate to <repo>`. Fall back to the bare agent name only if the namespaced form is not found.
|
|
38
42
|
- **OpenCode** — invoke `@polygraph-delegate-subagent`.
|
|
39
43
|
- **Codex** — launch `agent_type: "polygraph-delegate-subagent"` via Codex's own `spawn_agent`, and collect it with `wait_agent`.
|
|
44
|
+
- **Cursor** — a background `Task` with `subagent_type: "polygraph-delegate-subagent"`, `run_in_background: true`, and description `Delegate to <repo>`. Collect it with `Await`.
|
|
45
|
+
|
|
46
|
+
A collect step that returns while the poller subagent is still running has not failed. It has only reached the end of its collection window. Collect the same background-task id again, as many times as it takes for the poller subagent to stop. A poller that runs for several minutes is ordinary, and it is never a reason to take the wait back into the main conversation.
|
|
47
|
+
|
|
48
|
+
The background-task id is the handle your own harness returned when you launched the poller. It is not the Polygraph delegation id (`frontend-1`), which addresses the child agent. Once the poller subagent has finished, do not collect it again: read the child instead, as described below. A child that stops for attention also ends the poller, so treat that as a finished poller and not as a collection window running out.
|
|
40
49
|
|
|
41
50
|
The poller has exactly one tool and cannot read logs. It exits with a few lines naming the repo, the id, and the final status. That message is a doorbell, not a report — it tells you the child is worth reading, and nothing about what the child did.
|
|
42
51
|
|