@moreih29/nexus-core 0.16.2 → 0.18.2
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 +101 -67
- package/dist/cli/sync.d.ts +3 -0
- package/dist/cli/sync.d.ts.map +1 -0
- package/dist/cli/sync.js +59 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/generate/index.d.ts +3 -0
- package/dist/generate/index.d.ts.map +1 -0
- package/dist/generate/index.js +2 -0
- package/dist/generate/index.js.map +1 -0
- package/dist/generate/load-data.d.ts +8 -0
- package/dist/generate/load-data.d.ts.map +1 -0
- package/dist/generate/load-data.js +45 -0
- package/dist/generate/load-data.js.map +1 -0
- package/dist/generate/load-spec.d.ts +3 -0
- package/dist/generate/load-spec.d.ts.map +1 -0
- package/dist/generate/load-spec.js +48 -0
- package/dist/generate/load-spec.js.map +1 -0
- package/dist/generate/macros/expand.d.ts +3 -0
- package/dist/generate/macros/expand.d.ts.map +1 -0
- package/dist/generate/macros/expand.js +48 -0
- package/dist/generate/macros/expand.js.map +1 -0
- package/dist/generate/macros/parse.d.ts +4 -0
- package/dist/generate/macros/parse.d.ts.map +1 -0
- package/dist/generate/macros/parse.js +142 -0
- package/dist/generate/macros/parse.js.map +1 -0
- package/dist/generate/macros/validate.d.ts +3 -0
- package/dist/generate/macros/validate.d.ts.map +1 -0
- package/dist/generate/macros/validate.js +23 -0
- package/dist/generate/macros/validate.js.map +1 -0
- package/dist/generate/renderers/claude.d.ts +3 -0
- package/dist/generate/renderers/claude.d.ts.map +1 -0
- package/dist/generate/renderers/claude.js +48 -0
- package/dist/generate/renderers/claude.js.map +1 -0
- package/dist/generate/renderers/codex.d.ts +3 -0
- package/dist/generate/renderers/codex.d.ts.map +1 -0
- package/dist/generate/renderers/codex.js +79 -0
- package/dist/generate/renderers/codex.js.map +1 -0
- package/dist/generate/renderers/markdown.d.ts +2 -0
- package/dist/generate/renderers/markdown.d.ts.map +1 -0
- package/dist/generate/renderers/markdown.js +6 -0
- package/dist/generate/renderers/markdown.js.map +1 -0
- package/dist/generate/renderers/opencode.d.ts +3 -0
- package/dist/generate/renderers/opencode.d.ts.map +1 -0
- package/dist/generate/renderers/opencode.js +69 -0
- package/dist/generate/renderers/opencode.js.map +1 -0
- package/dist/generate/sync.d.ts +4 -0
- package/dist/generate/sync.d.ts.map +1 -0
- package/dist/generate/sync.js +60 -0
- package/dist/generate/sync.js.map +1 -0
- package/dist/generate/types.d.ts +74 -0
- package/dist/generate/types.d.ts.map +1 -0
- package/dist/generate/types.js +2 -0
- package/dist/generate/types.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/definitions/artifact.d.ts +20 -0
- package/dist/mcp/definitions/artifact.d.ts.map +1 -0
- package/dist/mcp/definitions/artifact.js +14 -0
- package/dist/mcp/definitions/artifact.js.map +1 -0
- package/dist/mcp/definitions/history.d.ts +20 -0
- package/dist/mcp/definitions/history.d.ts.map +1 -0
- package/dist/mcp/definitions/history.js +18 -0
- package/dist/mcp/definitions/history.js.map +1 -0
- package/dist/mcp/definitions/index.d.ts +276 -0
- package/dist/mcp/definitions/index.d.ts.map +1 -0
- package/dist/mcp/definitions/index.js +16 -0
- package/dist/mcp/definitions/index.js.map +1 -0
- package/dist/mcp/definitions/plan.d.ts +111 -0
- package/dist/mcp/definitions/plan.d.ts.map +1 -0
- package/dist/mcp/definitions/plan.js +89 -0
- package/dist/mcp/definitions/plan.js.map +1 -0
- package/dist/mcp/definitions/task.d.ts +138 -0
- package/dist/mcp/definitions/task.d.ts.map +1 -0
- package/dist/mcp/definitions/task.js +78 -0
- package/dist/mcp/definitions/task.js.map +1 -0
- package/dist/mcp/handlers/artifact.d.ts.map +1 -0
- package/dist/mcp/handlers/artifact.js +42 -0
- package/dist/mcp/handlers/artifact.js.map +1 -0
- package/dist/mcp/handlers/history.d.ts.map +1 -0
- package/dist/mcp/handlers/history.js +35 -0
- package/dist/mcp/handlers/history.js.map +1 -0
- package/dist/mcp/handlers/plan.d.ts.map +1 -0
- package/dist/mcp/handlers/plan.js +324 -0
- package/dist/mcp/handlers/plan.js.map +1 -0
- package/dist/mcp/handlers/task.d.ts.map +1 -0
- package/dist/mcp/handlers/task.js +216 -0
- package/dist/mcp/handlers/task.js.map +1 -0
- package/dist/{src/mcp → mcp}/server.d.ts +1 -1
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +58 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/shared/json-store.d.ts.map +1 -0
- package/dist/{src/shared → shared}/json-store.js +5 -4
- package/dist/shared/json-store.js.map +1 -0
- package/dist/shared/mcp-utils.d.ts.map +1 -0
- package/dist/shared/mcp-utils.js.map +1 -0
- package/dist/{src/shared → shared}/paths.d.ts +0 -4
- package/dist/shared/paths.d.ts.map +1 -0
- package/dist/shared/paths.js +62 -0
- package/dist/shared/paths.js.map +1 -0
- package/dist/shared/register-tool.d.ts +20 -0
- package/dist/shared/register-tool.d.ts.map +1 -0
- package/dist/shared/register-tool.js +15 -0
- package/dist/shared/register-tool.js.map +1 -0
- package/dist/{src/types → types}/state.d.ts +65 -65
- package/dist/types/state.d.ts.map +1 -0
- package/dist/{src/types → types}/state.js +1 -1
- package/dist/types/state.js.map +1 -0
- package/harness/claude/agent-rules.yml +21 -0
- package/harness/claude/invocations.yml +11 -0
- package/harness/claude/layout.yml +3 -0
- package/harness/codex/agent-rules.yml +28 -0
- package/harness/codex/invocations.yml +13 -0
- package/harness/codex/layout.yml +3 -0
- package/harness/opencode/agent-rules.yml +18 -0
- package/harness/opencode/invocations.yml +12 -0
- package/harness/opencode/layout.yml +3 -0
- package/package.json +38 -43
- package/{assets → spec}/agents/architect/body.ko.md +92 -84
- package/spec/agents/architect/body.md +185 -0
- package/spec/agents/designer/body.ko.md +330 -0
- package/spec/agents/designer/body.md +330 -0
- package/spec/agents/engineer/body.ko.md +166 -0
- package/spec/agents/engineer/body.md +166 -0
- package/spec/agents/lead/body.ko.md +276 -0
- package/spec/agents/lead/body.md +276 -0
- package/{assets → spec}/agents/postdoc/body.ko.md +116 -46
- package/spec/agents/postdoc/body.md +192 -0
- package/{assets → spec}/agents/researcher/body.ko.md +131 -45
- package/spec/agents/researcher/body.md +223 -0
- package/spec/agents/reviewer/body.ko.md +219 -0
- package/spec/agents/reviewer/body.md +219 -0
- package/{assets → spec}/agents/strategist/body.ko.md +108 -35
- package/spec/agents/strategist/body.md +187 -0
- package/spec/agents/tester/body.ko.md +272 -0
- package/spec/agents/tester/body.md +272 -0
- package/{assets → spec}/agents/writer/body.ko.md +109 -33
- package/spec/agents/writer/body.md +198 -0
- package/spec/skills/nx-auto-plan/body.ko.md +150 -0
- package/spec/skills/nx-auto-plan/body.md +150 -0
- package/spec/skills/nx-plan/body.ko.md +159 -0
- package/spec/skills/nx-plan/body.md +159 -0
- package/spec/skills/nx-run/body.ko.md +132 -0
- package/spec/skills/nx-run/body.md +132 -0
- package/vocabulary/enums/task-register-state.yml +4 -0
- package/vocabulary/invocations.yml +43 -0
- package/assets/agents/architect/body.md +0 -177
- package/assets/agents/designer/body.ko.md +0 -125
- package/assets/agents/designer/body.md +0 -125
- package/assets/agents/engineer/body.ko.md +0 -106
- package/assets/agents/engineer/body.md +0 -106
- package/assets/agents/lead/body.ko.md +0 -70
- package/assets/agents/lead/body.md +0 -70
- package/assets/agents/postdoc/body.md +0 -122
- package/assets/agents/researcher/body.md +0 -137
- package/assets/agents/reviewer/body.ko.md +0 -138
- package/assets/agents/reviewer/body.md +0 -138
- package/assets/agents/strategist/body.md +0 -116
- package/assets/agents/tester/body.ko.md +0 -195
- package/assets/agents/tester/body.md +0 -195
- package/assets/agents/writer/body.md +0 -122
- package/assets/capability-matrix.yml +0 -198
- package/assets/hooks/agent-bootstrap/handler.test.ts +0 -368
- package/assets/hooks/agent-bootstrap/handler.ts +0 -119
- package/assets/hooks/agent-bootstrap/meta.yml +0 -10
- package/assets/hooks/agent-finalize/handler.test.ts +0 -368
- package/assets/hooks/agent-finalize/handler.ts +0 -76
- package/assets/hooks/agent-finalize/meta.yml +0 -10
- package/assets/hooks/capability-matrix.yml +0 -313
- package/assets/hooks/post-tool-telemetry/handler.test.ts +0 -302
- package/assets/hooks/post-tool-telemetry/handler.ts +0 -49
- package/assets/hooks/post-tool-telemetry/meta.yml +0 -11
- package/assets/hooks/prompt-router/handler.test.ts +0 -801
- package/assets/hooks/prompt-router/handler.ts +0 -272
- package/assets/hooks/prompt-router/meta.yml +0 -11
- package/assets/hooks/session-init/handler.test.ts +0 -274
- package/assets/hooks/session-init/handler.ts +0 -30
- package/assets/hooks/session-init/meta.yml +0 -9
- package/assets/lsp-servers.json +0 -55
- package/assets/schema/lsp-servers.schema.json +0 -67
- package/assets/skills/nx-init/body.ko.md +0 -197
- package/assets/skills/nx-init/body.md +0 -197
- package/assets/skills/nx-plan/body.ko.md +0 -361
- package/assets/skills/nx-plan/body.md +0 -361
- package/assets/skills/nx-run/body.ko.md +0 -161
- package/assets/skills/nx-run/body.md +0 -160
- package/assets/skills/nx-sync/body.ko.md +0 -92
- package/assets/skills/nx-sync/body.md +0 -92
- package/assets/tools/tool-name-map.yml +0 -353
- package/dist/assets/hooks/agent-bootstrap/handler.d.ts +0 -4
- package/dist/assets/hooks/agent-bootstrap/handler.d.ts.map +0 -1
- package/dist/assets/hooks/agent-bootstrap/handler.js +0 -100
- package/dist/assets/hooks/agent-bootstrap/handler.js.map +0 -1
- package/dist/assets/hooks/agent-finalize/handler.d.ts +0 -4
- package/dist/assets/hooks/agent-finalize/handler.d.ts.map +0 -1
- package/dist/assets/hooks/agent-finalize/handler.js +0 -63
- package/dist/assets/hooks/agent-finalize/handler.js.map +0 -1
- package/dist/assets/hooks/post-tool-telemetry/handler.d.ts +0 -4
- package/dist/assets/hooks/post-tool-telemetry/handler.d.ts.map +0 -1
- package/dist/assets/hooks/post-tool-telemetry/handler.js +0 -40
- package/dist/assets/hooks/post-tool-telemetry/handler.js.map +0 -1
- package/dist/assets/hooks/prompt-router/handler.d.ts +0 -4
- package/dist/assets/hooks/prompt-router/handler.d.ts.map +0 -1
- package/dist/assets/hooks/prompt-router/handler.js +0 -214
- package/dist/assets/hooks/prompt-router/handler.js.map +0 -1
- package/dist/assets/hooks/session-init/handler.d.ts +0 -4
- package/dist/assets/hooks/session-init/handler.d.ts.map +0 -1
- package/dist/assets/hooks/session-init/handler.js +0 -23
- package/dist/assets/hooks/session-init/handler.js.map +0 -1
- package/dist/claude/.claude-plugin/marketplace.json +0 -75
- package/dist/claude/.claude-plugin/plugin.json +0 -67
- package/dist/claude/agents/architect.md +0 -172
- package/dist/claude/agents/designer.md +0 -120
- package/dist/claude/agents/engineer.md +0 -98
- package/dist/claude/agents/lead.md +0 -59
- package/dist/claude/agents/postdoc.md +0 -117
- package/dist/claude/agents/researcher.md +0 -132
- package/dist/claude/agents/reviewer.md +0 -133
- package/dist/claude/agents/strategist.md +0 -111
- package/dist/claude/agents/tester.md +0 -190
- package/dist/claude/agents/writer.md +0 -114
- package/dist/claude/dist/hooks/agent-bootstrap.js +0 -121
- package/dist/claude/dist/hooks/agent-finalize.js +0 -180
- package/dist/claude/dist/hooks/prompt-router.js +0 -7336
- package/dist/claude/dist/hooks/session-init.js +0 -37
- package/dist/claude/hooks/hooks.json +0 -52
- package/dist/claude/settings.json +0 -3
- package/dist/claude/skills/nx-init/SKILL.md +0 -189
- package/dist/claude/skills/nx-plan/SKILL.md +0 -353
- package/dist/claude/skills/nx-run/SKILL.md +0 -154
- package/dist/claude/skills/nx-sync/SKILL.md +0 -87
- package/dist/codex/agents/architect.toml +0 -175
- package/dist/codex/agents/designer.toml +0 -123
- package/dist/codex/agents/engineer.toml +0 -105
- package/dist/codex/agents/lead.toml +0 -64
- package/dist/codex/agents/postdoc.toml +0 -120
- package/dist/codex/agents/researcher.toml +0 -136
- package/dist/codex/agents/reviewer.toml +0 -137
- package/dist/codex/agents/strategist.toml +0 -114
- package/dist/codex/agents/tester.toml +0 -194
- package/dist/codex/agents/writer.toml +0 -121
- package/dist/codex/dist/hooks/agent-bootstrap.js +0 -121
- package/dist/codex/dist/hooks/agent-finalize.js +0 -180
- package/dist/codex/dist/hooks/prompt-router.js +0 -7336
- package/dist/codex/dist/hooks/session-init.js +0 -37
- package/dist/codex/hooks/hooks.json +0 -28
- package/dist/codex/install/AGENTS.fragment.md +0 -60
- package/dist/codex/install/config.fragment.toml +0 -5
- package/dist/codex/install/install.sh +0 -60
- package/dist/codex/package.json +0 -20
- package/dist/codex/plugin/.codex-plugin/plugin.json +0 -57
- package/dist/codex/plugin/skills/nx-init/SKILL.md +0 -189
- package/dist/codex/plugin/skills/nx-plan/SKILL.md +0 -353
- package/dist/codex/plugin/skills/nx-run/SKILL.md +0 -154
- package/dist/codex/plugin/skills/nx-sync/SKILL.md +0 -87
- package/dist/codex/prompts/architect.md +0 -166
- package/dist/codex/prompts/designer.md +0 -114
- package/dist/codex/prompts/engineer.md +0 -97
- package/dist/codex/prompts/lead.md +0 -60
- package/dist/codex/prompts/postdoc.md +0 -111
- package/dist/codex/prompts/researcher.md +0 -127
- package/dist/codex/prompts/reviewer.md +0 -128
- package/dist/codex/prompts/strategist.md +0 -105
- package/dist/codex/prompts/tester.md +0 -185
- package/dist/codex/prompts/writer.md +0 -113
- package/dist/hooks/agent-bootstrap.js +0 -121
- package/dist/hooks/agent-finalize.js +0 -180
- package/dist/hooks/prompt-router.js +0 -7336
- package/dist/hooks/session-init.js +0 -37
- package/dist/manifests/claude-hooks.json +0 -52
- package/dist/manifests/codex-hooks.json +0 -28
- package/dist/manifests/opencode-manifest.json +0 -44
- package/dist/manifests/portability-report.json +0 -87
- package/dist/opencode/.opencode/skills/nx-init/SKILL.md +0 -189
- package/dist/opencode/.opencode/skills/nx-plan/SKILL.md +0 -353
- package/dist/opencode/.opencode/skills/nx-run/SKILL.md +0 -154
- package/dist/opencode/.opencode/skills/nx-sync/SKILL.md +0 -87
- package/dist/opencode/package.json +0 -23
- package/dist/opencode/src/agents/architect.ts +0 -176
- package/dist/opencode/src/agents/designer.ts +0 -124
- package/dist/opencode/src/agents/engineer.ts +0 -105
- package/dist/opencode/src/agents/lead.ts +0 -66
- package/dist/opencode/src/agents/postdoc.ts +0 -121
- package/dist/opencode/src/agents/researcher.ts +0 -136
- package/dist/opencode/src/agents/reviewer.ts +0 -137
- package/dist/opencode/src/agents/strategist.ts +0 -115
- package/dist/opencode/src/agents/tester.ts +0 -194
- package/dist/opencode/src/agents/writer.ts +0 -121
- package/dist/opencode/src/index.ts +0 -25
- package/dist/opencode/src/plugin.ts +0 -6
- package/dist/scripts/build-agents.d.ts +0 -164
- package/dist/scripts/build-agents.d.ts.map +0 -1
- package/dist/scripts/build-agents.js +0 -890
- package/dist/scripts/build-agents.js.map +0 -1
- package/dist/scripts/build-hooks.d.ts +0 -57
- package/dist/scripts/build-hooks.d.ts.map +0 -1
- package/dist/scripts/build-hooks.js +0 -555
- package/dist/scripts/build-hooks.js.map +0 -1
- package/dist/scripts/cli.d.ts +0 -54
- package/dist/scripts/cli.d.ts.map +0 -1
- package/dist/scripts/cli.js +0 -504
- package/dist/scripts/cli.js.map +0 -1
- package/dist/scripts/smoke/smoke-claude.d.ts +0 -2
- package/dist/scripts/smoke/smoke-claude.d.ts.map +0 -1
- package/dist/scripts/smoke/smoke-claude.js +0 -58
- package/dist/scripts/smoke/smoke-claude.js.map +0 -1
- package/dist/scripts/smoke/smoke-codex.d.ts +0 -2
- package/dist/scripts/smoke/smoke-codex.d.ts.map +0 -1
- package/dist/scripts/smoke/smoke-codex.js +0 -50
- package/dist/scripts/smoke/smoke-codex.js.map +0 -1
- package/dist/scripts/smoke/smoke-consumer.d.ts +0 -2
- package/dist/scripts/smoke/smoke-consumer.d.ts.map +0 -1
- package/dist/scripts/smoke/smoke-consumer.js +0 -80
- package/dist/scripts/smoke/smoke-consumer.js.map +0 -1
- package/dist/scripts/smoke/smoke-opencode.d.ts +0 -2
- package/dist/scripts/smoke/smoke-opencode.d.ts.map +0 -1
- package/dist/scripts/smoke/smoke-opencode.js +0 -99
- package/dist/scripts/smoke/smoke-opencode.js.map +0 -1
- package/dist/src/hooks/opencode-mount.d.ts +0 -35
- package/dist/src/hooks/opencode-mount.d.ts.map +0 -1
- package/dist/src/hooks/opencode-mount.js +0 -352
- package/dist/src/hooks/opencode-mount.js.map +0 -1
- package/dist/src/hooks/runtime.d.ts +0 -37
- package/dist/src/hooks/runtime.d.ts.map +0 -1
- package/dist/src/hooks/runtime.js +0 -274
- package/dist/src/hooks/runtime.js.map +0 -1
- package/dist/src/hooks/types.d.ts +0 -196
- package/dist/src/hooks/types.d.ts.map +0 -1
- package/dist/src/hooks/types.js +0 -85
- package/dist/src/hooks/types.js.map +0 -1
- package/dist/src/lsp/cache.d.ts +0 -9
- package/dist/src/lsp/cache.d.ts.map +0 -1
- package/dist/src/lsp/cache.js +0 -216
- package/dist/src/lsp/cache.js.map +0 -1
- package/dist/src/lsp/client.d.ts +0 -24
- package/dist/src/lsp/client.d.ts.map +0 -1
- package/dist/src/lsp/client.js +0 -166
- package/dist/src/lsp/client.js.map +0 -1
- package/dist/src/lsp/detect.d.ts +0 -77
- package/dist/src/lsp/detect.d.ts.map +0 -1
- package/dist/src/lsp/detect.js +0 -116
- package/dist/src/lsp/detect.js.map +0 -1
- package/dist/src/mcp/server.d.ts.map +0 -1
- package/dist/src/mcp/server.js +0 -34
- package/dist/src/mcp/server.js.map +0 -1
- package/dist/src/mcp/tools/artifact.d.ts.map +0 -1
- package/dist/src/mcp/tools/artifact.js +0 -36
- package/dist/src/mcp/tools/artifact.js.map +0 -1
- package/dist/src/mcp/tools/history.d.ts.map +0 -1
- package/dist/src/mcp/tools/history.js +0 -29
- package/dist/src/mcp/tools/history.js.map +0 -1
- package/dist/src/mcp/tools/lsp.d.ts +0 -13
- package/dist/src/mcp/tools/lsp.d.ts.map +0 -1
- package/dist/src/mcp/tools/lsp.js +0 -225
- package/dist/src/mcp/tools/lsp.js.map +0 -1
- package/dist/src/mcp/tools/plan.d.ts.map +0 -1
- package/dist/src/mcp/tools/plan.js +0 -317
- package/dist/src/mcp/tools/plan.js.map +0 -1
- package/dist/src/mcp/tools/task.d.ts.map +0 -1
- package/dist/src/mcp/tools/task.js +0 -252
- package/dist/src/mcp/tools/task.js.map +0 -1
- package/dist/src/shared/invocations.d.ts +0 -74
- package/dist/src/shared/invocations.d.ts.map +0 -1
- package/dist/src/shared/invocations.js +0 -247
- package/dist/src/shared/invocations.js.map +0 -1
- package/dist/src/shared/json-store.d.ts.map +0 -1
- package/dist/src/shared/json-store.js.map +0 -1
- package/dist/src/shared/mcp-utils.d.ts.map +0 -1
- package/dist/src/shared/mcp-utils.js.map +0 -1
- package/dist/src/shared/package-root.d.ts +0 -6
- package/dist/src/shared/package-root.d.ts.map +0 -1
- package/dist/src/shared/package-root.js +0 -19
- package/dist/src/shared/package-root.js.map +0 -1
- package/dist/src/shared/paths.d.ts.map +0 -1
- package/dist/src/shared/paths.js +0 -81
- package/dist/src/shared/paths.js.map +0 -1
- package/dist/src/shared/tool-log.d.ts +0 -8
- package/dist/src/shared/tool-log.d.ts.map +0 -1
- package/dist/src/shared/tool-log.js +0 -22
- package/dist/src/shared/tool-log.js.map +0 -1
- package/dist/src/types/agent-config.d.ts +0 -22
- package/dist/src/types/agent-config.d.ts.map +0 -1
- package/dist/src/types/agent-config.js +0 -2
- package/dist/src/types/agent-config.js.map +0 -1
- package/dist/src/types/index.d.ts +0 -2
- package/dist/src/types/index.d.ts.map +0 -1
- package/dist/src/types/index.js +0 -2
- package/dist/src/types/index.js.map +0 -1
- package/dist/src/types/state.d.ts.map +0 -1
- package/dist/src/types/state.js.map +0 -1
- package/docs/consuming/codex-lead-merge.md +0 -106
- package/docs/contract/harness-io.md +0 -333
- package/docs/plugin-guide.md +0 -355
- package/docs/plugin-template/claude/.github/workflows/build.yml +0 -60
- package/docs/plugin-template/claude/README.md +0 -110
- package/docs/plugin-template/claude/package.json +0 -16
- package/docs/plugin-template/codex/.github/workflows/build.yml +0 -51
- package/docs/plugin-template/codex/README.md +0 -147
- package/docs/plugin-template/codex/install/install.sh +0 -60
- package/docs/plugin-template/codex/package.json +0 -17
- package/docs/plugin-template/opencode/.github/workflows/build.yml +0 -61
- package/docs/plugin-template/opencode/README.md +0 -121
- package/docs/plugin-template/opencode/package.json +0 -25
- package/docs/plugin-template/opencode/src/plugin.ts +0 -6
- /package/dist/{src/mcp/tools → mcp/handlers}/artifact.d.ts +0 -0
- /package/dist/{src/mcp/tools → mcp/handlers}/history.d.ts +0 -0
- /package/dist/{src/mcp/tools → mcp/handlers}/plan.d.ts +0 -0
- /package/dist/{src/mcp/tools → mcp/handlers}/task.d.ts +0 -0
- /package/dist/{src/shared → shared}/json-store.d.ts +0 -0
- /package/dist/{src/shared → shared}/mcp-utils.d.ts +0 -0
- /package/dist/{src/shared → shared}/mcp-utils.js +0 -0
|
@@ -1,313 +0,0 @@
|
|
|
1
|
-
# capability-matrix.yml
|
|
2
|
-
# nexus-core hook system capability matrix
|
|
3
|
-
#
|
|
4
|
-
# This file is the single source of truth for portability_tier auto-derivation
|
|
5
|
-
# in build-hooks.ts. The build script reads this file via js-yaml (or equivalent)
|
|
6
|
-
# and cross-references each hook's requires_capabilities[] against the matrix.
|
|
7
|
-
#
|
|
8
|
-
# Schema:
|
|
9
|
-
# Each top-level key is a dot-notation capability ID.
|
|
10
|
-
# Each entry has three harness keys: claude, codex, opencode.
|
|
11
|
-
# Values: true | false | partial
|
|
12
|
-
# true — fully supported, behavior is defined and verified
|
|
13
|
-
# false — not supported; the build will apply fallback policy (warn|skip|error)
|
|
14
|
-
# as specified in the hook's meta.yml
|
|
15
|
-
# partial — supported only under specific conditions (see per-entry note)
|
|
16
|
-
# note — required when value is partial or false; cites issue/PR where relevant
|
|
17
|
-
#
|
|
18
|
-
# Partial semantics: "operates only under specific matchers, timing conditions,
|
|
19
|
-
# or platform constraints — not universally available within the event."
|
|
20
|
-
#
|
|
21
|
-
# Updated: 2026-04-18
|
|
22
|
-
# Maintained by: nexus-core team
|
|
23
|
-
|
|
24
|
-
capabilities:
|
|
25
|
-
|
|
26
|
-
# ─── Event: session lifecycle ─────────────────────────────────────────────
|
|
27
|
-
|
|
28
|
-
event.session_start:
|
|
29
|
-
claude: true
|
|
30
|
-
codex: true
|
|
31
|
-
opencode: true
|
|
32
|
-
note: >
|
|
33
|
-
Claude: SessionStart hook. Codex: SessionStart hook (experimental flag required —
|
|
34
|
-
see runtime.experimental_flag_required). OpenCode: session.created Bus event
|
|
35
|
-
received via the generic `event` hook key.
|
|
36
|
-
|
|
37
|
-
event.user_prompt_submit:
|
|
38
|
-
claude: true
|
|
39
|
-
codex: true
|
|
40
|
-
opencode: true
|
|
41
|
-
note: >
|
|
42
|
-
Claude: UserPromptSubmit hook. Codex: UserPromptSubmit hook.
|
|
43
|
-
OpenCode: UserPromptSubmit maps to experimental.chat.system.transform
|
|
44
|
-
(fires immediately before each LLM call) or chat.message hook for
|
|
45
|
-
per-message interception.
|
|
46
|
-
|
|
47
|
-
# ─── Event: PreToolUse ────────────────────────────────────────────────────
|
|
48
|
-
|
|
49
|
-
event.pre_tool_use.bash:
|
|
50
|
-
claude: true
|
|
51
|
-
codex: true
|
|
52
|
-
opencode: true
|
|
53
|
-
note: >
|
|
54
|
-
Claude: PreToolUse matcher "Bash". Codex: PreToolUse currently emits only
|
|
55
|
-
for Bash — https://github.com/openai/codex/issues/16732 (open, PR #18391 pending).
|
|
56
|
-
OpenCode: tool.execute.before fires for all built-in tools including bash.
|
|
57
|
-
|
|
58
|
-
event.pre_tool_use.edit:
|
|
59
|
-
claude: true
|
|
60
|
-
codex: false
|
|
61
|
-
opencode: true
|
|
62
|
-
note: >
|
|
63
|
-
Codex: apply_patch does not emit PreToolUse/PostToolUse at this time.
|
|
64
|
-
Fix prepared in PR #18391 (OpenAI employee fcoury-oai, approved by canvrno-oai,
|
|
65
|
-
pending merge) — https://github.com/openai/codex/pull/18391.
|
|
66
|
-
When merged, update codex value to true and add release note to sister projects.
|
|
67
|
-
Claude: PreToolUse matcher "Edit|MultiEdit". OpenCode: tool.execute.before
|
|
68
|
-
fires for edit and apply_patch tools.
|
|
69
|
-
|
|
70
|
-
event.pre_tool_use.mcp:
|
|
71
|
-
claude: true
|
|
72
|
-
codex: false
|
|
73
|
-
opencode: false
|
|
74
|
-
note: >
|
|
75
|
-
MCP tool interception is Claude-only. Codex does not emit PreToolUse for MCP
|
|
76
|
-
tools — https://github.com/openai/codex/issues/16732. OpenCode tool.execute.before
|
|
77
|
-
does not fire for MCP tool calls —
|
|
78
|
-
https://github.com/sst/opencode/issues/2319 (open, unresolved).
|
|
79
|
-
Tier 2 user plugins can add MCP PreToolUse hooks in Claude environments only.
|
|
80
|
-
|
|
81
|
-
# ─── Event: PostToolUse ───────────────────────────────────────────────────
|
|
82
|
-
|
|
83
|
-
event.post_tool_use.bash:
|
|
84
|
-
claude: true
|
|
85
|
-
codex: true
|
|
86
|
-
opencode: true
|
|
87
|
-
note: >
|
|
88
|
-
Claude: PostToolUse matcher "Bash". Codex: PostToolUse emits for Bash
|
|
89
|
-
(verified in direct experiment — codex-cli 0.121.0, macOS).
|
|
90
|
-
OpenCode: tool.execute.after fires for bash tool.
|
|
91
|
-
|
|
92
|
-
event.post_tool_use.read:
|
|
93
|
-
claude: true
|
|
94
|
-
codex: false
|
|
95
|
-
opencode: true
|
|
96
|
-
note: >
|
|
97
|
-
Codex has no independent Read tool; file reads use shell (cat/head/tail).
|
|
98
|
-
The wrapper Bash-parsing layer maps cat|head|tail|less|more to Read as a
|
|
99
|
-
best-effort equivalent (see event.post_tool_use.bash_parsed).
|
|
100
|
-
Direct Read-equivalent PostToolUse is not available natively in Codex.
|
|
101
|
-
OpenCode: tool.execute.after fires for the read tool.
|
|
102
|
-
|
|
103
|
-
event.post_tool_use.edit:
|
|
104
|
-
claude: true
|
|
105
|
-
codex: false
|
|
106
|
-
opencode: true
|
|
107
|
-
note: >
|
|
108
|
-
Codex: apply_patch does not emit PostToolUse — same constraint as
|
|
109
|
-
event.pre_tool_use.edit. PR #18391 addresses this —
|
|
110
|
-
https://github.com/openai/codex/pull/18391.
|
|
111
|
-
Shell-based edits (echo > file, sed -i, heredoc) are partially captured
|
|
112
|
-
via event.post_tool_use.bash_parsed.
|
|
113
|
-
Claude: PostToolUse matcher "Edit|MultiEdit|Write".
|
|
114
|
-
OpenCode: tool.execute.after fires for edit, write, and apply_patch tools.
|
|
115
|
-
|
|
116
|
-
event.post_tool_use.bash_parsed:
|
|
117
|
-
claude: false
|
|
118
|
-
codex: true
|
|
119
|
-
opencode: false
|
|
120
|
-
note: >
|
|
121
|
-
Codex-specific capability: the nexus wrapper parses Bash commands to derive
|
|
122
|
-
equivalent nexus tool_name values. Mapping table (best-effort, complex pipes
|
|
123
|
-
and sudo are not parsed):
|
|
124
|
-
cat|head|tail|less|more <file> -> Read
|
|
125
|
-
ls <path> -> LS
|
|
126
|
-
find <path> -> Glob
|
|
127
|
-
rg|grep <pattern> <path> -> Grep
|
|
128
|
-
echo <text> > <file> -> Write
|
|
129
|
-
echo <text> >> <file> -> Edit
|
|
130
|
-
sed -i <...> <file> -> Edit
|
|
131
|
-
cat > <file> <<EOF (heredoc) -> Write
|
|
132
|
-
tee <file> -> Write
|
|
133
|
-
touch <file> -> Write
|
|
134
|
-
cp <src> <dst> -> Write (dst)
|
|
135
|
-
mv <src> <dst> -> Edit (dst)
|
|
136
|
-
This provides partial PostToolUse coverage for file operations that Codex
|
|
137
|
-
expresses as shell commands. Claude and OpenCode have dedicated first-class
|
|
138
|
-
tools and do not require this shim.
|
|
139
|
-
|
|
140
|
-
# ─── Event: subagent lifecycle ────────────────────────────────────────────
|
|
141
|
-
|
|
142
|
-
event.subagent_start:
|
|
143
|
-
claude: true
|
|
144
|
-
codex: true
|
|
145
|
-
opencode: true
|
|
146
|
-
note: >
|
|
147
|
-
Claude: SubagentStart hook. Codex: SubagentStart hook (thread_spawn jsonl
|
|
148
|
-
payload in transcript — codex-nexus adapter parses spawn_agent call).
|
|
149
|
-
OpenCode: tool.execute.before with input.tool === "task" matcher in mountHooks
|
|
150
|
-
(opencode-nexus verified pattern). agent_id equals subagent session ID and is
|
|
151
|
-
immutable across all three harnesses.
|
|
152
|
-
|
|
153
|
-
event.subagent_stop:
|
|
154
|
-
claude: true
|
|
155
|
-
codex: true
|
|
156
|
-
opencode: true
|
|
157
|
-
note: >
|
|
158
|
-
Claude: SubagentStop hook. Codex: SubagentStop hook (thread_close jsonl payload).
|
|
159
|
-
OpenCode: tool.execute.after with input.tool === "task" matcher in mountHooks.
|
|
160
|
-
agent-finalize uses tool.execute.after output.output append as an approved
|
|
161
|
-
exception (#6 decision — SubagentStop is the sole approved use of
|
|
162
|
-
tool.execute.after context injection in the nexus standard).
|
|
163
|
-
|
|
164
|
-
# ─── Output: additionalContext injection ──────────────────────────────────
|
|
165
|
-
|
|
166
|
-
output.additional_context.session_start:
|
|
167
|
-
claude: true
|
|
168
|
-
codex: true
|
|
169
|
-
opencode: true
|
|
170
|
-
note: >
|
|
171
|
-
Claude: additionalContext field in SessionStart hook output injected as a
|
|
172
|
-
system-reminder block (max 10,000 chars per hook; multiple hooks are merged).
|
|
173
|
-
Codex: additionalContext in SessionStart hookSpecificOutput — verified in
|
|
174
|
-
direct experiment (codex-cli 0.121.0, macOS).
|
|
175
|
-
OpenCode: experimental.chat.system.transform output.system.push at
|
|
176
|
-
session.created time.
|
|
177
|
-
|
|
178
|
-
output.additional_context.user_prompt:
|
|
179
|
-
claude: true
|
|
180
|
-
codex: true
|
|
181
|
-
opencode: true
|
|
182
|
-
note: >
|
|
183
|
-
Claude: additionalContext in UserPromptSubmit hook output.
|
|
184
|
-
Codex: additionalContext field in UserPromptSubmit hook output.
|
|
185
|
-
OpenCode: experimental.chat.system.transform fires before every LLM call;
|
|
186
|
-
this is the primary context injection mechanism for user-prompt-equivalent
|
|
187
|
-
interception. Note: fires on every LLM call, not only on new user messages —
|
|
188
|
-
buffered state must be cleared after one injection to prevent duplication.
|
|
189
|
-
|
|
190
|
-
output.additional_context.subagent_stop:
|
|
191
|
-
claude: true
|
|
192
|
-
codex: true
|
|
193
|
-
opencode: true
|
|
194
|
-
note: >
|
|
195
|
-
Claude: additionalContext in SubagentStop hook output.
|
|
196
|
-
Codex: additionalContext in SubagentStop (thread_close) hook output.
|
|
197
|
-
OpenCode: agent-finalize hook uses tool.execute.after output.output append
|
|
198
|
-
as an approved exception; the nexus wrapper translates this to the
|
|
199
|
-
additional_context semantic for subagent stop notifications.
|
|
200
|
-
|
|
201
|
-
output.additional_context.post_tool:
|
|
202
|
-
claude: true
|
|
203
|
-
codex: true
|
|
204
|
-
opencode: false
|
|
205
|
-
note: >
|
|
206
|
-
OpenCode: tool.execute.after can technically append to output.output and the
|
|
207
|
-
LLM receives the modified tool result (verified in direct experiment 2026-04-18).
|
|
208
|
-
However, all three sister projects (claude-nexus, opencode-nexus, codex-nexus)
|
|
209
|
-
use PostToolUse exclusively for telemetry/state-tracking side effects — not
|
|
210
|
-
context injection. This capability is not adopted in the nexus standard
|
|
211
|
-
(#6 decision — YAGNI). Marked false to prevent accidental use; user plugins
|
|
212
|
-
may use tool.execute.after output.output append as an escape hatch.
|
|
213
|
-
Context for future consideration: see .nexus/memory/external-opencode-hooks-tools.md §13.
|
|
214
|
-
Claude: additionalContext in PostToolUse output.
|
|
215
|
-
Codex: additionalContext in PostToolUse hookSpecificOutput.
|
|
216
|
-
|
|
217
|
-
# ─── Output: decision / control flow ──────────────────────────────────────
|
|
218
|
-
|
|
219
|
-
output.decision_block:
|
|
220
|
-
claude: true
|
|
221
|
-
codex: true
|
|
222
|
-
opencode: true
|
|
223
|
-
note: >
|
|
224
|
-
Claude: decision:"block" in hook stdout JSON (or exit 2 + stderr).
|
|
225
|
-
PostToolUse decision:block blocks the tool result from being fed back to
|
|
226
|
-
the model (the tool itself has already executed).
|
|
227
|
-
Codex: decision:"block" + reason in hook stdout JSON, or exit 2 + stderr;
|
|
228
|
-
both are functionally equivalent. Priority order: continue:false >
|
|
229
|
-
decision:block > exit 2.
|
|
230
|
-
OpenCode: throw new Error(...) in tool.execute.before blocks tool execution;
|
|
231
|
-
mountHooks translates nexus decision:block to throw. PostToolUse block is not
|
|
232
|
-
available in OpenCode (tool.execute.after cannot prevent tool result delivery).
|
|
233
|
-
|
|
234
|
-
output.updated_input.tool:
|
|
235
|
-
claude: true
|
|
236
|
-
codex: false
|
|
237
|
-
opencode: true
|
|
238
|
-
note: >
|
|
239
|
-
Claude: updatedInput field in PreToolUse output completely replaces tool
|
|
240
|
-
arguments (partial updates are not supported — any missing fields are lost).
|
|
241
|
-
Effective only when permissionDecision is "allow" or "ask".
|
|
242
|
-
Codex: updatedInput is parsed but is currently not applied — fail-open (noop).
|
|
243
|
-
The field is silently ignored with no error or warning —
|
|
244
|
-
https://github.com/openai/codex/issues/16732 (related tracking issue).
|
|
245
|
-
OpenCode: output.args mutation in tool.execute.before; mountHooks assigns
|
|
246
|
-
the nexus updatedInput value to output.args (reference is mutated in-place).
|
|
247
|
-
|
|
248
|
-
output.continue_false:
|
|
249
|
-
claude: true
|
|
250
|
-
codex: true
|
|
251
|
-
opencode: true
|
|
252
|
-
note: >
|
|
253
|
-
Claude: continue:false with optional stopReason (displayed to the user,
|
|
254
|
-
not to the model). Globally terminates the current session turn immediately,
|
|
255
|
-
taking precedence over all event-specific decision fields.
|
|
256
|
-
Codex: continue:false is the highest-priority control flow signal —
|
|
257
|
-
overrides decision:block and exit 2. Scope is turn termination (session-level
|
|
258
|
-
termination is unconfirmed per documentation). Supported on
|
|
259
|
-
SessionStart, UserPromptSubmit, PostToolUse, and Stop events.
|
|
260
|
-
OpenCode: mountHooks translates continue:false to throw, which terminates
|
|
261
|
-
tool execution and the current session turn.
|
|
262
|
-
|
|
263
|
-
# ─── Runtime: flags and prerequisites ─────────────────────────────────────
|
|
264
|
-
|
|
265
|
-
runtime.experimental_flag_required:
|
|
266
|
-
claude: false
|
|
267
|
-
codex: true
|
|
268
|
-
opencode: false
|
|
269
|
-
note: >
|
|
270
|
-
Codex requires an opt-in feature flag to activate the hook system.
|
|
271
|
-
~/.codex/config.toml must contain:
|
|
272
|
-
[features]
|
|
273
|
-
codex_hooks = true
|
|
274
|
-
Without this flag, hooks.json is silently ignored (no error, no warning).
|
|
275
|
-
Windows: the entire Codex hook system is currently disabled regardless of
|
|
276
|
-
the flag (documented as a temporary measure by OpenAI).
|
|
277
|
-
Claude and OpenCode activate hook processing without any experimental flag.
|
|
278
|
-
|
|
279
|
-
# ─── Permission hooks ──────────────────────────────────────────────────────
|
|
280
|
-
|
|
281
|
-
event.permission_request:
|
|
282
|
-
claude: true
|
|
283
|
-
codex: partial
|
|
284
|
-
opencode: false
|
|
285
|
-
note: >
|
|
286
|
-
Claude: PermissionRequest hook fires when a permission dialog is triggered;
|
|
287
|
-
output supports permissionDecision allow|deny|ask|defer.
|
|
288
|
-
Codex: permission_request.rs confirmed present in codex-rs/hooks/src/events/
|
|
289
|
-
(discovered 2026-04-18 — external-codex-hooks-tools.md §12). This makes Codex
|
|
290
|
-
hooks 6 events, not 5. stdin/stdout semantics and matcher behavior are
|
|
291
|
-
unverified; marked partial pending investigation.
|
|
292
|
-
OpenCode: permission.ask hook exists but is not firing due to a missing
|
|
293
|
-
Plugin.trigger call in PermissionNext.ask() —
|
|
294
|
-
https://github.com/sst/opencode/issues/7006 (open).
|
|
295
|
-
PR #19453 (anomalyco fork) proposes a fix but is not merged into sst/opencode
|
|
296
|
-
main. PermissionRequest is outside the portable standard until #7006 is resolved.
|
|
297
|
-
|
|
298
|
-
# ─── Context injection: PreToolUse ────────────────────────────────────────
|
|
299
|
-
|
|
300
|
-
output.additional_context.pre_tool:
|
|
301
|
-
claude: true
|
|
302
|
-
codex: partial
|
|
303
|
-
opencode: true
|
|
304
|
-
note: >
|
|
305
|
-
Claude: additionalContext in PreToolUse output is injected as a system-reminder
|
|
306
|
-
before tool execution (when permissionDecision is not "defer").
|
|
307
|
-
Codex: additionalContext in PreToolUse output is parsed but the field is
|
|
308
|
-
currently not implemented — fail-open (noop). Marked partial because the field
|
|
309
|
-
is accepted without error but has no observable effect on the model.
|
|
310
|
-
See external-codex-hooks-tools.md §10-2.
|
|
311
|
-
OpenCode: tool.execute.before can prepend context to output.args for
|
|
312
|
-
prompt-bearing tools (such as task/subagent), or buffer context for delivery
|
|
313
|
-
via experimental.chat.system.transform on the subsequent LLM call.
|
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from "bun:test";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import fsPromises from "node:fs/promises";
|
|
4
|
-
import os from "node:os";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import handler from "./handler.ts";
|
|
7
|
-
import type { NexusHookInput } from "../../../src/hooks/types.ts";
|
|
8
|
-
|
|
9
|
-
// ---------------------------------------------------------------------------
|
|
10
|
-
// Fixture helpers
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
|
-
|
|
13
|
-
let tmpDir: string;
|
|
14
|
-
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "nexus-post-tool-"));
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
afterEach(async () => {
|
|
20
|
-
await fsPromises.rm(tmpDir, { recursive: true, force: true });
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
/** Build a minimal PostToolUse input */
|
|
24
|
-
function makeInput(
|
|
25
|
-
overrides: Partial<Extract<NexusHookInput, { hook_event_name: "PostToolUse" }>> & {
|
|
26
|
-
tool_input?: Record<string, unknown>;
|
|
27
|
-
},
|
|
28
|
-
): NexusHookInput {
|
|
29
|
-
return {
|
|
30
|
-
hook_event_name: "PostToolUse",
|
|
31
|
-
session_id: "sid-test",
|
|
32
|
-
cwd: tmpDir,
|
|
33
|
-
tool_name: "Edit",
|
|
34
|
-
agent_id: "agent-engineer",
|
|
35
|
-
...overrides,
|
|
36
|
-
} as NexusHookInput;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function toolLogPath(sessionId = "sid-test"): string {
|
|
40
|
-
return path.join(tmpDir, ".nexus/state", sessionId, "tool-log.jsonl");
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function memAccessPath(): string {
|
|
44
|
-
return path.join(tmpDir, ".nexus/memory-access.jsonl");
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function readJsonLines(filePath: string): unknown[] {
|
|
48
|
-
const raw = fs.readFileSync(filePath, "utf8");
|
|
49
|
-
return raw
|
|
50
|
-
.trimEnd()
|
|
51
|
-
.split("\n")
|
|
52
|
-
.filter((l) => l.trim() !== "")
|
|
53
|
-
.map((l) => JSON.parse(l));
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// ---------------------------------------------------------------------------
|
|
57
|
-
// Scenario 1 — Edit + agent_id present → tool-log.jsonl 1-line append
|
|
58
|
-
// ---------------------------------------------------------------------------
|
|
59
|
-
|
|
60
|
-
describe("scenario 1: Edit + agent_id → tool-log append", () => {
|
|
61
|
-
it("appends one record to .nexus/state/sessions/<sid>/tool-log.jsonl", async () => {
|
|
62
|
-
const input = makeInput({
|
|
63
|
-
tool_name: "Edit",
|
|
64
|
-
agent_id: "agent-engineer",
|
|
65
|
-
tool_input: { file_path: path.join(tmpDir, "src/foo.ts") },
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
const result = await handler(input);
|
|
69
|
-
|
|
70
|
-
// No additional_context or block returned
|
|
71
|
-
expect(result).toBeUndefined();
|
|
72
|
-
|
|
73
|
-
const logFile = toolLogPath();
|
|
74
|
-
expect(fs.existsSync(logFile)).toBe(true);
|
|
75
|
-
|
|
76
|
-
const lines = readJsonLines(logFile);
|
|
77
|
-
expect(lines).toHaveLength(1);
|
|
78
|
-
|
|
79
|
-
const entry = lines[0] as Record<string, unknown>;
|
|
80
|
-
expect(entry.agent_id).toBe("agent-engineer");
|
|
81
|
-
expect(entry.tool).toBe("Edit");
|
|
82
|
-
expect(entry.file).toBe("src/foo.ts");
|
|
83
|
-
expect(entry.status).toBe("ok");
|
|
84
|
-
expect(typeof entry.ts).toBe("string");
|
|
85
|
-
expect(() => new Date(entry.ts as string)).not.toThrow();
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
// ---------------------------------------------------------------------------
|
|
90
|
-
// Scenario 2 — Read + file_path within .nexus/memory/** → memory-access.jsonl append
|
|
91
|
-
// ---------------------------------------------------------------------------
|
|
92
|
-
|
|
93
|
-
describe("scenario 2: Read + memory path → memory-access.jsonl append", () => {
|
|
94
|
-
it("appends one record to .nexus/memory-access.jsonl", async () => {
|
|
95
|
-
const memFile = path.join(tmpDir, ".nexus/memory/lessons.md");
|
|
96
|
-
// File does not need to exist; only the path matters for the hook
|
|
97
|
-
|
|
98
|
-
const input = makeInput({
|
|
99
|
-
tool_name: "Read",
|
|
100
|
-
agent_id: "agent-researcher",
|
|
101
|
-
tool_input: { file_path: memFile },
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
await handler(input);
|
|
105
|
-
|
|
106
|
-
const accFile = memAccessPath();
|
|
107
|
-
expect(fs.existsSync(accFile)).toBe(true);
|
|
108
|
-
|
|
109
|
-
const lines = readJsonLines(accFile);
|
|
110
|
-
expect(lines).toHaveLength(1);
|
|
111
|
-
|
|
112
|
-
const entry = lines[0] as Record<string, unknown>;
|
|
113
|
-
expect(entry.path).toBe(".nexus/memory/lessons.md");
|
|
114
|
-
expect(entry.agent).toBe("agent-researcher");
|
|
115
|
-
expect(typeof entry.accessed_at).toBe("string");
|
|
116
|
-
expect(() => new Date(entry.accessed_at as string)).not.toThrow();
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
// ---------------------------------------------------------------------------
|
|
121
|
-
// Scenario 3 — Read + other path (src/foo.ts) → memory-access.jsonl NOT written
|
|
122
|
-
// ---------------------------------------------------------------------------
|
|
123
|
-
|
|
124
|
-
describe("scenario 3: Read + non-memory path → memory-access skip", () => {
|
|
125
|
-
it("does not create memory-access.jsonl for a non-memory file path", async () => {
|
|
126
|
-
const input = makeInput({
|
|
127
|
-
tool_name: "Read",
|
|
128
|
-
agent_id: "agent-engineer",
|
|
129
|
-
tool_input: { file_path: path.join(tmpDir, "src/foo.ts") },
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
await handler(input);
|
|
133
|
-
|
|
134
|
-
expect(fs.existsSync(memAccessPath())).toBe(false);
|
|
135
|
-
// tool-log is also not written because tool is Read (not an edit tool)
|
|
136
|
-
expect(fs.existsSync(toolLogPath())).toBe(false);
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// ---------------------------------------------------------------------------
|
|
141
|
-
// Scenario 4 — Lead (agent_id = null) + Edit → tool-log skip
|
|
142
|
-
// ---------------------------------------------------------------------------
|
|
143
|
-
|
|
144
|
-
describe("scenario 4: Lead (agent_id null) + Edit → tool-log skip", () => {
|
|
145
|
-
it("does not write tool-log.jsonl when agent_id is null", async () => {
|
|
146
|
-
const input = makeInput({
|
|
147
|
-
tool_name: "Edit",
|
|
148
|
-
agent_id: null,
|
|
149
|
-
tool_input: { file_path: path.join(tmpDir, "src/bar.ts") },
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
await handler(input);
|
|
153
|
-
|
|
154
|
-
expect(fs.existsSync(toolLogPath())).toBe(false);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it("does not write tool-log.jsonl when agent_id is undefined", async () => {
|
|
158
|
-
const input: NexusHookInput = {
|
|
159
|
-
hook_event_name: "PostToolUse",
|
|
160
|
-
session_id: "sid-test",
|
|
161
|
-
cwd: tmpDir,
|
|
162
|
-
tool_name: "Edit",
|
|
163
|
-
// agent_id intentionally omitted
|
|
164
|
-
tool_input: { file_path: path.join(tmpDir, "src/bar.ts") },
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
await handler(input);
|
|
168
|
-
|
|
169
|
-
expect(fs.existsSync(toolLogPath())).toBe(false);
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
// ---------------------------------------------------------------------------
|
|
174
|
-
// Scenario 5 — NotebookEdit + notebook_path (no file_path) → tool-log uses notebook_path
|
|
175
|
-
// ---------------------------------------------------------------------------
|
|
176
|
-
|
|
177
|
-
describe("scenario 5: NotebookEdit + notebook_path → tool-log with notebook_path", () => {
|
|
178
|
-
it("uses notebook_path when file_path is absent", async () => {
|
|
179
|
-
const nbPath = path.join(tmpDir, "notebooks/analysis.ipynb");
|
|
180
|
-
|
|
181
|
-
const input = makeInput({
|
|
182
|
-
tool_name: "NotebookEdit",
|
|
183
|
-
agent_id: "agent-engineer",
|
|
184
|
-
tool_input: { notebook_path: nbPath },
|
|
185
|
-
// no file_path key
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
await handler(input);
|
|
189
|
-
|
|
190
|
-
const logFile = toolLogPath();
|
|
191
|
-
expect(fs.existsSync(logFile)).toBe(true);
|
|
192
|
-
|
|
193
|
-
const lines = readJsonLines(logFile);
|
|
194
|
-
expect(lines).toHaveLength(1);
|
|
195
|
-
|
|
196
|
-
const entry = lines[0] as Record<string, unknown>;
|
|
197
|
-
expect(entry.tool).toBe("NotebookEdit");
|
|
198
|
-
expect(entry.file).toBe("notebooks/analysis.ipynb");
|
|
199
|
-
expect(entry.agent_id).toBe("agent-engineer");
|
|
200
|
-
expect(entry.status).toBe("ok");
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
it("prefers file_path over notebook_path when both are present", async () => {
|
|
204
|
-
const input = makeInput({
|
|
205
|
-
tool_name: "NotebookEdit",
|
|
206
|
-
agent_id: "agent-engineer",
|
|
207
|
-
tool_input: {
|
|
208
|
-
file_path: path.join(tmpDir, "src/primary.ipynb"),
|
|
209
|
-
notebook_path: path.join(tmpDir, "notebooks/secondary.ipynb"),
|
|
210
|
-
},
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
await handler(input);
|
|
214
|
-
|
|
215
|
-
const lines = readJsonLines(toolLogPath());
|
|
216
|
-
const entry = lines[0] as Record<string, unknown>;
|
|
217
|
-
// file_path is ?? first, so it wins
|
|
218
|
-
expect(entry.file).toBe("src/primary.ipynb");
|
|
219
|
-
});
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
// ---------------------------------------------------------------------------
|
|
223
|
-
// Scenario 6 — 100 parallel appendJsonLine → jsonl integrity
|
|
224
|
-
// ---------------------------------------------------------------------------
|
|
225
|
-
|
|
226
|
-
describe("scenario 6: 100 parallel handler calls → jsonl integrity", () => {
|
|
227
|
-
it("all 100 lines are valid JSON and each has expected shape", async () => {
|
|
228
|
-
const inputs = Array.from({ length: 100 }, (_, i) =>
|
|
229
|
-
makeInput({
|
|
230
|
-
tool_name: "Edit",
|
|
231
|
-
agent_id: `agent-${i}`,
|
|
232
|
-
session_id: "sid-parallel",
|
|
233
|
-
tool_input: { file_path: path.join(tmpDir, `src/file-${i}.ts`) },
|
|
234
|
-
}),
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
await Promise.all(inputs.map((inp) => handler(inp)));
|
|
238
|
-
|
|
239
|
-
const logFile = toolLogPath("sid-parallel");
|
|
240
|
-
expect(fs.existsSync(logFile)).toBe(true);
|
|
241
|
-
|
|
242
|
-
const raw = fs.readFileSync(logFile, "utf8");
|
|
243
|
-
const lines = raw
|
|
244
|
-
.trimEnd()
|
|
245
|
-
.split("\n")
|
|
246
|
-
.filter((l) => l.trim() !== "");
|
|
247
|
-
|
|
248
|
-
expect(lines).toHaveLength(100);
|
|
249
|
-
|
|
250
|
-
for (const line of lines) {
|
|
251
|
-
let parsed: unknown;
|
|
252
|
-
expect(() => {
|
|
253
|
-
parsed = JSON.parse(line);
|
|
254
|
-
}).not.toThrow();
|
|
255
|
-
|
|
256
|
-
const entry = parsed as Record<string, unknown>;
|
|
257
|
-
expect(typeof entry.ts).toBe("string");
|
|
258
|
-
expect(typeof entry.agent_id).toBe("string");
|
|
259
|
-
expect(entry.tool).toBe("Edit");
|
|
260
|
-
expect(typeof entry.file).toBe("string");
|
|
261
|
-
expect(entry.status).toBe("ok");
|
|
262
|
-
}
|
|
263
|
-
}, 15_000);
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
// ---------------------------------------------------------------------------
|
|
267
|
-
// Scenario 7 — handler returns no additional_context and no block
|
|
268
|
-
// ---------------------------------------------------------------------------
|
|
269
|
-
|
|
270
|
-
describe("scenario 7: handler returns no additional_context / block", () => {
|
|
271
|
-
it("returns undefined for Edit + agent_id call", async () => {
|
|
272
|
-
const result = await handler(
|
|
273
|
-
makeInput({
|
|
274
|
-
tool_name: "Edit",
|
|
275
|
-
agent_id: "agent-engineer",
|
|
276
|
-
tool_input: { file_path: path.join(tmpDir, "src/x.ts") },
|
|
277
|
-
}),
|
|
278
|
-
);
|
|
279
|
-
expect(result).toBeUndefined();
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
it("returns undefined for Read + memory path call", async () => {
|
|
283
|
-
const result = await handler(
|
|
284
|
-
makeInput({
|
|
285
|
-
tool_name: "Read",
|
|
286
|
-
agent_id: "agent-researcher",
|
|
287
|
-
tool_input: { file_path: path.join(tmpDir, ".nexus/memory/ref.md") },
|
|
288
|
-
}),
|
|
289
|
-
);
|
|
290
|
-
expect(result).toBeUndefined();
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
it("returns undefined for non-PostToolUse event (early return)", async () => {
|
|
294
|
-
const input: NexusHookInput = {
|
|
295
|
-
hook_event_name: "SessionStart",
|
|
296
|
-
session_id: "sid-test",
|
|
297
|
-
cwd: tmpDir,
|
|
298
|
-
};
|
|
299
|
-
const result = await handler(input);
|
|
300
|
-
expect(result).toBeUndefined();
|
|
301
|
-
});
|
|
302
|
-
});
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import type { HookHandler } from "../../../src/hooks/types.js";
|
|
2
|
-
import { appendJsonLine } from "../../../src/shared/json-store.js";
|
|
3
|
-
import { join, resolve, relative } from "node:path";
|
|
4
|
-
|
|
5
|
-
const EDIT_TOOLS = new Set(["Edit", "Write", "MultiEdit", "ApplyPatch", "NotebookEdit"]);
|
|
6
|
-
|
|
7
|
-
function isWithinMemory(filePath: string, projectRoot: string): boolean {
|
|
8
|
-
const memRoot = resolve(projectRoot, ".nexus/memory");
|
|
9
|
-
const abs = resolve(filePath);
|
|
10
|
-
return abs.startsWith(memRoot + "/") || abs === memRoot;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const handler: HookHandler = async (input) => {
|
|
14
|
-
if (input.hook_event_name !== "PostToolUse") return;
|
|
15
|
-
|
|
16
|
-
const { cwd, session_id, tool_name, agent_id } = input;
|
|
17
|
-
const toolInput = (input.tool_input ?? {}) as Record<string, unknown>;
|
|
18
|
-
|
|
19
|
-
// 1. Memory access tracking (Read)
|
|
20
|
-
if (tool_name === "Read") {
|
|
21
|
-
const filePath = toolInput.file_path as string | undefined;
|
|
22
|
-
if (filePath && isWithinMemory(filePath, cwd)) {
|
|
23
|
-
appendJsonLine(join(cwd, ".nexus/memory-access.jsonl"), {
|
|
24
|
-
path: relative(cwd, resolve(filePath)),
|
|
25
|
-
accessed_at: new Date().toISOString(),
|
|
26
|
-
agent: agent_id ?? null,
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// 2. Tool-log append (edit tools + agent_id present)
|
|
32
|
-
if (EDIT_TOOLS.has(tool_name) && agent_id) {
|
|
33
|
-
const filePath = (toolInput.file_path ?? toolInput.notebook_path) as string | undefined;
|
|
34
|
-
if (filePath) {
|
|
35
|
-
appendJsonLine(
|
|
36
|
-
join(cwd, ".nexus/state", session_id, "tool-log.jsonl"),
|
|
37
|
-
{
|
|
38
|
-
ts: new Date().toISOString(),
|
|
39
|
-
agent_id,
|
|
40
|
-
tool: tool_name,
|
|
41
|
-
file: relative(cwd, resolve(filePath)),
|
|
42
|
-
status: "ok",
|
|
43
|
-
},
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export default handler;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
name: post-tool-telemetry
|
|
2
|
-
description: Track memory access and file-edit operations for strength/forgetting signals and audit
|
|
3
|
-
events: [PostToolUse]
|
|
4
|
-
matcher: "Read|Edit|Write|MultiEdit|ApplyPatch|NotebookEdit|Bash"
|
|
5
|
-
timeout: 5
|
|
6
|
-
fallback: warn
|
|
7
|
-
priority: 10
|
|
8
|
-
requires_capabilities:
|
|
9
|
-
- event.post_tool_use.read
|
|
10
|
-
- event.post_tool_use.edit
|
|
11
|
-
- event.post_tool_use.bash_parsed
|