@polygraph/opencode-plugin 0.4.24 → 0.4.26
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/package.json +1 -1
- package/server.js +92 -0
- package/skills/polygraph/SKILL.md +1 -1
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { fileURLToPath } from 'node:url';
|
|
4
5
|
import yaml from 'js-yaml';
|
|
@@ -29,6 +30,18 @@ export const PolygraphPlugin = async () => {
|
|
|
29
30
|
output.env.POLYGRAPH_AGENT_SESSION_ID = input.sessionID;
|
|
30
31
|
output.env.POLYGRAPH_AGENT_TYPE = 'opencode';
|
|
31
32
|
},
|
|
33
|
+
|
|
34
|
+
// OpenCode has no SessionStart hook, but the Polygraph CLI already seeds the
|
|
35
|
+
// session id into context at launch. The one thing compaction can drop is
|
|
36
|
+
// that identity, so we steer the summary prompt to retain it. This fires
|
|
37
|
+
// before each compaction; the note is appended to the summarization prompt
|
|
38
|
+
// (best-effort — we trust the model to keep the id + repos in the summary).
|
|
39
|
+
'experimental.session.compacting': async (input, output) => {
|
|
40
|
+
const note = polygraphCompactionNote(input.sessionID);
|
|
41
|
+
if (note) {
|
|
42
|
+
output.context.push(note);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
32
45
|
};
|
|
33
46
|
};
|
|
34
47
|
|
|
@@ -92,3 +105,82 @@ function numberValue(value) {
|
|
|
92
105
|
function recordValue(value) {
|
|
93
106
|
return value && typeof value === 'object' && !Array.isArray(value) ? value : undefined;
|
|
94
107
|
}
|
|
108
|
+
|
|
109
|
+
// --- Polygraph session context (mirrors source/hooks/reinject-polygraph-context.mjs) ---
|
|
110
|
+
//
|
|
111
|
+
// Resolve the Polygraph session for this OpenCode session id from local state,
|
|
112
|
+
// then build a short instruction telling the summarizer to keep the Polygraph
|
|
113
|
+
// session id and repo list in the compaction summary. Returns null when this is
|
|
114
|
+
// not a Polygraph session (no matching parent-log sidecar) — a silent no-op.
|
|
115
|
+
//
|
|
116
|
+
// These helpers must NOT be exported: OpenCode calls every export of this
|
|
117
|
+
// module as a plugin factory, and a factory that doesn't return a hooks object
|
|
118
|
+
// crashes the server on startup ("Unexpected server error").
|
|
119
|
+
|
|
120
|
+
function polygraphCompactionNote(agentSessionId, root) {
|
|
121
|
+
const session = readPolygraphSession(agentSessionId, root);
|
|
122
|
+
if (!session) {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const repos = session.repos
|
|
127
|
+
.map((repo) => repo.repoFullName)
|
|
128
|
+
.filter(Boolean)
|
|
129
|
+
.join(', ');
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
`This conversation is running inside Polygraph session ${session.sessionId}` +
|
|
133
|
+
(repos ? ` (repos: ${repos})` : '') +
|
|
134
|
+
'. Preserve the Polygraph session id and the repo list verbatim in the ' +
|
|
135
|
+
'summary so they remain available after compaction.'
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function readPolygraphSession(
|
|
140
|
+
agentSessionId,
|
|
141
|
+
root = path.join(homedir(), '.polygraph')
|
|
142
|
+
) {
|
|
143
|
+
if (!agentSessionId) {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const sidecarsDir = path.join(root, 'sidecars');
|
|
148
|
+
if (!existsSync(sidecarsDir)) {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const fileName = `parent-${agentSessionId}.json`;
|
|
153
|
+
let polygraphSessionId;
|
|
154
|
+
for (const entry of readdirSync(sidecarsDir, { withFileTypes: true })) {
|
|
155
|
+
if (!entry.isDirectory()) continue;
|
|
156
|
+
const candidate = path.join(sidecarsDir, entry.name, fileName);
|
|
157
|
+
if (existsSync(candidate)) {
|
|
158
|
+
try {
|
|
159
|
+
polygraphSessionId = JSON.parse(readFileSync(candidate, 'utf8')).sessionId;
|
|
160
|
+
} catch {
|
|
161
|
+
polygraphSessionId = undefined;
|
|
162
|
+
}
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (!polygraphSessionId) {
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
let session = {};
|
|
171
|
+
try {
|
|
172
|
+
session = JSON.parse(
|
|
173
|
+
readFileSync(
|
|
174
|
+
path.join(root, 'sessions', polygraphSessionId, 'session', 'session.json'),
|
|
175
|
+
'utf8'
|
|
176
|
+
)
|
|
177
|
+
);
|
|
178
|
+
} catch {
|
|
179
|
+
session = {};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
sessionId: polygraphSessionId,
|
|
184
|
+
repos: Array.isArray(session.repos) ? session.repos : [],
|
|
185
|
+
};
|
|
186
|
+
}
|
|
@@ -105,7 +105,7 @@ The subagent will:
|
|
|
105
105
|
4. Call `show_session` to retrieve session details
|
|
106
106
|
5. Return a summary with session URL and repo info
|
|
107
107
|
|
|
108
|
-
**Case C only — new session just created:** After the init subagent completes and creates the new session, render the session welcome card (skip the session-details block below for this case). Prefer the `session_intro` MCP tool — call it with the session ID; it returns the card as markdown. If that tool is unavailable, run `polygraph session intro -s <sessionId>` via the CLI instead. Either way, print the result to the user verbatim as markdown — do NOT wrap it in a code block or reformat it (the logo is pre-fenced; the rest is live markdown). It needs no other input, and you do not need to call `show_session` first. Then continue (ask the user what they want, or start the requested task).
|
|
108
|
+
**Case C only — new session just created:** After the init subagent completes and creates the new session, render the session welcome card (skip the session-details block below for this case). Prefer the `session_intro` MCP tool — call it with the session ID; it returns the card as markdown. If that tool is unavailable, run `polygraph session intro -s <sessionId>` via the CLI instead. The CLI command is intentionally hidden/internal and may not appear in public command listings, but it remains the correct skill fallback for rendering the welcome card. Either way, print the result to the user verbatim as markdown — do NOT wrap it in a code block or reformat it (the logo is pre-fenced; the rest is live markdown). It needs no other input, and you do not need to call `show_session` first. Then continue (ask the user what they want, or start the requested task).
|
|
109
109
|
|
|
110
110
|
**After receiving the subagent's summary (Case B) or after calling `show_session` for an existing session (Case A), print the session details:**
|
|
111
111
|
|