@moreih29/nexus-core 0.13.0 → 0.14.0

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 (158) hide show
  1. package/README.md +34 -0
  2. package/dist/assets/hooks/agent-bootstrap/handler.d.ts +4 -0
  3. package/dist/assets/hooks/agent-bootstrap/handler.d.ts.map +1 -0
  4. package/dist/assets/hooks/agent-bootstrap/handler.js +100 -0
  5. package/dist/assets/hooks/agent-bootstrap/handler.js.map +1 -0
  6. package/dist/assets/hooks/agent-finalize/handler.d.ts +4 -0
  7. package/dist/assets/hooks/agent-finalize/handler.d.ts.map +1 -0
  8. package/dist/assets/hooks/agent-finalize/handler.js +63 -0
  9. package/dist/assets/hooks/agent-finalize/handler.js.map +1 -0
  10. package/dist/assets/hooks/post-tool-telemetry/handler.d.ts +4 -0
  11. package/dist/assets/hooks/post-tool-telemetry/handler.d.ts.map +1 -0
  12. package/dist/assets/hooks/post-tool-telemetry/handler.js +40 -0
  13. package/dist/assets/hooks/post-tool-telemetry/handler.js.map +1 -0
  14. package/dist/assets/hooks/prompt-router/handler.d.ts +4 -0
  15. package/dist/assets/hooks/prompt-router/handler.d.ts.map +1 -0
  16. package/dist/assets/hooks/prompt-router/handler.js +204 -0
  17. package/dist/assets/hooks/prompt-router/handler.js.map +1 -0
  18. package/dist/assets/hooks/session-init/handler.d.ts +4 -0
  19. package/dist/assets/hooks/session-init/handler.d.ts.map +1 -0
  20. package/dist/assets/hooks/session-init/handler.js +23 -0
  21. package/dist/assets/hooks/session-init/handler.js.map +1 -0
  22. package/dist/hooks/agent-bootstrap.js +105 -0
  23. package/dist/hooks/agent-finalize.js +164 -0
  24. package/dist/hooks/post-tool-telemetry.js +55 -0
  25. package/dist/hooks/prompt-router.js +7300 -0
  26. package/dist/hooks/session-init.js +21 -0
  27. package/dist/manifests/claude-hooks.json +52 -0
  28. package/dist/manifests/codex-hooks.json +28 -0
  29. package/dist/manifests/opencode-manifest.json +44 -0
  30. package/dist/manifests/portability-report.json +87 -0
  31. package/dist/scripts/build-agents.d.ts +157 -0
  32. package/dist/scripts/build-agents.d.ts.map +1 -0
  33. package/dist/scripts/build-agents.js +737 -0
  34. package/dist/scripts/build-agents.js.map +1 -0
  35. package/dist/scripts/build-hooks.d.ts +16 -0
  36. package/dist/scripts/build-hooks.d.ts.map +1 -0
  37. package/dist/scripts/build-hooks.js +388 -0
  38. package/dist/scripts/build-hooks.js.map +1 -0
  39. package/dist/scripts/cli.d.ts +54 -0
  40. package/dist/scripts/cli.d.ts.map +1 -0
  41. package/dist/scripts/cli.js +467 -0
  42. package/dist/scripts/cli.js.map +1 -0
  43. package/dist/src/hooks/opencode-mount.d.ts.map +1 -0
  44. package/dist/{hooks → src/hooks}/opencode-mount.js +26 -6
  45. package/dist/src/hooks/opencode-mount.js.map +1 -0
  46. package/dist/src/hooks/runtime.d.ts.map +1 -0
  47. package/dist/src/hooks/runtime.js.map +1 -0
  48. package/dist/src/hooks/types.d.ts.map +1 -0
  49. package/dist/src/hooks/types.js.map +1 -0
  50. package/dist/src/lsp/cache.d.ts.map +1 -0
  51. package/dist/src/lsp/cache.js.map +1 -0
  52. package/dist/src/lsp/client.d.ts.map +1 -0
  53. package/dist/src/lsp/client.js.map +1 -0
  54. package/dist/src/lsp/detect.d.ts.map +1 -0
  55. package/dist/src/lsp/detect.js.map +1 -0
  56. package/dist/src/mcp/server.d.ts.map +1 -0
  57. package/dist/src/mcp/server.js.map +1 -0
  58. package/dist/src/mcp/tools/artifact.d.ts.map +1 -0
  59. package/dist/src/mcp/tools/artifact.js.map +1 -0
  60. package/dist/src/mcp/tools/history.d.ts.map +1 -0
  61. package/dist/src/mcp/tools/history.js.map +1 -0
  62. package/dist/src/mcp/tools/lsp.d.ts.map +1 -0
  63. package/dist/src/mcp/tools/lsp.js.map +1 -0
  64. package/dist/src/mcp/tools/plan.d.ts.map +1 -0
  65. package/dist/src/mcp/tools/plan.js.map +1 -0
  66. package/dist/src/mcp/tools/task.d.ts.map +1 -0
  67. package/dist/src/mcp/tools/task.js.map +1 -0
  68. package/dist/src/shared/invocations.d.ts.map +1 -0
  69. package/dist/src/shared/invocations.js.map +1 -0
  70. package/dist/src/shared/json-store.d.ts.map +1 -0
  71. package/dist/src/shared/json-store.js.map +1 -0
  72. package/dist/src/shared/mcp-utils.d.ts.map +1 -0
  73. package/dist/src/shared/mcp-utils.js.map +1 -0
  74. package/dist/src/shared/paths.d.ts.map +1 -0
  75. package/dist/src/shared/paths.js.map +1 -0
  76. package/dist/src/shared/tool-log.d.ts.map +1 -0
  77. package/dist/src/shared/tool-log.js.map +1 -0
  78. package/dist/src/types/state.d.ts.map +1 -0
  79. package/dist/src/types/state.js.map +1 -0
  80. package/docs/plugin-guide.md +36 -0
  81. package/package.json +25 -17
  82. package/dist/hooks/opencode-mount.d.ts.map +0 -1
  83. package/dist/hooks/opencode-mount.js.map +0 -1
  84. package/dist/hooks/runtime.d.ts.map +0 -1
  85. package/dist/hooks/runtime.js.map +0 -1
  86. package/dist/hooks/types.d.ts.map +0 -1
  87. package/dist/hooks/types.js.map +0 -1
  88. package/dist/lsp/cache.d.ts.map +0 -1
  89. package/dist/lsp/cache.js.map +0 -1
  90. package/dist/lsp/client.d.ts.map +0 -1
  91. package/dist/lsp/client.js.map +0 -1
  92. package/dist/lsp/detect.d.ts.map +0 -1
  93. package/dist/lsp/detect.js.map +0 -1
  94. package/dist/mcp/server.d.ts.map +0 -1
  95. package/dist/mcp/server.js.map +0 -1
  96. package/dist/mcp/tools/artifact.d.ts.map +0 -1
  97. package/dist/mcp/tools/artifact.js.map +0 -1
  98. package/dist/mcp/tools/history.d.ts.map +0 -1
  99. package/dist/mcp/tools/history.js.map +0 -1
  100. package/dist/mcp/tools/lsp.d.ts.map +0 -1
  101. package/dist/mcp/tools/lsp.js.map +0 -1
  102. package/dist/mcp/tools/plan.d.ts.map +0 -1
  103. package/dist/mcp/tools/plan.js.map +0 -1
  104. package/dist/mcp/tools/task.d.ts.map +0 -1
  105. package/dist/mcp/tools/task.js.map +0 -1
  106. package/dist/shared/invocations.d.ts.map +0 -1
  107. package/dist/shared/invocations.js.map +0 -1
  108. package/dist/shared/json-store.d.ts.map +0 -1
  109. package/dist/shared/json-store.js.map +0 -1
  110. package/dist/shared/mcp-utils.d.ts.map +0 -1
  111. package/dist/shared/mcp-utils.js.map +0 -1
  112. package/dist/shared/paths.d.ts.map +0 -1
  113. package/dist/shared/paths.js.map +0 -1
  114. package/dist/shared/tool-log.d.ts.map +0 -1
  115. package/dist/shared/tool-log.js.map +0 -1
  116. package/dist/types/state.d.ts.map +0 -1
  117. package/dist/types/state.js.map +0 -1
  118. package/scripts/build-agents.test.ts +0 -1279
  119. package/scripts/build-agents.ts +0 -978
  120. package/scripts/build-hooks.test.ts +0 -1385
  121. package/scripts/build-hooks.ts +0 -584
  122. package/scripts/cli.test.ts +0 -367
  123. package/scripts/cli.ts +0 -547
  124. /package/dist/{hooks → src/hooks}/opencode-mount.d.ts +0 -0
  125. /package/dist/{hooks → src/hooks}/runtime.d.ts +0 -0
  126. /package/dist/{hooks → src/hooks}/runtime.js +0 -0
  127. /package/dist/{hooks → src/hooks}/types.d.ts +0 -0
  128. /package/dist/{hooks → src/hooks}/types.js +0 -0
  129. /package/dist/{lsp → src/lsp}/cache.d.ts +0 -0
  130. /package/dist/{lsp → src/lsp}/cache.js +0 -0
  131. /package/dist/{lsp → src/lsp}/client.d.ts +0 -0
  132. /package/dist/{lsp → src/lsp}/client.js +0 -0
  133. /package/dist/{lsp → src/lsp}/detect.d.ts +0 -0
  134. /package/dist/{lsp → src/lsp}/detect.js +0 -0
  135. /package/dist/{mcp → src/mcp}/server.d.ts +0 -0
  136. /package/dist/{mcp → src/mcp}/server.js +0 -0
  137. /package/dist/{mcp → src/mcp}/tools/artifact.d.ts +0 -0
  138. /package/dist/{mcp → src/mcp}/tools/artifact.js +0 -0
  139. /package/dist/{mcp → src/mcp}/tools/history.d.ts +0 -0
  140. /package/dist/{mcp → src/mcp}/tools/history.js +0 -0
  141. /package/dist/{mcp → src/mcp}/tools/lsp.d.ts +0 -0
  142. /package/dist/{mcp → src/mcp}/tools/lsp.js +0 -0
  143. /package/dist/{mcp → src/mcp}/tools/plan.d.ts +0 -0
  144. /package/dist/{mcp → src/mcp}/tools/plan.js +0 -0
  145. /package/dist/{mcp → src/mcp}/tools/task.d.ts +0 -0
  146. /package/dist/{mcp → src/mcp}/tools/task.js +0 -0
  147. /package/dist/{shared → src/shared}/invocations.d.ts +0 -0
  148. /package/dist/{shared → src/shared}/invocations.js +0 -0
  149. /package/dist/{shared → src/shared}/json-store.d.ts +0 -0
  150. /package/dist/{shared → src/shared}/json-store.js +0 -0
  151. /package/dist/{shared → src/shared}/mcp-utils.d.ts +0 -0
  152. /package/dist/{shared → src/shared}/mcp-utils.js +0 -0
  153. /package/dist/{shared → src/shared}/paths.d.ts +0 -0
  154. /package/dist/{shared → src/shared}/paths.js +0 -0
  155. /package/dist/{shared → src/shared}/tool-log.d.ts +0 -0
  156. /package/dist/{shared → src/shared}/tool-log.js +0 -0
  157. /package/dist/{types → src/types}/state.d.ts +0 -0
  158. /package/dist/{types → src/types}/state.js +0 -0
package/README.md CHANGED
@@ -18,7 +18,10 @@
18
18
 
19
19
  ## Installation
20
20
 
21
+ **요구사항: Node.js 22 이상** (`import ... with { type: "json" }` 구문이 Node 22에서 stable입니다.)
22
+
21
23
  ```bash
24
+ node --version # v22.0.0 이상 확인
22
25
  bun add -D @moreih29/nexus-core
23
26
  ```
24
27
 
@@ -63,6 +66,37 @@ git add . && git commit -m "Initial plugin scaffold"
63
66
 
64
67
  ---
65
68
 
69
+ ## Consumer 통합 가이드
70
+
71
+ ### 서브패스 경유 정책
72
+
73
+ `@moreih29/nexus-core`의 bare import(`import "@moreih29/nexus-core"`)는 의도적으로 비활성화되어 있습니다 (`"."` export = `null`). 모든 기능은 서브패스를 통해 접근해야 합니다.
74
+
75
+ | 서브패스 | 노출 내용 |
76
+ |---|---|
77
+ | `@moreih29/nexus-core/hooks/opencode-mount` | `mountHooks` 함수 |
78
+ | `@moreih29/nexus-core/hooks/runtime` | 런타임 유틸리티 |
79
+ | `@moreih29/nexus-core/hooks/opencode-manifest` | OpenCode hook JSON manifest |
80
+
81
+ ### OpenCode 플러그인 thin-wrapper 예제
82
+
83
+ OpenCode 플러그인을 구축하는 가장 간단한 패턴은 다음과 같습니다.
84
+
85
+ ```typescript
86
+ import type { Plugin } from "@opencode-ai/plugin";
87
+ import { mountHooks } from "@moreih29/nexus-core/hooks/opencode-mount";
88
+ import manifest from "@moreih29/nexus-core/hooks/opencode-manifest" with { type: "json" };
89
+
90
+ export const OpencodeNexus: Plugin = async (ctx) => mountHooks(ctx, manifest);
91
+ ```
92
+
93
+ - `manifest`는 `./hooks/opencode-manifest` 서브패스를 통해 JSON으로 임포트합니다. Node 22의 `import ... with { type: "json" }` 구문이 필요합니다.
94
+ - `mountHooks(ctx, manifest)`는 manifest에 정의된 훅을 OpenCode context에 등록합니다.
95
+
96
+ 전체 하네스별 통합 절차는 [`docs/plugin-guide.md`](./docs/plugin-guide.md)를 참조하세요.
97
+
98
+ ---
99
+
66
100
  ## Consumer 하네스
67
101
 
68
102
  | 하네스 | 플러그인 repo |
@@ -0,0 +1,4 @@
1
+ import type { HookHandler } from "../../../src/hooks/types.js";
2
+ declare const handler: HookHandler;
3
+ export default handler;
4
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../assets/hooks/agent-bootstrap/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAoF/D,QAAA,MAAM,OAAO,EAAE,WAgCd,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,100 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ const CORE_INDEX_SIZE_LIMIT = 2 * 1024; // 2KB
4
+ function loadValidRoles(cwd) {
5
+ const agentsDir = join(cwd, "assets/agents");
6
+ const roles = [];
7
+ if (existsSync(agentsDir)) {
8
+ for (const entry of readdirSync(agentsDir, { withFileTypes: true })) {
9
+ if (entry.isDirectory())
10
+ roles.push(entry.name);
11
+ }
12
+ }
13
+ return roles;
14
+ }
15
+ function readFirstLine(path) {
16
+ try {
17
+ const content = readFileSync(path, "utf-8");
18
+ const firstNonEmpty = content.split("\n").find((l) => l.trim().length > 0) ?? "";
19
+ return firstNonEmpty.replace(/^#+\s*/, "").slice(0, 80);
20
+ }
21
+ catch {
22
+ return "";
23
+ }
24
+ }
25
+ function buildCoreIndex(cwd) {
26
+ const entries = [];
27
+ for (const sub of [".nexus/memory", ".nexus/context"]) {
28
+ const absDir = join(cwd, sub);
29
+ if (!existsSync(absDir))
30
+ continue;
31
+ for (const f of readdirSync(absDir, { withFileTypes: true })) {
32
+ if (!f.isFile() || !f.name.endsWith(".md"))
33
+ continue;
34
+ const full = join(absDir, f.name);
35
+ entries.push({
36
+ path: `${sub}/${f.name}`,
37
+ mtime: statSync(full).mtimeMs,
38
+ line: readFirstLine(full),
39
+ });
40
+ }
41
+ }
42
+ entries.sort((a, b) => b.mtime - a.mtime);
43
+ const lines = [];
44
+ let bytes = 0;
45
+ for (const e of entries) {
46
+ const formatted = `- ${e.path}: ${e.line}`;
47
+ if (bytes + formatted.length + 1 > CORE_INDEX_SIZE_LIMIT)
48
+ break;
49
+ lines.push(formatted);
50
+ bytes += formatted.length + 1;
51
+ }
52
+ return lines.length > 0
53
+ ? "Available memory/context:\n" + lines.join("\n")
54
+ : "";
55
+ }
56
+ function getResumeCount(cwd, sessionId, agentId) {
57
+ const trackerPath = join(cwd, ".nexus/state", sessionId, "agent-tracker.json");
58
+ if (!existsSync(trackerPath))
59
+ return 0;
60
+ try {
61
+ const tracker = JSON.parse(readFileSync(trackerPath, "utf-8"));
62
+ const entry = Array.isArray(tracker)
63
+ ? tracker.find((e) => e.agent_id === agentId)
64
+ : null;
65
+ return entry?.resume_count ?? 0;
66
+ }
67
+ catch {
68
+ return 0;
69
+ }
70
+ }
71
+ const handler = async (input) => {
72
+ if (input.hook_event_name !== "SubagentStart")
73
+ return;
74
+ const { cwd, session_id, agent_type, agent_id } = input;
75
+ // fresh only — skip on resume
76
+ const resumeCount = getResumeCount(cwd, session_id, agent_id);
77
+ if (resumeCount > 0)
78
+ return;
79
+ // unregistered role: silent skip
80
+ const validRoles = loadValidRoles(cwd);
81
+ if (!validRoles.includes(agent_type))
82
+ return;
83
+ const parts = [];
84
+ const coreIndex = buildCoreIndex(cwd);
85
+ if (coreIndex) {
86
+ parts.push(`<system-notice>\n${coreIndex}\n</system-notice>`);
87
+ }
88
+ const rulePath = join(cwd, ".nexus/rules", `${agent_type}.md`);
89
+ if (existsSync(rulePath)) {
90
+ const ruleContent = readFileSync(rulePath, "utf-8").trim();
91
+ if (ruleContent) {
92
+ parts.push(`<system-notice>\nCustom rule for ${agent_type}:\n${ruleContent}\n</system-notice>`);
93
+ }
94
+ }
95
+ if (parts.length === 0)
96
+ return;
97
+ return { additional_context: parts.join("\n\n") };
98
+ };
99
+ export default handler;
100
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../../assets/hooks/agent-bootstrap/handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { HookHandler } from "../../../src/hooks/types.js";
2
+ declare const handler: HookHandler;
3
+ export default handler;
4
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../assets/hooks/agent-finalize/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAK/D,QAAA,MAAM,OAAO,EAAE,WAoEd,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,63 @@
1
+ import { updateJsonFileLocked } from "../../../src/shared/json-store.js";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ const handler = async (input) => {
5
+ if (input.hook_event_name !== "SubagentStop")
6
+ return;
7
+ const { cwd, session_id, agent_type, agent_id } = input;
8
+ const lastMessage = (input.last_assistant_message ?? "").slice(0, 500);
9
+ const sessionDir = join(cwd, ".nexus/state", session_id);
10
+ const trackerPath = join(sessionDir, "agent-tracker.json");
11
+ const toolLogPath = join(sessionDir, "tool-log.jsonl");
12
+ const tasksPath = join(sessionDir, "tasks.json");
13
+ // 1. tracker update + files_touched aggregation (locked)
14
+ await updateJsonFileLocked(trackerPath, [], (tracker) => {
15
+ const entry = tracker.find((e) => e["agent_id"] === agent_id);
16
+ if (!entry)
17
+ return tracker;
18
+ entry["status"] = "completed";
19
+ entry["stopped_at"] = new Date().toISOString();
20
+ entry["last_message"] = lastMessage;
21
+ if (existsSync(toolLogPath)) {
22
+ const files = new Set();
23
+ const raw = readFileSync(toolLogPath, "utf-8");
24
+ for (const line of raw.split("\n")) {
25
+ if (!line.trim())
26
+ continue;
27
+ try {
28
+ const log = JSON.parse(line);
29
+ if (log["agent_id"] === agent_id && typeof log["file"] === "string") {
30
+ files.add(log["file"]);
31
+ }
32
+ }
33
+ catch {
34
+ // skip malformed lines
35
+ }
36
+ }
37
+ entry["files_touched"] = [...files];
38
+ }
39
+ return tracker;
40
+ });
41
+ // 2. pending tasks alert (owner.role === agent_type)
42
+ if (!existsSync(tasksPath))
43
+ return;
44
+ try {
45
+ const tasksData = JSON.parse(readFileSync(tasksPath, "utf-8"));
46
+ const tasks = Array.isArray(tasksData?.["tasks"])
47
+ ? tasksData["tasks"]
48
+ : [];
49
+ const incomplete = tasks.filter((t) => t["owner"]?.["role"] === agent_type &&
50
+ t["status"] !== "completed");
51
+ if (incomplete.length === 0)
52
+ return;
53
+ const ids = incomplete.map((t) => t["id"]).join(", ");
54
+ return {
55
+ additional_context: `<system-notice>\nSubagent "${agent_type}" finished. Tasks still pending with this role: ${ids}. Review status and coordinate remaining subagent delegation.\n</system-notice>`,
56
+ };
57
+ }
58
+ catch {
59
+ return;
60
+ }
61
+ };
62
+ export default handler;
63
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../../assets/hooks/agent-finalize/handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { HookHandler } from "../../../src/hooks/types.js";
2
+ declare const handler: HookHandler;
3
+ export default handler;
4
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../assets/hooks/post-tool-telemetry/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAY/D,QAAA,MAAM,OAAO,EAAE,WAkCd,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { appendJsonLine } from "../../../src/shared/json-store.js";
2
+ import { join, resolve, relative } from "node:path";
3
+ const EDIT_TOOLS = new Set(["Edit", "Write", "MultiEdit", "ApplyPatch", "NotebookEdit"]);
4
+ function isWithinMemory(filePath, projectRoot) {
5
+ const memRoot = resolve(projectRoot, ".nexus/memory");
6
+ const abs = resolve(filePath);
7
+ return abs.startsWith(memRoot + "/") || abs === memRoot;
8
+ }
9
+ const handler = async (input) => {
10
+ if (input.hook_event_name !== "PostToolUse")
11
+ return;
12
+ const { cwd, session_id, tool_name, agent_id } = input;
13
+ const toolInput = (input.tool_input ?? {});
14
+ // 1. Memory access tracking (Read)
15
+ if (tool_name === "Read") {
16
+ const filePath = toolInput.file_path;
17
+ if (filePath && isWithinMemory(filePath, cwd)) {
18
+ appendJsonLine(join(cwd, ".nexus/memory-access.jsonl"), {
19
+ path: relative(cwd, resolve(filePath)),
20
+ accessed_at: new Date().toISOString(),
21
+ agent: agent_id ?? null,
22
+ });
23
+ }
24
+ }
25
+ // 2. Tool-log append (edit tools + agent_id present)
26
+ if (EDIT_TOOLS.has(tool_name) && agent_id) {
27
+ const filePath = (toolInput.file_path ?? toolInput.notebook_path);
28
+ if (filePath) {
29
+ appendJsonLine(join(cwd, ".nexus/state", session_id, "tool-log.jsonl"), {
30
+ ts: new Date().toISOString(),
31
+ agent_id,
32
+ tool: tool_name,
33
+ file: relative(cwd, resolve(filePath)),
34
+ status: "ok",
35
+ });
36
+ }
37
+ }
38
+ };
39
+ export default handler;
40
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../../assets/hooks/post-tool-telemetry/handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEpD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC;AAEzF,SAAS,cAAc,CAAC,QAAgB,EAAE,WAAmB;IAC3D,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9B,OAAO,GAAG,CAAC,UAAU,CAAC,OAAO,GAAG,GAAG,CAAC,IAAI,GAAG,KAAK,OAAO,CAAC;AAC1D,CAAC;AAED,MAAM,OAAO,GAAgB,KAAK,EAAE,KAAK,EAAE,EAAE;IAC3C,IAAI,KAAK,CAAC,eAAe,KAAK,aAAa;QAAE,OAAO;IAEpD,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IACvD,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE,CAA4B,CAAC;IAEtE,mCAAmC;IACnC,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,SAAS,CAAC,SAA+B,CAAC;QAC3D,IAAI,QAAQ,IAAI,cAAc,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC;YAC9C,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,4BAA4B,CAAC,EAAE;gBACtD,IAAI,EAAE,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;gBACtC,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACrC,KAAK,EAAE,QAAQ,IAAI,IAAI;aACxB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,qDAAqD;IACrD,IAAI,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,QAAQ,EAAE,CAAC;QAC1C,MAAM,QAAQ,GAAG,CAAC,SAAS,CAAC,SAAS,IAAI,SAAS,CAAC,aAAa,CAAuB,CAAC;QACxF,IAAI,QAAQ,EAAE,CAAC;YACb,cAAc,CACZ,IAAI,CAAC,GAAG,EAAE,cAAc,EAAE,UAAU,EAAE,gBAAgB,CAAC,EACvD;gBACE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBAC5B,QAAQ;gBACR,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;gBACtC,MAAM,EAAE,IAAI;aACb,CACF,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { HookHandler } from "../../../src/hooks/types.js";
2
+ declare const handler: HookHandler;
3
+ export default handler;
4
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../assets/hooks/prompt-router/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAmB,MAAM,6BAA6B,CAAC;AAmGhF,QAAA,MAAM,OAAO,EAAE,WA+Jd,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,204 @@
1
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
2
+ import { join, resolve, dirname } from "node:path";
3
+ import { parse as parseYaml } from "yaml";
4
+ import { expandInvocations, } from "../../../src/shared/invocations.js";
5
+ // Tag priority: specific variants first (m:gc > m, rule:name > rule, plan:auto > plan, init:reset > init)
6
+ const TAG_PATTERNS = [
7
+ { name: "plan:auto", regex: /\[plan:auto\]/ },
8
+ { name: "plan", regex: /\[plan\](?!\w)/ },
9
+ { name: "run", regex: /\[run\](?!\w)/ },
10
+ { name: "d", regex: /\[d\](?!\w)/ },
11
+ { name: "m:gc", regex: /\[m:gc\]/ },
12
+ { name: "m", regex: /\[m\](?!\w)/ },
13
+ { name: "rule:name", regex: /\[rule:([a-zA-Z0-9_-]+)\]/ },
14
+ { name: "rule", regex: /\[rule\](?!\w)/ },
15
+ { name: "sync", regex: /\[sync\](?!\w)/ },
16
+ { name: "init:reset", regex: /\[init:reset\]/ },
17
+ { name: "init", regex: /\[init\](?!\w)/ },
18
+ ];
19
+ // ---------------------------------------------------------------------------
20
+ // Invocations loader — cached per process
21
+ // ---------------------------------------------------------------------------
22
+ let _invocationsCache = null;
23
+ function loadInvocations() {
24
+ if (_invocationsCache)
25
+ return _invocationsCache;
26
+ const selfDir = new URL(".", import.meta.url).pathname;
27
+ // Walk up from handler directory to find assets/tools/tool-name-map.yml
28
+ let dir = selfDir;
29
+ while (dir !== "/") {
30
+ const candidate = resolve(dir, "assets/tools/tool-name-map.yml");
31
+ if (existsSync(candidate)) {
32
+ const raw = readFileSync(candidate, "utf-8");
33
+ const parsed = parseYaml(raw);
34
+ if (!parsed.invocations) {
35
+ throw new Error("[prompt-router] tool-name-map.yml missing 'invocations' section");
36
+ }
37
+ _invocationsCache = parsed.invocations;
38
+ return _invocationsCache;
39
+ }
40
+ const parent = dirname(dir);
41
+ if (parent === dir)
42
+ break;
43
+ dir = parent;
44
+ }
45
+ throw new Error(`[prompt-router] Cannot locate assets/tools/tool-name-map.yml from ${selfDir}`);
46
+ }
47
+ // ---------------------------------------------------------------------------
48
+ // Harness resolution
49
+ // ---------------------------------------------------------------------------
50
+ function resolveHarness() {
51
+ const h = process.env["NEXUS_HARNESS"];
52
+ if (h === "claude" || h === "opencode" || h === "codex")
53
+ return h;
54
+ if (h) {
55
+ process.stderr.write(`[prompt-router] Unknown NEXUS_HARNESS="${h}", falling back to "claude"\n`);
56
+ }
57
+ return "claude";
58
+ }
59
+ // ---------------------------------------------------------------------------
60
+ // Invocation expansion helper
61
+ // ---------------------------------------------------------------------------
62
+ function expand(template, harness) {
63
+ return expandInvocations(template, harness, loadInvocations());
64
+ }
65
+ // ---------------------------------------------------------------------------
66
+ // Rule target loader
67
+ // ---------------------------------------------------------------------------
68
+ function loadValidRuleTargets(cwd) {
69
+ const targets = [];
70
+ for (const dir of ["assets/agents", "assets/skills"]) {
71
+ const absDir = join(cwd, dir);
72
+ if (!existsSync(absDir))
73
+ continue;
74
+ for (const entry of readdirSync(absDir, { withFileTypes: true })) {
75
+ if (entry.isDirectory())
76
+ targets.push(entry.name);
77
+ }
78
+ }
79
+ return targets;
80
+ }
81
+ // ---------------------------------------------------------------------------
82
+ // Handler
83
+ // ---------------------------------------------------------------------------
84
+ const handler = async (input) => {
85
+ if (input.hook_event_name !== "UserPromptSubmit")
86
+ return;
87
+ const prompt = input.prompt;
88
+ const detected = [];
89
+ // Detect all tags — use seen Set keyed on base tag name to prevent duplicates
90
+ // (e.g. plan:auto and plan share base "plan"; whichever appears first wins)
91
+ const seen = new Set();
92
+ for (const { name, regex } of TAG_PATTERNS) {
93
+ const m = regex.exec(prompt);
94
+ if (!m)
95
+ continue;
96
+ const base = name.split(":")[0];
97
+ if (seen.has(base))
98
+ continue;
99
+ seen.add(base);
100
+ detected.push({ name, arg: m[1] });
101
+ }
102
+ const sessionDir = join(input.cwd, ".nexus/state", input.session_id);
103
+ const planPath = join(sessionDir, "plan.json");
104
+ const tasksPath = join(sessionDir, "tasks.json");
105
+ const hasPlan = existsSync(planPath);
106
+ const hasTasks = existsSync(tasksPath);
107
+ const harness = resolveHarness();
108
+ const notices = [];
109
+ let decision;
110
+ let block_reason;
111
+ for (const tag of detected) {
112
+ switch (tag.name) {
113
+ case "plan":
114
+ notices.push(`<system-notice>[plan] tag detected. ${expand('{{skill_activation skill="nx-plan"}}', harness)} for structured planning.</system-notice>`);
115
+ break;
116
+ case "plan:auto":
117
+ notices.push(`<system-notice>[plan:auto] tag detected. ${expand('{{skill_activation skill="nx-plan" mode="auto"}}', harness)} for structured planning.</system-notice>`);
118
+ break;
119
+ case "run":
120
+ if (!hasTasks) {
121
+ notices.push(`<system-notice>[run] tag detected but no tasks.json. ${expand('{{skill_activation skill="nx-plan"}}', harness)} with args "auto" first to generate tasks, then run.</system-notice>`);
122
+ }
123
+ else {
124
+ notices.push(`<system-notice>[run] tag detected. ${expand('{{skill_activation skill="nx-run"}}', harness)} to execute tasks.</system-notice>`);
125
+ }
126
+ break;
127
+ case "d":
128
+ if (!hasPlan) {
129
+ decision = "block";
130
+ block_reason =
131
+ `[d] tag requires an active plan session. ${expand('{{skill_activation skill="nx-plan"}}', harness)} first.`;
132
+ }
133
+ else {
134
+ notices.push(`<system-notice>[d] tag detected. Record decision via \`nx_plan_decide(issue_id, summary)\` MCP tool.</system-notice>`);
135
+ }
136
+ break;
137
+ case "m":
138
+ notices.push(`<system-notice>[m] tag detected. Save a memory note to \`.nexus/memory/<prefix>-<name>.md\`. Prefix: empirical-, external-, or pattern- (see architecture.md §2-1).</system-notice>`);
139
+ break;
140
+ case "m:gc":
141
+ notices.push(`<system-notice>[m:gc] tag detected. Review \`.nexus/memory/\` for stale or duplicate entries and consolidate.</system-notice>`);
142
+ break;
143
+ case "rule": {
144
+ const valid = loadValidRuleTargets(input.cwd);
145
+ notices.push(`<system-notice>[rule] tag detected. Determine target from intent. Valid targets: ${valid.join(", ")}. Update \`.nexus/rules/<target>.md\`.</system-notice>`);
146
+ break;
147
+ }
148
+ case "rule:name": {
149
+ const valid = loadValidRuleTargets(input.cwd);
150
+ const name = tag.arg ?? "";
151
+ if (!valid.includes(name)) {
152
+ decision = "block";
153
+ block_reason = `[rule:${name}] invalid — must be one of: ${valid.join(", ")}`;
154
+ }
155
+ else {
156
+ notices.push(`<system-notice>[rule:${name}] tag detected. Update \`.nexus/rules/${name}.md\` with user's directive.</system-notice>`);
157
+ }
158
+ break;
159
+ }
160
+ case "sync":
161
+ notices.push(`<system-notice>[sync] tag detected. ${expand('{{skill_activation skill="nx-sync"}}', harness)} to synchronize \`.nexus/context/\`.</system-notice>`);
162
+ break;
163
+ case "init":
164
+ notices.push(`<system-notice>[init] tag detected. ${expand('{{skill_activation skill="nx-init"}}', harness)} for project onboarding.</system-notice>`);
165
+ break;
166
+ case "init:reset":
167
+ notices.push(`<system-notice>[init:reset] tag detected. ${expand('{{skill_activation skill="nx-init" mode="reset"}}', harness)} for full re-initialization.</system-notice>`);
168
+ break;
169
+ }
170
+ }
171
+ // No tags detected + active state → emit state notice
172
+ if (detected.length === 0) {
173
+ if (hasPlan) {
174
+ try {
175
+ const plan = JSON.parse(readFileSync(planPath, "utf-8"));
176
+ const pending = plan.issues?.filter((i) => i.status === "pending").length ?? 0;
177
+ notices.push(`<system-notice>Active plan session: "${plan.topic ?? "(unknown)"}", ${pending} issues pending.</system-notice>`);
178
+ }
179
+ catch {
180
+ // Malformed plan.json — skip notice
181
+ }
182
+ }
183
+ else if (hasTasks) {
184
+ try {
185
+ const tasks = JSON.parse(readFileSync(tasksPath, "utf-8"));
186
+ const pending = tasks.tasks?.filter((t) => t.status !== "completed").length ?? 0;
187
+ if (pending > 0) {
188
+ notices.push(`<system-notice>Active run session: ${pending} tasks remaining in tasks.json.</system-notice>`);
189
+ }
190
+ }
191
+ catch {
192
+ // Malformed tasks.json — skip notice
193
+ }
194
+ }
195
+ }
196
+ if (decision === "block") {
197
+ return { decision, block_reason };
198
+ }
199
+ if (notices.length === 0)
200
+ return;
201
+ return { additional_context: notices.join("\n\n") };
202
+ };
203
+ export default handler;
204
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../../assets/hooks/prompt-router/handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { HookHandler } from "../../../src/hooks/types.js";
2
+ declare const handler: HookHandler;
3
+ export default handler;
4
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../assets/hooks/session-init/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAI/D,QAAA,MAAM,OAAO,EAAE,WAuBd,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { join, basename } from "node:path";
3
+ const handler = async (input) => {
4
+ if (input.hook_event_name !== "SessionStart")
5
+ return;
6
+ // Sanitize session_id to prevent path traversal
7
+ const safeSid = basename(input.session_id);
8
+ if (!safeSid || safeSid.startsWith(".") || safeSid.includes("/")) {
9
+ process.stderr.write(`[session-init] invalid session_id: ${input.session_id}\n`);
10
+ return;
11
+ }
12
+ const sessionDir = join(input.cwd, ".nexus/state", safeSid);
13
+ // Ensure directory exists (idempotent)
14
+ mkdirSync(sessionDir, { recursive: true });
15
+ // Initialize per-session state files — overwrite unconditionally (resume is intentional)
16
+ writeFileSync(join(sessionDir, "agent-tracker.json"), "[]");
17
+ writeFileSync(join(sessionDir, "tool-log.jsonl"), "");
18
+ // plan.json and tasks.json are MCP responsibility — not touched here
19
+ // memory-access.jsonl is project-level — not touched here
20
+ // No additional_context returned (decided: no context injection at session start)
21
+ };
22
+ export default handler;
23
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../../assets/hooks/session-init/handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,OAAO,GAAgB,KAAK,EAAE,KAAK,EAAE,EAAE;IAC3C,IAAI,KAAK,CAAC,eAAe,KAAK,cAAc;QAAE,OAAO;IAErD,gDAAgD;IAChD,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC3C,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sCAAsC,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC;QACjF,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;IAE5D,uCAAuC;IACvC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3C,yFAAyF;IACzF,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,oBAAoB,CAAC,EAAE,IAAI,CAAC,CAAC;IAC5D,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,gBAAgB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEtD,qEAAqE;IACrE,0DAA0D;IAE1D,kFAAkF;AACpF,CAAC,CAAC;AAEF,eAAe,OAAO,CAAC"}