claude-nexus 0.28.1 → 0.29.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.
@@ -7,7 +7,7 @@
7
7
  {
8
8
  "name": "claude-nexus",
9
9
  "description": "Agent orchestration plugin for Claude Code. Injects optimized context per agent role with minimal overhead.",
10
- "version": "0.28.1",
10
+ "version": "0.29.0",
11
11
  "author": {
12
12
  "name": "kih"
13
13
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-nexus",
3
- "version": "0.28.1",
3
+ "version": "0.29.0",
4
4
  "description": "Agent orchestration plugin for Claude Code — optimized context injection per role",
5
5
  "author": {
6
6
  "name": "kih"
package/VERSION CHANGED
@@ -1 +1 @@
1
- 0.28.1
1
+ 0.29.0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: "Technical design — evaluates How, reviews architecture, advises on implementation approach"
3
- model: claude-opus-4
3
+ model: opus
4
4
  disallowedTools:
5
5
  - Edit
6
6
  - Write
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: "UX/UI design — evaluates user experience, interaction patterns, and how users will experience the product"
3
- model: claude-opus-4
3
+ model: opus
4
4
  disallowedTools:
5
5
  - Edit
6
6
  - Write
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: "Implementation — writes code, debugs issues, follows specifications from Lead and architect"
3
- model: claude-sonnet-4
3
+ model: sonnet
4
4
  disallowedTools:
5
5
  - mcp__plugin_claude-nexus_nx__nx_task_add
6
6
  ---
package/agents/lead.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: "Primary orchestrator — converses directly with users, composes 9 subagents across HOW/DO/CHECK categories, and owns scope decisions and task lifecycle"
3
- model: claude-opus-4
3
+ model: opus
4
4
  ---
5
5
  ## Identity
6
6
 
package/agents/postdoc.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: "Research methodology and synthesis — designs investigation approach, evaluates evidence quality, writes synthesis documents"
3
- model: claude-opus-4
3
+ model: opus
4
4
  disallowedTools:
5
5
  - Edit
6
6
  - Write
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: "Independent investigation — conducts web searches, gathers evidence, and reports findings with citations"
3
- model: claude-sonnet-4
3
+ model: sonnet
4
4
  disallowedTools:
5
5
  - Edit
6
6
  - Write
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: "Content verification — validates accuracy, checks facts, confirms grammar and format of non-code deliverables"
3
- model: claude-sonnet-4
3
+ model: sonnet
4
4
  disallowedTools:
5
5
  - Edit
6
6
  - Write
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: "Business strategy — evaluates market positioning, competitive landscape, and business viability of decisions"
3
- model: claude-opus-4
3
+ model: opus
4
4
  disallowedTools:
5
5
  - Edit
6
6
  - Write
package/agents/tester.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: "Testing and verification — tests, verifies, validates stability and security of implementations"
3
- model: claude-sonnet-4
3
+ model: sonnet
4
4
  disallowedTools:
5
5
  - Edit
6
6
  - Write
package/agents/writer.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: "Technical writing — transforms research findings, code, and analysis into clear documents and presentations for the intended audience"
3
- model: claude-sonnet-4
3
+ model: sonnet
4
4
  disallowedTools:
5
5
  - mcp__plugin_claude-nexus_nx__nx_task_add
6
6
  ---
@@ -1,21 +1,124 @@
1
+ // src/shared/json-store.js
2
+ import fs from "node:fs/promises";
3
+ import { constants as fsConstants, appendFileSync, mkdirSync } from "node:fs";
4
+ import path from "node:path";
5
+ import { randomUUID } from "node:crypto";
6
+ var inProcessQueues = new Map;
7
+ async function runWithInProcessLock(filePath, action) {
8
+ const previous = inProcessQueues.get(filePath) ?? Promise.resolve();
9
+ let release = () => {};
10
+ const gate = new Promise((resolve) => {
11
+ release = resolve;
12
+ });
13
+ const entry = previous.then(() => gate);
14
+ inProcessQueues.set(filePath, entry);
15
+ await previous;
16
+ try {
17
+ return await action();
18
+ } finally {
19
+ release();
20
+ entry.finally(() => {
21
+ if (inProcessQueues.get(filePath) === entry) {
22
+ inProcessQueues.delete(filePath);
23
+ }
24
+ });
25
+ }
26
+ }
27
+ var LOCK_RETRY_INTERVAL_MS = 100;
28
+ var LOCK_MAX_RETRIES = 50;
29
+ var LOCK_STALE_MS = 30000;
30
+ function lockPath(filePath) {
31
+ return `${filePath}.lock`;
32
+ }
33
+ async function acquireFsLock(filePath) {
34
+ const lp = lockPath(filePath);
35
+ for (let attempt = 0;attempt <= LOCK_MAX_RETRIES; attempt++) {
36
+ try {
37
+ const fd = await fs.open(lp, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL);
38
+ await fd.close();
39
+ return;
40
+ } catch (err) {
41
+ const e = err;
42
+ if (e.code !== "EEXIST")
43
+ throw err;
44
+ try {
45
+ const stat = await fs.stat(lp);
46
+ const ageMs = Date.now() - stat.mtimeMs;
47
+ if (ageMs > LOCK_STALE_MS) {
48
+ await fs.unlink(lp).catch(() => {
49
+ return;
50
+ });
51
+ continue;
52
+ }
53
+ } catch {
54
+ continue;
55
+ }
56
+ if (attempt === LOCK_MAX_RETRIES) {
57
+ throw new Error(`Failed to acquire lock for "${filePath}" after ${LOCK_MAX_RETRIES} retries`);
58
+ }
59
+ await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_INTERVAL_MS));
60
+ }
61
+ }
62
+ }
63
+ async function releaseFsLock(filePath) {
64
+ await fs.unlink(lockPath(filePath)).catch(() => {
65
+ return;
66
+ });
67
+ }
68
+ async function readJsonFile(filePath, defaultValue) {
69
+ let raw;
70
+ try {
71
+ raw = await fs.readFile(filePath, "utf8");
72
+ } catch (err) {
73
+ const e = err;
74
+ if (e.code === "ENOENT")
75
+ return defaultValue;
76
+ throw err;
77
+ }
78
+ try {
79
+ return JSON.parse(raw);
80
+ } catch {
81
+ return defaultValue;
82
+ }
83
+ }
84
+ async function writeJsonFile(filePath, data) {
85
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
86
+ const tmpPath = `${filePath}.tmp.${process.pid}.${Date.now()}.${randomUUID()}`;
87
+ await fs.writeFile(tmpPath, JSON.stringify(data, null, 2) + `
88
+ `, "utf8");
89
+ await fs.rename(tmpPath, filePath);
90
+ }
91
+ async function updateJsonFileLocked(filePath, defaultValue, updater) {
92
+ return runWithInProcessLock(filePath, async () => {
93
+ await acquireFsLock(filePath);
94
+ try {
95
+ const current = await readJsonFile(filePath, defaultValue);
96
+ const next = await updater(current);
97
+ await writeJsonFile(filePath, next);
98
+ return next;
99
+ } finally {
100
+ await releaseFsLock(filePath);
101
+ }
102
+ });
103
+ }
104
+ var APPEND_SIZE_WARN_THRESHOLD = 4 * 1024;
105
+
1
106
  // assets/hooks/agent-bootstrap/handler.ts
2
107
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
3
108
  import { join } from "node:path";
4
109
  var CORE_INDEX_SIZE_LIMIT = 2 * 1024;
5
110
  function loadValidRoles(cwd) {
111
+ const inlined = globalThis.__NEXUS_INLINE_AGENT_ROLES__;
112
+ if (Array.isArray(inlined))
113
+ return inlined;
6
114
  const agentsDir = join(cwd, "assets/agents");
7
- const roles = [];
8
- if (existsSync(agentsDir)) {
9
- for (const entry of readdirSync(agentsDir, { withFileTypes: true })) {
10
- if (entry.isDirectory())
11
- roles.push(entry.name);
12
- }
13
- }
14
- return roles;
115
+ if (!existsSync(agentsDir))
116
+ return [];
117
+ return readdirSync(agentsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
15
118
  }
16
- function readFirstLine(path) {
119
+ function readFirstLine(path2) {
17
120
  try {
18
- const content = readFileSync(path, "utf-8");
121
+ const content = readFileSync(path2, "utf-8");
19
122
  const firstNonEmpty = content.split(`
20
123
  `).find((l) => l.trim().length > 0) ?? "";
21
124
  return firstNonEmpty.replace(/^#+\s*/, "").slice(0, 80);
@@ -76,6 +179,19 @@ var handler = async (input) => {
76
179
  const validRoles = loadValidRoles(cwd);
77
180
  if (!validRoles.includes(agent_type))
78
181
  return;
182
+ const trackerPath = join(cwd, ".nexus/state", session_id, "agent-tracker.json");
183
+ await updateJsonFileLocked(trackerPath, [], (tracker) => {
184
+ const list = Array.isArray(tracker) ? tracker : [];
185
+ if (list.find((e) => e["agent_id"] === agent_id))
186
+ return list;
187
+ list.push({
188
+ agent_id,
189
+ agent_type,
190
+ started_at: new Date().toISOString(),
191
+ status: "running"
192
+ });
193
+ return list;
194
+ });
79
195
  const parts = [];
80
196
  const coreIndex = buildCoreIndex(cwd);
81
197
  if (coreIndex) {
@@ -100,6 +216,23 @@ ${ruleContent}
100
216
  `) };
101
217
  };
102
218
  var handler_default = handler;
103
- export {
104
- handler_default as default
105
- };
219
+
220
+ // ../../../../../tmp/nexus-hook-entry-agent-bootstrap-1776690665703/agent-bootstrap-entry.ts
221
+ import { readFileSync as readFileSync2 } from "node:fs";
222
+ globalThis.__NEXUS_INLINE_AGENT_ROLES__ = ["architect", "designer", "engineer", "reviewer", "strategist", "researcher", "postdoc", "lead", "tester", "writer"];
223
+ async function main() {
224
+ let raw = "";
225
+ try {
226
+ raw = readFileSync2(0, "utf-8");
227
+ } catch {}
228
+ const input = raw ? JSON.parse(raw) : {};
229
+ const result = await handler_default(input);
230
+ if (result != null && result !== undefined) {
231
+ process.stdout.write(JSON.stringify(result));
232
+ }
233
+ }
234
+ main().then(() => process.exit(0), (err) => {
235
+ process.stderr.write(String(err?.stack ?? err) + `
236
+ `);
237
+ process.exit(1);
238
+ });
@@ -159,6 +159,22 @@ Subagent "${agent_type}" finished. Tasks still pending with this role: ${ids}. R
159
159
  }
160
160
  };
161
161
  var handler_default = handler;
162
- export {
163
- handler_default as default
164
- };
162
+
163
+ // ../../../../../tmp/nexus-hook-entry-agent-finalize-1776690665695/agent-finalize-entry.ts
164
+ import { readFileSync as readFileSync2 } from "node:fs";
165
+ async function main() {
166
+ let raw = "";
167
+ try {
168
+ raw = readFileSync2(0, "utf-8");
169
+ } catch {}
170
+ const input = raw ? JSON.parse(raw) : {};
171
+ const result = await handler_default(input);
172
+ if (result != null && result !== undefined) {
173
+ process.stdout.write(JSON.stringify(result));
174
+ }
175
+ }
176
+ main().then(() => process.exit(0), (err) => {
177
+ process.stderr.write(String(err?.stack ?? err) + `
178
+ `);
179
+ process.exit(1);
180
+ });
@@ -0,0 +1,71 @@
1
+ // src/shared/json-store.js
2
+ import { constants as fsConstants, appendFileSync, mkdirSync } from "node:fs";
3
+ import path from "node:path";
4
+ var inProcessQueues = new Map;
5
+ var APPEND_SIZE_WARN_THRESHOLD = 4 * 1024;
6
+ function appendJsonLine(filePath, record) {
7
+ const line = JSON.stringify(record) + `
8
+ `;
9
+ if (line.length > APPEND_SIZE_WARN_THRESHOLD) {
10
+ console.error(`[json-store] appendJsonLine line exceeds ${APPEND_SIZE_WARN_THRESHOLD} bytes ` + `(${line.length}) — write may not be atomic on some filesystems. path=${filePath}`);
11
+ }
12
+ mkdirSync(path.dirname(filePath), { recursive: true });
13
+ appendFileSync(filePath, line);
14
+ }
15
+
16
+ // assets/hooks/post-tool-telemetry/handler.ts
17
+ import { join, resolve, relative } from "node:path";
18
+ var EDIT_TOOLS = new Set(["Edit", "Write", "MultiEdit", "ApplyPatch", "NotebookEdit"]);
19
+ function isWithinMemory(filePath, projectRoot) {
20
+ const memRoot = resolve(projectRoot, ".nexus/memory");
21
+ const abs = resolve(filePath);
22
+ return abs.startsWith(memRoot + "/") || abs === memRoot;
23
+ }
24
+ var handler = async (input) => {
25
+ if (input.hook_event_name !== "PostToolUse")
26
+ return;
27
+ const { cwd, session_id, tool_name, agent_id } = input;
28
+ const toolInput = input.tool_input ?? {};
29
+ if (tool_name === "Read") {
30
+ const filePath = toolInput.file_path;
31
+ if (filePath && isWithinMemory(filePath, cwd)) {
32
+ appendJsonLine(join(cwd, ".nexus/memory-access.jsonl"), {
33
+ path: relative(cwd, resolve(filePath)),
34
+ accessed_at: new Date().toISOString(),
35
+ agent: agent_id ?? null
36
+ });
37
+ }
38
+ }
39
+ if (EDIT_TOOLS.has(tool_name) && agent_id) {
40
+ const filePath = toolInput.file_path ?? toolInput.notebook_path;
41
+ if (filePath) {
42
+ appendJsonLine(join(cwd, ".nexus/state", session_id, "tool-log.jsonl"), {
43
+ ts: new Date().toISOString(),
44
+ agent_id,
45
+ tool: tool_name,
46
+ file: relative(cwd, resolve(filePath)),
47
+ status: "ok"
48
+ });
49
+ }
50
+ }
51
+ };
52
+ var handler_default = handler;
53
+
54
+ // ../../../../../tmp/nexus-hook-entry-post-tool-telemetry-1776690665643/post-tool-telemetry-entry.ts
55
+ import { readFileSync } from "node:fs";
56
+ async function main() {
57
+ let raw = "";
58
+ try {
59
+ raw = readFileSync(0, "utf-8");
60
+ } catch {}
61
+ const input = raw ? JSON.parse(raw) : {};
62
+ const result = await handler_default(input);
63
+ if (result != null && result !== undefined) {
64
+ process.stdout.write(JSON.stringify(result));
65
+ }
66
+ }
67
+ main().then(() => process.exit(0), (err) => {
68
+ process.stderr.write(String(err?.stack ?? err) + `
69
+ `);
70
+ process.exit(1);
71
+ });
@@ -7141,6 +7141,11 @@ var _invocationsCache = null;
7141
7141
  function loadInvocations() {
7142
7142
  if (_invocationsCache)
7143
7143
  return _invocationsCache;
7144
+ const inlined = globalThis.__NEXUS_INLINE_INVOCATIONS__;
7145
+ if (inlined) {
7146
+ _invocationsCache = inlined;
7147
+ return inlined;
7148
+ }
7144
7149
  const selfDir = new URL(".", import.meta.url).pathname;
7145
7150
  let dir = selfDir;
7146
7151
  while (dir !== "/") {
@@ -7175,6 +7180,9 @@ function expand(template, harness) {
7175
7180
  return expandInvocations(template, harness, loadInvocations());
7176
7181
  }
7177
7182
  function loadValidRuleTargets(cwd) {
7183
+ const inlined = globalThis.__NEXUS_INLINE_RULE_TARGETS__;
7184
+ if (inlined && inlined.length > 0)
7185
+ return inlined;
7178
7186
  const targets = [];
7179
7187
  for (const dir of ["assets/agents", "assets/skills"]) {
7180
7188
  const absDir = join(cwd, dir);
@@ -7295,6 +7303,34 @@ var handler = async (input) => {
7295
7303
  `) };
7296
7304
  };
7297
7305
  var handler_default = handler;
7298
- export {
7299
- handler_default as default
7300
- };
7306
+
7307
+ // ../../../../../tmp/nexus-hook-entry-prompt-router-1776690665662/prompt-router-entry.ts
7308
+ import { readFileSync as readFileSync2 } from "node:fs";
7309
+ globalThis.__NEXUS_INLINE_INVOCATIONS__ = { subagent_spawn: { args: ["target_role", "prompt", "name"], templates: { claude: 'Agent({ subagent_type: "{target_role}", prompt: "{prompt}", description: "{name}" })', opencode: 'task({ subagent_type: "{target_role}", prompt: "{prompt}", description: "{name}" })', codex: 'spawn_agent("{target_role}", "{prompt}")' }, notes: { claude: `description field is optional; omit when name arg is absent. model field may be added to override the spawned agent's model.
7310
+ `, opencode: `description is required by OpenCode's Zod schema — use target_role as fallback when name is absent. task_id param enables session resume (§15).
7311
+ `, codex: `Agent role must be pre-registered in config.toml [agents.<target_role>]. No description equivalent in spawn_agent call signature.
7312
+ ` } }, skill_activation: { args: ["skill", "mode"], templates: { claude: 'Skill({ command: "{skill}" })', opencode: 'skill({ name: "{skill}" })', codex: "${skill}" }, notes: { claude: "The Skill tool accepts only the `command` string; mode/args cannot be passed as a separate parameter. Mode must be embedded in the SKILL.md body via $ARGUMENTS placeholder substitution.\n", opencode: "The skill tool accepts only `name`; args passing is unconfirmed per source review. Design skills to be args-free or embed defaults in SKILL.md body.\n", codex: `Positional args: "$skill-name {mode}". Named args: "$skill-name MODE={mode}". Confirmed only for Custom Prompts; treat as best-effort for Skills. $ prefix is literal in composer input, not a tool call.
7313
+ ` } }, task_register: { args: ["label", "state"], templates: { claude: 'TaskCreate({ subject: "{label}" }) then nx_task_update({ taskId, status: "{state}" })', opencode: 'nx_task_add({ subject: "{label}" }) then nx_task_update({ taskId, status: "{state}" })', codex: 'update_plan([{ name: "{label}", state: "{state}" }])' }, notes: { claude: `TaskCreate is a Claude Code native tool (not MCP). nx_task_update is the nexus-core MCP tool — full name mcp__plugin_claude-nexus_nx__nx_task_update. taskId is returned by TaskCreate and must be threaded to the update call.
7314
+ `, opencode: `Both nx_task_add and nx_task_update are nexus-core MCP tools exposed via the nexus MCP server. task_id returned by nx_task_add must be threaded to update.
7315
+ `, codex: `update_plan subsumes creation and update in a single call via plan/step/status fields. No separate create/update step is needed.
7316
+ ` } }, user_question: { args: ["question", "options"], templates: { claude: 'AskUserQuestion({ questions: [{ question: "{question}", options: {options} }] })', opencode: 'question({ question: "{question}", choices: {options} })', codex: 'request_user_input({ prompt: "{question}", options: {options} })' }, notes: { claude: `options is a JSON array of strings. Omit the options field (not an empty array) for free-text responses. Multiple questions can be batched in the questions[] array.
7317
+ `, opencode: `choices field name (not options). Omit choices for free-text input.
7318
+ `, codex: `Exact request_user_input schema (options field name, types) is not fully documented — treat as best-effort. Verified as a native Codex tool in external-codex-hooks-tools.md §7-4.
7319
+ ` } } };
7320
+ globalThis.__NEXUS_INLINE_RULE_TARGETS__ = ["architect", "designer", "engineer", "reviewer", "strategist", "researcher", "postdoc", "lead", "tester", "writer", "nx-run", "nx-init", "nx-sync", "nx-plan"];
7321
+ async function main() {
7322
+ let raw = "";
7323
+ try {
7324
+ raw = readFileSync2(0, "utf-8");
7325
+ } catch {}
7326
+ const input = raw ? JSON.parse(raw) : {};
7327
+ const result = await handler_default(input);
7328
+ if (result != null && result !== undefined) {
7329
+ process.stdout.write(JSON.stringify(result));
7330
+ }
7331
+ }
7332
+ main().then(() => process.exit(0), (err) => {
7333
+ process.stderr.write(String(err?.stack ?? err) + `
7334
+ `);
7335
+ process.exit(1);
7336
+ });
@@ -1,6 +1,15 @@
1
1
  // assets/hooks/session-init/handler.ts
2
2
  import { mkdirSync, writeFileSync } from "node:fs";
3
3
  import { join, basename } from "node:path";
4
+
5
+ // src/shared/paths.ts
6
+ function getParentPid() {
7
+ const testOverride = parseInt(process.env["NEXUS_TEST_PPID"] ?? "");
8
+ return testOverride || process.ppid;
9
+ }
10
+ var byPpidCache = new Map;
11
+
12
+ // assets/hooks/session-init/handler.ts
4
13
  var handler = async (input) => {
5
14
  if (input.hook_event_name !== "SessionStart")
6
15
  return;
@@ -14,8 +23,28 @@ var handler = async (input) => {
14
23
  mkdirSync(sessionDir, { recursive: true });
15
24
  writeFileSync(join(sessionDir, "agent-tracker.json"), "[]");
16
25
  writeFileSync(join(sessionDir, "tool-log.jsonl"), "");
26
+ const ppid = getParentPid();
27
+ const byPpidDir = join(input.cwd, ".nexus/state/runtime/by-ppid");
28
+ mkdirSync(byPpidDir, { recursive: true });
29
+ writeFileSync(join(byPpidDir, `${ppid}.json`), JSON.stringify({ session_id: input.session_id, updated_at: new Date().toISOString(), cwd: input.cwd }));
17
30
  };
18
31
  var handler_default = handler;
19
- export {
20
- handler_default as default
21
- };
32
+
33
+ // ../../../../../tmp/nexus-hook-entry-session-init-1776690665653/session-init-entry.ts
34
+ import { readFileSync } from "node:fs";
35
+ async function main() {
36
+ let raw = "";
37
+ try {
38
+ raw = readFileSync(0, "utf-8");
39
+ } catch {}
40
+ const input = raw ? JSON.parse(raw) : {};
41
+ const result = await handler_default(input);
42
+ if (result != null && result !== undefined) {
43
+ process.stdout.write(JSON.stringify(result));
44
+ }
45
+ }
46
+ main().then(() => process.exit(0), (err) => {
47
+ process.stderr.write(String(err?.stack ?? err) + `
48
+ `);
49
+ process.exit(1);
50
+ });
package/hooks/hooks.json CHANGED
@@ -1,5 +1,17 @@
1
1
  {
2
2
  "hooks": {
3
+ "PostToolUse": [
4
+ {
5
+ "matcher": "Read|Edit|Write|MultiEdit|NotebookEdit",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "node ${CLAUDE_PLUGIN_ROOT}/dist/hooks/post-tool-telemetry.js",
10
+ "timeout": 5
11
+ }
12
+ ]
13
+ }
14
+ ],
3
15
  "SessionStart": [
4
16
  {
5
17
  "matcher": "*",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-nexus",
3
- "version": "0.28.1",
3
+ "version": "0.29.0",
4
4
  "type": "module",
5
5
  "description": "Agent orchestration plugin for Claude Code — optimized context injection per role",
6
6
  "author": "kih",
@@ -36,7 +36,7 @@
36
36
  "VERSION"
37
37
  ],
38
38
  "devDependencies": {
39
- "@moreih29/nexus-core": "^0.15.1"
39
+ "@moreih29/nexus-core": "^0.17.0"
40
40
  },
41
41
  "dependencies": {}
42
42
  }