@polygraph/opencode-plugin 0.4.32 → 0.4.34

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
@@ -8,7 +8,7 @@
8
8
  <h1 align="center">Polygraph Skills</h1>
9
9
 
10
10
  <p align="center">
11
- AI agent skills and subagents for <a href="https://nx.dev/features/polygraph">Polygraph</a> multi-repo coordination.
11
+ AI agent skills and subagents for <a href="https://trypolygraph.com/">Polygraph</a> — the meta-harness for maximum agentic autonomy, giving agents visibility across every repo and memory that survives every session.
12
12
  </p>
13
13
 
14
14
  <p align="center">
@@ -23,7 +23,17 @@
23
23
 
24
24
  ## What is Polygraph?
25
25
 
26
- Polygraph is a standalone product for coordinating changes across multiple repositories. It lets AI agents delegate work to child agents in other repos, monitor CI across repos, and manage multi-repo sessions.
26
+ Polygraph is a 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.
27
37
 
28
38
  ## Skills
29
39
 
@@ -36,66 +46,6 @@ Polygraph is a standalone product for coordinating changes across multiple repos
36
46
  - **polygraph-init-subagent** — Discovers candidate repositories and initializes a Polygraph session
37
47
  - **polygraph-delegate-subagent** — Delegates work to a child agent in another repository, polls for completion
38
48
 
39
- ## Codex Installer
40
-
41
- The publishable Codex package now exposes an explicit installer CLI:
42
-
43
- ```sh
44
- npx @polygraph/codex-plugin
45
- ```
46
-
47
- That command copies the packaged Codex plugin into:
48
-
49
- ```text
50
- ~/.agents/plugins/polygraph
51
- ```
52
-
53
- installs the packaged custom Codex subagents into:
54
-
55
- ```text
56
- $CODEX_HOME/agents
57
- ```
58
-
59
- updates the personal Codex marketplace at:
60
-
61
- ```text
62
- ~/.agents/plugins/marketplace.json
63
- ```
64
-
65
- so the `polygraph` plugin points at `./.agents/plugins/polygraph`, and enables the plugin in:
66
-
67
- ```text
68
- $CODEX_HOME/config.toml
69
- ```
70
-
71
- `CODEX_HOME` defaults to `~/.codex` when unset.
72
-
73
- To verify an install, run:
74
-
75
- ```sh
76
- npx @polygraph/codex-plugin check
77
- ```
78
-
79
- ## OpenCode Plugin
80
-
81
- The publishable OpenCode package exposes the skills and subagents through OpenCode's native plugin system. Add it to `opencode.json`:
82
-
83
- ```json
84
- {
85
- "plugin": ["@polygraph/opencode-plugin"]
86
- }
87
- ```
88
-
89
- For repeatable installs, pin the npm version:
90
-
91
- ```json
92
- {
93
- "plugin": ["@polygraph/opencode-plugin@0.4.18"]
94
- }
95
- ```
96
-
97
- The plugin adds its packaged `skills/` directory to OpenCode's skill paths and registers the packaged Markdown agents as `subagent` entries in OpenCode config during startup.
98
-
99
49
  ## Development
100
50
 
101
51
  ```sh
@@ -118,10 +68,8 @@ For the strictest release flow, do not allow direct `npm publish` for the truste
118
68
 
119
69
  ## Learn More
120
70
 
121
- - **[Polygraph](https://nx.dev/features/polygraph)** — Multi-repo coordination with Polygraph
71
+ - **[Polygraph](https://trypolygraph.com/)** — The meta-harness for maximum agentic autonomy
122
72
  - **[@polygraph/mcp](https://www.npmjs.com/package/@polygraph/mcp)** — The MCP server that powers Polygraph tools
123
- - **[Nx AI Agent Skills](https://github.com/nrwl/nx-ai-agents-config)** — The main Nx AI agent skills repo
124
-
125
73
  ## License
126
74
 
127
75
  License information is defined in the package metadata.
@@ -17,7 +17,15 @@
17
17
  // - Refresh: preserves firstSeenAt when a valid prior mapping exists.
18
18
  // - All failures are silently swallowed.
19
19
 
20
- import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
20
+ import {
21
+ appendFileSync,
22
+ existsSync,
23
+ mkdirSync,
24
+ readFileSync,
25
+ renameSync,
26
+ statSync,
27
+ writeFileSync,
28
+ } from 'node:fs';
21
29
  import { homedir } from 'node:os';
22
30
  import path from 'node:path';
23
31
 
@@ -25,6 +33,55 @@ function sanitizeMappingFilename(str) {
25
33
  return str.replace(/[^A-Za-z0-9._-]/g, '_');
26
34
  }
27
35
 
36
+ const HOOK_LOG_MAX_BYTES = 5 * 1024 * 1024;
37
+
38
+ /**
39
+ * Append a one-line JSON record of a hook failure to ~/.polygraph/logs/hooks.log.
40
+ *
41
+ * Hooks otherwise swallow their errors silently (a broken hook must never break
42
+ * the agent session) and must never write to stdout — so this on-disk log is the
43
+ * only record that something went wrong. The logger is itself failure-proof:
44
+ * any error here is swallowed so a logging bug can never break a hook.
45
+ *
46
+ * @param {string} hook Identifier for the failing hook.
47
+ * @param {unknown} error The thrown value.
48
+ * @param {object} [meta] Extra context to record (sessionID, etc.).
49
+ * @param {string} [home] Override HOME for testing.
50
+ */
51
+ export function logHookFailure(
52
+ hook,
53
+ error,
54
+ meta = {},
55
+ home = process.env.HOME?.trim() || homedir()
56
+ ) {
57
+ try {
58
+ const logsDir = path.join(home, '.polygraph', 'logs');
59
+ mkdirSync(logsDir, { recursive: true });
60
+ const logFile = path.join(logsDir, 'hooks.log');
61
+
62
+ // Best-effort rotation so the log can't grow unbounded.
63
+ try {
64
+ if (statSync(logFile).size > HOOK_LOG_MAX_BYTES) {
65
+ renameSync(logFile, `${logFile}.1`);
66
+ }
67
+ } catch {
68
+ // no prior log, or rotation failed — ignore
69
+ }
70
+
71
+ const entry = {
72
+ time: new Date().toISOString(),
73
+ hook,
74
+ pid: process.pid,
75
+ ...meta,
76
+ error: error instanceof Error ? error.message : String(error),
77
+ ...(error instanceof Error && error.stack ? { stack: error.stack } : {}),
78
+ };
79
+ appendFileSync(logFile, JSON.stringify(entry) + '\n');
80
+ } catch {
81
+ // Logging must never throw — a failing logger must not break the hook.
82
+ }
83
+ }
84
+
28
85
  /**
29
86
  * Write (or refresh) the agent-capture mapping for an OpenCode session.
30
87
  * Reads POLYGRAPH_SESSION_ID and POLYGRAPH_CHILD_AGENT from process.env.
@@ -84,7 +141,9 @@ export function writeAgentCaptureMapping(
84
141
 
85
142
  writeFileSync(tmpPath, JSON.stringify(mapping, null, 2) + '\n');
86
143
  renameSync(tmpPath, finalPath);
87
- } catch {
88
- // Silent — a broken plugin hook must never break the agent session.
144
+ } catch (error) {
145
+ // Silent toward the agent — a broken plugin hook must never break the
146
+ // session — but record it so failures are not invisible.
147
+ logHookFailure('opencode:writeAgentCaptureMapping', error, { agentSessionId }, home);
89
148
  }
90
149
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polygraph/opencode-plugin",
3
- "version": "0.4.32",
3
+ "version": "0.4.34",
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
@@ -14,7 +14,7 @@ import path from 'node:path';
14
14
  import { fileURLToPath } from 'node:url';
15
15
  import yaml from 'js-yaml';
16
16
 
17
- import { writeAgentCaptureMapping } from './agent-capture-mapping.mjs';
17
+ import { writeAgentCaptureMapping, logHookFailure } from './agent-capture-mapping.mjs';
18
18
 
19
19
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
20
20
  const packageRoot = __dirname;
@@ -39,11 +39,16 @@ export const PolygraphPlugin = async () => {
39
39
  },
40
40
 
41
41
  'shell.env': async (input, output) => {
42
- output.env.POLYGRAPH_AGENT_SESSION_ID = input.sessionID;
43
- output.env.POLYGRAPH_AGENT_TYPE = 'opencode';
44
- // Record the agent-capture mapping so the Polygraph CLI can bind
45
- // parent-log capture deterministically for this session.
46
- writeAgentCaptureMapping(input.sessionID);
42
+ try {
43
+ output.env.POLYGRAPH_AGENT_SESSION_ID = input.sessionID;
44
+ output.env.POLYGRAPH_AGENT_TYPE = 'opencode';
45
+ // Record the agent-capture mapping so the Polygraph CLI can bind
46
+ // parent-log capture deterministically for this session.
47
+ writeAgentCaptureMapping(input.sessionID);
48
+ } catch (error) {
49
+ // Never let a hook failure break the OpenCode session; just record it.
50
+ logHookFailure('opencode:shell.env', error, { sessionID: input?.sessionID });
51
+ }
47
52
  },
48
53
 
49
54
  // OpenCode has no SessionStart hook, but the Polygraph CLI already seeds the
@@ -52,13 +57,20 @@ export const PolygraphPlugin = async () => {
52
57
  // before each compaction; the note is appended to the summarization prompt
53
58
  // (best-effort — we trust the model to keep the id + repos in the summary).
54
59
  'experimental.session.compacting': async (input, output) => {
55
- const note = polygraphCompactionNote(input.sessionID);
56
- if (note) {
57
- output.context.push(note);
60
+ try {
61
+ const note = polygraphCompactionNote(input.sessionID);
62
+ if (note) {
63
+ output.context.push(note);
64
+ }
65
+ // Refresh the mapping on compaction (same refresh semantics as Claude/Codex
66
+ // SessionStart hooks firing on 'compact').
67
+ writeAgentCaptureMapping(input.sessionID);
68
+ } catch (error) {
69
+ // Never let a hook failure break the OpenCode session; just record it.
70
+ logHookFailure('opencode:session.compacting', error, {
71
+ sessionID: input?.sessionID,
72
+ });
58
73
  }
59
- // Refresh the mapping on compaction (same refresh semantics as Claude/Codex
60
- // SessionStart hooks firing on 'compact').
61
- writeAgentCaptureMapping(input.sessionID);
62
74
  },
63
75
  };
64
76
  };