@polygraph/opencode-plugin 0.4.24 → 0.4.25

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server.js +88 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polygraph/opencode-plugin",
3
- "version": "0.4.24",
3
+ "version": "0.4.25",
4
4
  "description": "AI agent skills and subagents for Polygraph multi-repo coordination",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
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,78 @@ 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
+ export function polygraphCompactionNote(agentSessionId, root) {
117
+ const session = readPolygraphSession(agentSessionId, root);
118
+ if (!session) {
119
+ return undefined;
120
+ }
121
+
122
+ const repos = session.repos
123
+ .map((repo) => repo.repoFullName)
124
+ .filter(Boolean)
125
+ .join(', ');
126
+
127
+ return (
128
+ `This conversation is running inside Polygraph session ${session.sessionId}` +
129
+ (repos ? ` (repos: ${repos})` : '') +
130
+ '. Preserve the Polygraph session id and the repo list verbatim in the ' +
131
+ 'summary so they remain available after compaction.'
132
+ );
133
+ }
134
+
135
+ export function readPolygraphSession(
136
+ agentSessionId,
137
+ root = path.join(homedir(), '.polygraph')
138
+ ) {
139
+ if (!agentSessionId) {
140
+ return undefined;
141
+ }
142
+
143
+ const sidecarsDir = path.join(root, 'sidecars');
144
+ if (!existsSync(sidecarsDir)) {
145
+ return undefined;
146
+ }
147
+
148
+ const fileName = `parent-${agentSessionId}.json`;
149
+ let polygraphSessionId;
150
+ for (const entry of readdirSync(sidecarsDir, { withFileTypes: true })) {
151
+ if (!entry.isDirectory()) continue;
152
+ const candidate = path.join(sidecarsDir, entry.name, fileName);
153
+ if (existsSync(candidate)) {
154
+ try {
155
+ polygraphSessionId = JSON.parse(readFileSync(candidate, 'utf8')).sessionId;
156
+ } catch {
157
+ polygraphSessionId = undefined;
158
+ }
159
+ break;
160
+ }
161
+ }
162
+ if (!polygraphSessionId) {
163
+ return undefined;
164
+ }
165
+
166
+ let session = {};
167
+ try {
168
+ session = JSON.parse(
169
+ readFileSync(
170
+ path.join(root, 'sessions', polygraphSessionId, 'session', 'session.json'),
171
+ 'utf8'
172
+ )
173
+ );
174
+ } catch {
175
+ session = {};
176
+ }
177
+
178
+ return {
179
+ sessionId: polygraphSessionId,
180
+ repos: Array.isArray(session.repos) ? session.repos : [],
181
+ };
182
+ }