@polygraph/codex-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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polygraph",
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
  "author": {
6
6
  "name": "Narwhal Technologies Inc",
package/.mcp.json CHANGED
@@ -5,7 +5,10 @@
5
5
  "command": "npx",
6
6
  "args": [
7
7
  "@polygraph/mcp@latest"
8
- ]
8
+ ],
9
+ "env": {
10
+ "POLYGRAPH_AGENT_TYPE": "codex"
11
+ }
9
12
  }
10
13
  }
11
14
  }
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.
@@ -18,17 +18,58 @@
18
18
  // injects hook stdout into the model context); never exits non-zero.
19
19
 
20
20
  import {
21
+ appendFileSync,
21
22
  existsSync,
22
23
  mkdirSync,
23
24
  readFileSync,
24
25
  realpathSync,
25
26
  renameSync,
27
+ statSync,
26
28
  writeFileSync,
27
29
  } from 'node:fs';
28
30
  import { homedir } from 'node:os';
29
31
  import { join } from 'node:path';
30
32
  import { fileURLToPath } from 'node:url';
31
33
 
34
+ const HOOK_LOG_MAX_BYTES = 5 * 1024 * 1024;
35
+
36
+ // Append a one-line JSON record of a hook failure to ~/.polygraph/logs/hooks.log.
37
+ // This hook swallows its errors silently and must never write to stdout (Claude
38
+ // Code injects hook stdout into the model context), so this on-disk log is the
39
+ // only record that something went wrong. The logger is itself failure-proof.
40
+ function logHookFailure(
41
+ hook,
42
+ error,
43
+ meta = {},
44
+ home = process.env.HOME?.trim() || homedir()
45
+ ) {
46
+ try {
47
+ const logsDir = join(home, '.polygraph', 'logs');
48
+ mkdirSync(logsDir, { recursive: true });
49
+ const logFile = join(logsDir, 'hooks.log');
50
+
51
+ try {
52
+ if (statSync(logFile).size > HOOK_LOG_MAX_BYTES) {
53
+ renameSync(logFile, `${logFile}.1`);
54
+ }
55
+ } catch {
56
+ // no prior log, or rotation failed — ignore
57
+ }
58
+
59
+ const entry = {
60
+ time: new Date().toISOString(),
61
+ hook,
62
+ pid: process.pid,
63
+ ...meta,
64
+ error: error instanceof Error ? error.message : String(error),
65
+ ...(error instanceof Error && error.stack ? { stack: error.stack } : {}),
66
+ };
67
+ appendFileSync(logFile, JSON.stringify(entry) + '\n');
68
+ } catch {
69
+ // Logging must never throw — a failing logger must not break the hook.
70
+ }
71
+ }
72
+
32
73
  function readStdin() {
33
74
  try {
34
75
  return readFileSync(0, 'utf8');
@@ -147,8 +188,10 @@ export function main() {
147
188
  // process.ppid is the harness pid when the hook is spawned as a child.
148
189
  pid: process.ppid,
149
190
  });
150
- } catch {
151
- // Silent — a broken hook must never break the agent session.
191
+ } catch (error) {
192
+ // Silent toward the agent — a broken hook must never break the session
193
+ // but record it so failures are not invisible.
194
+ logHookFailure(`${process.argv[2] || 'unknown'}:record-session-mapping`, error);
152
195
  }
153
196
  }
154
197
 
@@ -18,7 +18,16 @@
18
18
  //
19
19
  // Outside a Polygraph session (no matching sidecar) the hook is a silent no-op.
20
20
 
21
- import { readFileSync, readdirSync, existsSync, realpathSync } from 'node:fs';
21
+ import {
22
+ appendFileSync,
23
+ existsSync,
24
+ mkdirSync,
25
+ readFileSync,
26
+ readdirSync,
27
+ realpathSync,
28
+ renameSync,
29
+ statSync,
30
+ } from 'node:fs';
22
31
  import { homedir } from 'node:os';
23
32
  import path from 'node:path';
24
33
  import { fileURLToPath } from 'node:url';
@@ -27,6 +36,45 @@ export function polygraphRoot(home = homedir()) {
27
36
  return path.join(home, '.polygraph');
28
37
  }
29
38
 
39
+ const HOOK_LOG_MAX_BYTES = 5 * 1024 * 1024;
40
+
41
+ // Append a one-line JSON record of a hook failure to ~/.polygraph/logs/hooks.log.
42
+ // This hook must never write to stdout except its hookSpecificOutput payload
43
+ // (Claude Code injects hook stdout into the model context), so this on-disk log
44
+ // is the only record that something went wrong. The logger is failure-proof.
45
+ function logHookFailure(
46
+ hook,
47
+ error,
48
+ meta = {},
49
+ home = process.env.HOME?.trim() || homedir()
50
+ ) {
51
+ try {
52
+ const logsDir = path.join(home, '.polygraph', 'logs');
53
+ mkdirSync(logsDir, { recursive: true });
54
+ const logFile = path.join(logsDir, 'hooks.log');
55
+
56
+ try {
57
+ if (statSync(logFile).size > HOOK_LOG_MAX_BYTES) {
58
+ renameSync(logFile, `${logFile}.1`);
59
+ }
60
+ } catch {
61
+ // no prior log, or rotation failed — ignore
62
+ }
63
+
64
+ const entry = {
65
+ time: new Date().toISOString(),
66
+ hook,
67
+ pid: process.pid,
68
+ ...meta,
69
+ error: error instanceof Error ? error.message : String(error),
70
+ ...(error instanceof Error && error.stack ? { stack: error.stack } : {}),
71
+ };
72
+ appendFileSync(logFile, JSON.stringify(entry) + '\n');
73
+ } catch {
74
+ // Logging must never throw — a failing logger must not break the hook.
75
+ }
76
+ }
77
+
30
78
  function readJson(file) {
31
79
  try {
32
80
  return JSON.parse(readFileSync(file, 'utf8'));
@@ -115,30 +163,36 @@ function readStdin() {
115
163
  }
116
164
 
117
165
  export function main() {
118
- let payload = {};
119
- const raw = readStdin();
120
- if (raw) {
121
- try {
122
- payload = JSON.parse(raw);
123
- } catch {
124
- payload = {};
166
+ let agentSessionId = '';
167
+ try {
168
+ let payload = {};
169
+ const raw = readStdin();
170
+ if (raw) {
171
+ try {
172
+ payload = JSON.parse(raw);
173
+ } catch {
174
+ payload = {};
175
+ }
125
176
  }
126
- }
127
177
 
128
- const agentSessionId =
129
- payload.session_id || process.env.CLAUDE_CODE_SESSION_ID || '';
178
+ agentSessionId =
179
+ payload.session_id || process.env.CLAUDE_CODE_SESSION_ID || '';
130
180
 
131
- const context = buildPolygraphContext(agentSessionId);
132
- if (!context) return; // not a Polygraph session — stay silent
181
+ const context = buildPolygraphContext(agentSessionId);
182
+ if (!context) return; // not a Polygraph session — stay silent
133
183
 
134
- process.stdout.write(
135
- JSON.stringify({
136
- hookSpecificOutput: {
137
- hookEventName: 'SessionStart',
138
- additionalContext: context,
139
- },
140
- })
141
- );
184
+ process.stdout.write(
185
+ JSON.stringify({
186
+ hookSpecificOutput: {
187
+ hookEventName: 'SessionStart',
188
+ additionalContext: context,
189
+ },
190
+ })
191
+ );
192
+ } catch (error) {
193
+ // Never let a hook failure surface to the agent; just record it.
194
+ logHookFailure('reinject-polygraph-context', error, { agentSessionId });
195
+ }
142
196
  }
143
197
 
144
198
  // Run only when executed directly as a hook, not when imported (e.g. by tests).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polygraph/codex-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,