@polygraph/cursor-plugin 0.4.51 → 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.
|
@@ -1,6 +1,6 @@
|
|
|
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;
|
|
@@ -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) {
|
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -43,6 +43,8 @@ Polygraph functionality is available via both MCP tools and CLI commands. Use wh
|
|
|
43
43
|
| `select_account` | `polygraph account select` | Select the organization that future commands run against |
|
|
44
44
|
| `whoami` | `polygraph whoami` | Show current auth status and org |
|
|
45
45
|
|
|
46
|
+
**Delegation rules:** `list_repos` and `start_session` MUST be called via the `polygraph-init-subagent` as described in the "Initialize or Join Polygraph Session" section. Direct `add_repo` is allowed only when the user provides exact repo refs for an existing session. `spawn_agent` is a fast, non-blocking call and IS allowed directly in the main conversation — it returns a delegation id. Waited `show_agent` POLLING must run in a background `Task` (`subagent_type: "polygraph-delegate-subagent"`, `run_in_background: true`), collected with `Await`, never inline. One-off unwaited `show_agent` reads in the main conversation are fine and expected — that is how you read a child's result. See [`reference/delegation.md`](reference/delegation.md). The init subagent is launched the same way, by its bare name: a `Task` with `subagent_type: "polygraph-init-subagent"` — without `run_in_background`, since you need its summary before continuing.
|
|
47
|
+
|
|
46
48
|
## CLI Statefulness
|
|
47
49
|
|
|
48
50
|
The Polygraph CLI (`polygraph`) is **stateful**. When you select an organization — via `polygraph account select` or the equivalent MCP tool — that selection is saved globally and all subsequent CLI commands and MCP tool calls operate against it. You do not need to pass the org on every command.
|
|
@@ -69,8 +71,8 @@ After logging in (or if logged in but no org is selected), use `polygraph accoun
|
|
|
69
71
|
|
|
70
72
|
The delegate/monitor/stop steps apply only when working across repos. A single-repo session skips them and still benefits from shared progress, resume, and CI visibility.
|
|
71
73
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
0. **Initialize or join Polygraph session** - If you were spawned inside an existing session (the startup banner names a session ID), reuse it. Call `show_session` first; if it already has repos and the user did not ask to add more, you're done. If the user asks to add exact repo refs, call `add_repo` directly and skip candidate discovery. If the session has no repos and no exact refs were provided, launch the `polygraph-init-subagent` with that `sessionId` so it discovers candidates and uses `add_repo` (NOT `start_session`). Only when there is no session ID at all should the init subagent create a new session.
|
|
75
|
+
1. **Delegate work to each repo** - Call `spawn_agent` for each repo to get a delegation id, then launch one background `polygraph-delegate-subagent` per id to wait on it. With the default role, delegate only to *other* repos — never to the repo you are in; work on it directly (your regular subagents are fine for local work — only Polygraph delegation is reserved for other repos). Delegating into the repo you are in is allowed only with an explicit non-default `role`. Parallel delegation across repos is encouraged. Read [`reference/delegation.md`](reference/delegation.md) before delegating.
|
|
74
76
|
|
|
75
77
|
4. **Monitor child agents** - Let the background poller subagent do the waiting. When it exits, read that child's answer with a single unwaited `show_agent(sessionId, id)` — `result.text` is the child's final message.
|
|
76
78
|
5. **Stop child agents** (if needed) - Use `stop_agent` with the delegation id to cancel an in-progress child agent. The agent's session is preserved for later read-only context restoration; after a resume, wait for explicit user instructions before making changes.
|
|
@@ -97,7 +99,7 @@ There are three cases. Pick exactly one before calling any tool. The case labels
|
|
|
97
99
|
|
|
98
100
|
**Case C — No session at all.** Launch the `polygraph-init-subagent` with only `userContext` (no `sessionId`). The subagent will discover candidates and call `start_session` to create a new session.
|
|
99
101
|
|
|
100
|
-
In case B,
|
|
102
|
+
In case B, call `add_repo` yourself when exact repo refs were provided; otherwise the subagent handles discovery and attachment. In case C the subagent handles session creation. In case A you call `show_session` yourself.
|
|
101
103
|
|
|
102
104
|
**Session ID handling:**
|
|
103
105
|
|
|
@@ -281,7 +283,7 @@ If the session has a description timeline, also display:
|
|
|
281
283
|
|
|
282
284
|
## Best Practices
|
|
283
285
|
|
|
284
|
-
1. **
|
|
286
|
+
1. **Wait in background subagents** — `spawn_agent` is fine to call directly and returns a delegation id, but every waited `show_agent` poll belongs in a background `Task` with `subagent_type: "polygraph-delegate-subagent"` and `run_in_background: true`. Collect that Task with `Await`, and if `Await` returns while the poller is still running, call `Await` again with the same background-task id. Inline polling floods the context with status noise.
|
|
285
287
|
|
|
286
288
|
1. **Read each result once** — when a poller exits, read that child with a single unwaited `show_agent(sessionId, id)`; `result.text` is the child's final message. Only reach for an explicit `tail` if that is not enough.
|
|
287
289
|
1. **Poll child status before proceeding** — Always verify child agents have reached a terminal `child.status` (`'completed'`, `'failed'`, or `'cancelled'`) before pushing branches or creating PRs
|
|
@@ -291,4 +293,6 @@ If the session has a description timeline, also display:
|
|
|
291
293
|
1. **Test integration** before marking PRs ready
|
|
292
294
|
1. **Coordinate merge order** if there are deployment dependencies
|
|
293
295
|
|
|
296
|
+
1. **NEVER run a waited `show_agent` loop in the main conversation**. Waiting MUST run inside `polygraph-delegate-subagent`, launched as a background `Task` and collected with `Await`.
|
|
297
|
+
|
|
294
298
|
1. **Use `stop_agent` to clean up** — Stop child agents that are stuck or no longer needed (pass the delegation id). The child's session is preserved (`sessionPreserved: true`) so the context can be restored later, but after resuming you must wait for explicit user instructions before making changes.
|
|
@@ -41,6 +41,11 @@ For each id, launch one background poller subagent whose entire job is to block
|
|
|
41
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.
|
|
42
42
|
- **OpenCode** — invoke `@polygraph-delegate-subagent`.
|
|
43
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.
|
|
44
49
|
|
|
45
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.
|
|
46
51
|
|