@moreih29/nexus-core 0.12.0 → 0.13.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.
- package/README.md +48 -63
- package/assets/agents/architect/body.ko.md +177 -0
- package/{agents → assets/agents}/architect/body.md +16 -0
- package/assets/agents/designer/body.ko.md +125 -0
- package/{agents → assets/agents}/designer/body.md +16 -0
- package/assets/agents/engineer/body.ko.md +106 -0
- package/{agents → assets/agents}/engineer/body.md +14 -0
- package/assets/agents/lead/body.ko.md +70 -0
- package/assets/agents/lead/body.md +70 -0
- package/assets/agents/postdoc/body.ko.md +122 -0
- package/{agents → assets/agents}/postdoc/body.md +16 -0
- package/assets/agents/researcher/body.ko.md +137 -0
- package/{agents → assets/agents}/researcher/body.md +15 -0
- package/assets/agents/reviewer/body.ko.md +138 -0
- package/{agents → assets/agents}/reviewer/body.md +15 -0
- package/assets/agents/strategist/body.ko.md +116 -0
- package/{agents → assets/agents}/strategist/body.md +16 -0
- package/assets/agents/tester/body.ko.md +195 -0
- package/{agents → assets/agents}/tester/body.md +15 -0
- package/assets/agents/writer/body.ko.md +122 -0
- package/{agents → assets/agents}/writer/body.md +14 -0
- package/assets/capability-matrix.yml +198 -0
- package/assets/hooks/agent-bootstrap/handler.test.ts +368 -0
- package/assets/hooks/agent-bootstrap/handler.ts +119 -0
- package/assets/hooks/agent-bootstrap/meta.yml +10 -0
- package/assets/hooks/agent-finalize/handler.test.ts +368 -0
- package/assets/hooks/agent-finalize/handler.ts +76 -0
- package/assets/hooks/agent-finalize/meta.yml +10 -0
- package/assets/hooks/capability-matrix.yml +313 -0
- package/assets/hooks/post-tool-telemetry/handler.test.ts +302 -0
- package/assets/hooks/post-tool-telemetry/handler.ts +49 -0
- package/assets/hooks/post-tool-telemetry/meta.yml +11 -0
- package/assets/hooks/prompt-router/handler.test.ts +801 -0
- package/assets/hooks/prompt-router/handler.ts +261 -0
- package/assets/hooks/prompt-router/meta.yml +11 -0
- package/assets/hooks/session-init/handler.test.ts +274 -0
- package/assets/hooks/session-init/handler.ts +30 -0
- package/assets/hooks/session-init/meta.yml +9 -0
- package/assets/lsp-servers.json +55 -0
- package/assets/schema/lsp-servers.schema.json +67 -0
- package/assets/skills/nx-init/body.ko.md +197 -0
- package/{skills → assets/skills}/nx-init/body.md +11 -0
- package/assets/skills/nx-plan/body.ko.md +361 -0
- package/{skills → assets/skills}/nx-plan/body.md +13 -0
- package/assets/skills/nx-run/body.ko.md +161 -0
- package/{skills → assets/skills}/nx-run/body.md +11 -0
- package/assets/skills/nx-sync/body.ko.md +92 -0
- package/{skills → assets/skills}/nx-sync/body.md +10 -0
- package/assets/tools/tool-name-map.yml +353 -0
- package/dist/hooks/opencode-mount.d.ts +35 -0
- package/dist/hooks/opencode-mount.d.ts.map +1 -0
- package/dist/hooks/opencode-mount.js +332 -0
- package/dist/hooks/opencode-mount.js.map +1 -0
- package/dist/hooks/runtime.d.ts +37 -0
- package/dist/hooks/runtime.d.ts.map +1 -0
- package/dist/hooks/runtime.js +274 -0
- package/dist/hooks/runtime.js.map +1 -0
- package/dist/hooks/types.d.ts +196 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +85 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/lsp/cache.d.ts +9 -0
- package/dist/lsp/cache.d.ts.map +1 -0
- package/dist/lsp/cache.js +216 -0
- package/dist/lsp/cache.js.map +1 -0
- package/dist/lsp/client.d.ts +24 -0
- package/dist/lsp/client.d.ts.map +1 -0
- package/dist/lsp/client.js +166 -0
- package/dist/lsp/client.js.map +1 -0
- package/dist/lsp/detect.d.ts +77 -0
- package/dist/lsp/detect.d.ts.map +1 -0
- package/dist/lsp/detect.js +116 -0
- package/dist/lsp/detect.js.map +1 -0
- package/dist/mcp/server.d.ts +5 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +34 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/artifact.d.ts +4 -0
- package/dist/mcp/tools/artifact.d.ts.map +1 -0
- package/dist/mcp/tools/artifact.js +36 -0
- package/dist/mcp/tools/artifact.js.map +1 -0
- package/dist/mcp/tools/history.d.ts +3 -0
- package/dist/mcp/tools/history.d.ts.map +1 -0
- package/dist/mcp/tools/history.js +29 -0
- package/dist/mcp/tools/history.js.map +1 -0
- package/dist/mcp/tools/lsp.d.ts +13 -0
- package/dist/mcp/tools/lsp.d.ts.map +1 -0
- package/dist/mcp/tools/lsp.js +225 -0
- package/dist/mcp/tools/lsp.js.map +1 -0
- package/dist/mcp/tools/plan.d.ts +3 -0
- package/dist/mcp/tools/plan.d.ts.map +1 -0
- package/dist/mcp/tools/plan.js +317 -0
- package/dist/mcp/tools/plan.js.map +1 -0
- package/dist/mcp/tools/task.d.ts +3 -0
- package/dist/mcp/tools/task.d.ts.map +1 -0
- package/dist/mcp/tools/task.js +252 -0
- package/dist/mcp/tools/task.js.map +1 -0
- package/dist/shared/invocations.d.ts +74 -0
- package/dist/shared/invocations.d.ts.map +1 -0
- package/dist/shared/invocations.js +247 -0
- package/dist/shared/invocations.js.map +1 -0
- package/dist/shared/json-store.d.ts +37 -0
- package/dist/shared/json-store.d.ts.map +1 -0
- package/dist/shared/json-store.js +163 -0
- package/dist/shared/json-store.js.map +1 -0
- package/dist/shared/mcp-utils.d.ts +3 -0
- package/dist/shared/mcp-utils.d.ts.map +1 -0
- package/dist/shared/mcp-utils.js +6 -0
- package/dist/shared/mcp-utils.js.map +1 -0
- package/dist/shared/paths.d.ts +21 -0
- package/dist/shared/paths.d.ts.map +1 -0
- package/dist/shared/paths.js +81 -0
- package/dist/shared/paths.js.map +1 -0
- package/dist/shared/tool-log.d.ts +8 -0
- package/dist/shared/tool-log.d.ts.map +1 -0
- package/dist/shared/tool-log.js +22 -0
- package/dist/shared/tool-log.js.map +1 -0
- package/dist/types/state.d.ts +862 -0
- package/dist/types/state.d.ts.map +1 -0
- package/dist/types/state.js +66 -0
- package/dist/types/state.js.map +1 -0
- package/docs/consuming/codex-lead-merge.md +106 -0
- package/docs/plugin-guide.md +360 -0
- package/docs/plugin-template/claude/.github/workflows/build.yml +60 -0
- package/docs/plugin-template/claude/README.md +110 -0
- package/docs/plugin-template/claude/package.json +16 -0
- package/docs/plugin-template/codex/.github/workflows/build.yml +51 -0
- package/docs/plugin-template/codex/README.md +147 -0
- package/docs/plugin-template/codex/package.json +17 -0
- package/docs/plugin-template/opencode/.github/workflows/build.yml +61 -0
- package/docs/plugin-template/opencode/README.md +121 -0
- package/docs/plugin-template/opencode/package.json +25 -0
- package/package.json +21 -21
- package/scripts/build-agents.test.ts +1279 -0
- package/scripts/build-agents.ts +978 -0
- package/scripts/build-hooks.test.ts +1385 -0
- package/scripts/build-hooks.ts +584 -0
- package/scripts/cli.test.ts +367 -0
- package/scripts/cli.ts +547 -0
- package/agents/architect/meta.yml +0 -13
- package/agents/designer/meta.yml +0 -13
- package/agents/engineer/meta.yml +0 -11
- package/agents/postdoc/meta.yml +0 -13
- package/agents/researcher/meta.yml +0 -12
- package/agents/reviewer/meta.yml +0 -12
- package/agents/strategist/meta.yml +0 -13
- package/agents/tester/meta.yml +0 -12
- package/agents/writer/meta.yml +0 -11
- package/conformance/README.md +0 -311
- package/conformance/examples/plan.extension.schema.example.json +0 -25
- package/conformance/lifecycle/README.md +0 -48
- package/conformance/lifecycle/agent-complete.json +0 -44
- package/conformance/lifecycle/agent-resume.json +0 -43
- package/conformance/lifecycle/agent-spawn.json +0 -36
- package/conformance/lifecycle/memory-access-record.json +0 -27
- package/conformance/lifecycle/session-end.json +0 -48
- package/conformance/scenarios/full-plan-cycle.json +0 -147
- package/conformance/scenarios/task-deps-ordering.json +0 -95
- package/conformance/schema/fixture.schema.json +0 -354
- package/conformance/state-schemas/agent-tracker.schema.json +0 -63
- package/conformance/state-schemas/history.schema.json +0 -134
- package/conformance/state-schemas/memory-access.schema.json +0 -36
- package/conformance/state-schemas/plan.schema.json +0 -77
- package/conformance/state-schemas/tasks.schema.json +0 -98
- package/conformance/tools/artifact-write.json +0 -97
- package/conformance/tools/context.json +0 -172
- package/conformance/tools/history-search.json +0 -219
- package/conformance/tools/plan-decide.json +0 -139
- package/conformance/tools/plan-start.json +0 -81
- package/conformance/tools/plan-status.json +0 -127
- package/conformance/tools/plan-update.json +0 -341
- package/conformance/tools/task-add.json +0 -156
- package/conformance/tools/task-close.json +0 -161
- package/conformance/tools/task-list.json +0 -177
- package/conformance/tools/task-update.json +0 -167
- package/docs/behavioral-contracts.md +0 -145
- package/docs/consumer-implementation-guide.md +0 -840
- package/docs/memory-lifecycle-contract.md +0 -119
- package/docs/nexus-layout.md +0 -224
- package/docs/nexus-outputs-contract.md +0 -344
- package/docs/nexus-state-overview.md +0 -170
- package/docs/nexus-tools-contract.md +0 -438
- package/manifest.json +0 -448
- package/schema/README.md +0 -69
- package/schema/agent.schema.json +0 -23
- package/schema/common.schema.json +0 -17
- package/schema/manifest.schema.json +0 -78
- package/schema/memory-policy.schema.json +0 -98
- package/schema/skill.schema.json +0 -54
- package/schema/task-exceptions.schema.json +0 -40
- package/schema/vocabulary.schema.json +0 -167
- package/scripts/.gitkeep +0 -0
- package/scripts/conformance-coverage.ts +0 -466
- package/scripts/import-from-claude-nexus.ts +0 -403
- package/scripts/lib/frontmatter.ts +0 -71
- package/scripts/lib/lint.ts +0 -348
- package/scripts/lib/structure.ts +0 -159
- package/scripts/lib/validate.ts +0 -796
- package/scripts/validate.ts +0 -90
- package/skills/nx-init/meta.yml +0 -8
- package/skills/nx-plan/meta.yml +0 -10
- package/skills/nx-run/meta.yml +0 -8
- package/skills/nx-sync/meta.yml +0 -7
- package/vocabulary/capabilities.yml +0 -65
- package/vocabulary/categories.yml +0 -11
- package/vocabulary/invocations.yml +0 -147
- package/vocabulary/memory_policy.yml +0 -88
- package/vocabulary/resume-tiers.yml +0 -11
- package/vocabulary/tags.yml +0 -60
- package/vocabulary/task-exceptions.yml +0 -29
package/scripts/cli.ts
ADDED
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* scripts/cli.ts
|
|
4
|
+
*
|
|
5
|
+
* nexus-core CLI — subcommand dispatcher.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* nexus-core <command> [flags]
|
|
9
|
+
* bun run scripts/cli.ts <command> [flags]
|
|
10
|
+
*
|
|
11
|
+
* Commands:
|
|
12
|
+
* sync Build agents + hooks (build-agents + build-hooks pipeline)
|
|
13
|
+
* init Copy plugin template to a target directory
|
|
14
|
+
* list List agents, skills, and hooks from assets/
|
|
15
|
+
* validate Validate frontmatter and YAML assets
|
|
16
|
+
* mcp Start the MCP stdio server (same as nexus-mcp)
|
|
17
|
+
*
|
|
18
|
+
* Flags:
|
|
19
|
+
* --help, -h Show help for the current command
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
23
|
+
import { join, resolve, dirname } from "node:path";
|
|
24
|
+
import { fileURLToPath } from "node:url";
|
|
25
|
+
import { parse as parseYaml } from "yaml";
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Constants
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
32
|
+
export const ROOT = resolve(__dirname, "..");
|
|
33
|
+
export const ASSETS_DIR = join(ROOT, "assets");
|
|
34
|
+
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Parsed flags helpers
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
export interface ParsedFlags {
|
|
40
|
+
harness?: string;
|
|
41
|
+
target?: string;
|
|
42
|
+
dryRun: boolean;
|
|
43
|
+
force: boolean;
|
|
44
|
+
strict: boolean;
|
|
45
|
+
only?: string;
|
|
46
|
+
help: boolean;
|
|
47
|
+
remaining: string[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function parseFlags(argv: string[]): ParsedFlags {
|
|
51
|
+
const flags: ParsedFlags = {
|
|
52
|
+
dryRun: false,
|
|
53
|
+
force: false,
|
|
54
|
+
strict: false,
|
|
55
|
+
help: false,
|
|
56
|
+
remaining: [],
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
for (const arg of argv) {
|
|
60
|
+
if (arg === "--help" || arg === "-h") {
|
|
61
|
+
flags.help = true;
|
|
62
|
+
} else if (arg.startsWith("--harness=")) {
|
|
63
|
+
flags.harness = arg.slice("--harness=".length);
|
|
64
|
+
} else if (arg.startsWith("--target=")) {
|
|
65
|
+
flags.target = resolve(arg.slice("--target=".length));
|
|
66
|
+
} else if (arg === "--dry-run") {
|
|
67
|
+
flags.dryRun = true;
|
|
68
|
+
} else if (arg === "--force") {
|
|
69
|
+
flags.force = true;
|
|
70
|
+
} else if (arg === "--strict") {
|
|
71
|
+
flags.strict = true;
|
|
72
|
+
} else if (arg.startsWith("--only=")) {
|
|
73
|
+
flags.only = arg.slice("--only=".length);
|
|
74
|
+
} else {
|
|
75
|
+
flags.remaining.push(arg);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return flags;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
// Help messages
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
|
|
86
|
+
const HELP_MAIN = `
|
|
87
|
+
nexus-core — Nexus ecosystem CLI
|
|
88
|
+
|
|
89
|
+
Usage:
|
|
90
|
+
nexus-core <command> [flags]
|
|
91
|
+
|
|
92
|
+
Commands:
|
|
93
|
+
sync Build agents + hooks (runs build-agents + build-hooks pipelines)
|
|
94
|
+
init Copy plugin template to a target directory
|
|
95
|
+
list List agents, skills, and hooks from assets/
|
|
96
|
+
validate Validate frontmatter and YAML assets
|
|
97
|
+
mcp Start the MCP stdio server (same as nexus-mcp)
|
|
98
|
+
|
|
99
|
+
Flags:
|
|
100
|
+
--help, -h Show help for the current command
|
|
101
|
+
|
|
102
|
+
Run \`nexus-core <command> --help\` for command-specific flags.
|
|
103
|
+
`.trim();
|
|
104
|
+
|
|
105
|
+
const HELP_SYNC = `
|
|
106
|
+
nexus-core sync — Build agents + hooks
|
|
107
|
+
|
|
108
|
+
Usage:
|
|
109
|
+
nexus-core sync [flags]
|
|
110
|
+
|
|
111
|
+
Flags:
|
|
112
|
+
--harness=<claude|opencode|codex> Restrict to one harness (default: all)
|
|
113
|
+
--target=<dir> Output directory (default: dist/)
|
|
114
|
+
--dry-run Print affected files, no writes
|
|
115
|
+
--force Force template file overwrite
|
|
116
|
+
--strict Error if managed output has untracked modifications
|
|
117
|
+
--only=<name> Restrict to a single agent or skill name
|
|
118
|
+
`.trim();
|
|
119
|
+
|
|
120
|
+
const HELP_INIT = `
|
|
121
|
+
nexus-core init — Copy plugin template to target directory
|
|
122
|
+
|
|
123
|
+
Usage:
|
|
124
|
+
nexus-core init [flags]
|
|
125
|
+
|
|
126
|
+
Flags:
|
|
127
|
+
--harness=<claude|opencode|codex> Harness template to copy (default: claude)
|
|
128
|
+
--target=<dir> Destination directory (required)
|
|
129
|
+
`.trim();
|
|
130
|
+
|
|
131
|
+
const HELP_LIST = `
|
|
132
|
+
nexus-core list — List assets from assets/
|
|
133
|
+
|
|
134
|
+
Usage:
|
|
135
|
+
nexus-core list [flags]
|
|
136
|
+
|
|
137
|
+
Flags:
|
|
138
|
+
(none currently)
|
|
139
|
+
|
|
140
|
+
Prints agents, skills, and hooks with their descriptions.
|
|
141
|
+
`.trim();
|
|
142
|
+
|
|
143
|
+
const HELP_VALIDATE = `
|
|
144
|
+
nexus-core validate — Validate frontmatter and YAML assets
|
|
145
|
+
|
|
146
|
+
Usage:
|
|
147
|
+
nexus-core validate [flags]
|
|
148
|
+
|
|
149
|
+
Flags:
|
|
150
|
+
(none currently)
|
|
151
|
+
|
|
152
|
+
Validates:
|
|
153
|
+
- assets/agents/*/body.md frontmatter (required fields: id, name, category, model_tier)
|
|
154
|
+
- assets/skills/*/body.md frontmatter (required fields: id, name)
|
|
155
|
+
- assets/capability-matrix.yml YAML parse
|
|
156
|
+
- assets/tools/tool-name-map.yml YAML parse
|
|
157
|
+
`.trim();
|
|
158
|
+
|
|
159
|
+
const HELP_MCP = `
|
|
160
|
+
nexus-core mcp — Start the MCP stdio server
|
|
161
|
+
|
|
162
|
+
Usage:
|
|
163
|
+
nexus-core mcp
|
|
164
|
+
|
|
165
|
+
Starts the nexus-core MCP server on stdio. Equivalent to running nexus-mcp directly.
|
|
166
|
+
`.trim();
|
|
167
|
+
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
// Subcommand: sync
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
|
|
172
|
+
export async function runSync(argv: string[]): Promise<void> {
|
|
173
|
+
const flags = parseFlags(argv);
|
|
174
|
+
|
|
175
|
+
if (flags.help) {
|
|
176
|
+
console.log(HELP_SYNC);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Build argv for build-agents: reconstruct flags as process.argv-style
|
|
181
|
+
// build-agents.parseArgs expects process.argv (slices [2:])
|
|
182
|
+
const fakeArgv = ["node", "build-agents.ts"];
|
|
183
|
+
if (flags.harness) fakeArgv.push(`--harness=${flags.harness}`);
|
|
184
|
+
if (flags.target) fakeArgv.push(`--target=${flags.target}`);
|
|
185
|
+
if (flags.dryRun) fakeArgv.push("--dry-run");
|
|
186
|
+
if (flags.force) fakeArgv.push("--force");
|
|
187
|
+
if (flags.strict) fakeArgv.push("--strict");
|
|
188
|
+
if (flags.only) fakeArgv.push(`--only=${flags.only}`);
|
|
189
|
+
|
|
190
|
+
const { buildAgents, parseArgs: parseAgentArgs } = await import("./build-agents.js");
|
|
191
|
+
|
|
192
|
+
const agentOpts = parseAgentArgs(fakeArgv);
|
|
193
|
+
await buildAgents(agentOpts);
|
|
194
|
+
|
|
195
|
+
if (flags.dryRun) {
|
|
196
|
+
console.log(`[nexus-core sync] --dry-run: skipping buildHooks (no writes)`);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const { buildHooks } = await import("./build-hooks.js");
|
|
201
|
+
await buildHooks();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ---------------------------------------------------------------------------
|
|
205
|
+
// Subcommand: init
|
|
206
|
+
// ---------------------------------------------------------------------------
|
|
207
|
+
|
|
208
|
+
export async function runInit(argv: string[]): Promise<void> {
|
|
209
|
+
const flags = parseFlags(argv);
|
|
210
|
+
|
|
211
|
+
if (flags.help) {
|
|
212
|
+
console.log(HELP_INIT);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const harness = flags.harness ?? "claude";
|
|
217
|
+
const target = flags.target;
|
|
218
|
+
|
|
219
|
+
if (!target) {
|
|
220
|
+
process.stderr.write(`[nexus-core init] --target=<dir> is required\n`);
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const templateDir = join(ROOT, "docs", "plugin-template", harness);
|
|
225
|
+
|
|
226
|
+
if (!existsSync(templateDir)) {
|
|
227
|
+
process.stderr.write(
|
|
228
|
+
`[nexus-core init] Template not yet available for harness "${harness}".\n` +
|
|
229
|
+
` Expected path: ${templateDir}\n` +
|
|
230
|
+
` Templates are generated by the T5 phase. Use "nexus-core sync" to build dist/ first.\n`,
|
|
231
|
+
);
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Copy template directory to target using recursive copy
|
|
236
|
+
const { cpSync } = await import("node:fs");
|
|
237
|
+
cpSync(templateDir, target, { recursive: true });
|
|
238
|
+
console.log(`[nexus-core init] Initialized ${harness} plugin template → ${target}`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ---------------------------------------------------------------------------
|
|
242
|
+
// Frontmatter parsing (lightweight, no dependency on build-agents)
|
|
243
|
+
// ---------------------------------------------------------------------------
|
|
244
|
+
|
|
245
|
+
const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/;
|
|
246
|
+
|
|
247
|
+
function parseFrontmatterRaw(raw: string): Record<string, unknown> | null {
|
|
248
|
+
const match = FRONTMATTER_RE.exec(raw);
|
|
249
|
+
if (!match) return null;
|
|
250
|
+
try {
|
|
251
|
+
return parseYaml(match[1]!) as Record<string, unknown>;
|
|
252
|
+
} catch {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// ---------------------------------------------------------------------------
|
|
258
|
+
// Subcommand: list
|
|
259
|
+
// ---------------------------------------------------------------------------
|
|
260
|
+
|
|
261
|
+
interface ListEntry {
|
|
262
|
+
kind: "agent" | "skill" | "hook";
|
|
263
|
+
name: string;
|
|
264
|
+
description: string;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export function collectListEntries(): ListEntry[] {
|
|
268
|
+
const entries: ListEntry[] = [];
|
|
269
|
+
|
|
270
|
+
// Agents
|
|
271
|
+
const agentsDir = join(ASSETS_DIR, "agents");
|
|
272
|
+
if (existsSync(agentsDir)) {
|
|
273
|
+
for (const entry of readdirSync(agentsDir, { withFileTypes: true })) {
|
|
274
|
+
if (!entry.isDirectory()) continue;
|
|
275
|
+
const bodyPath = join(agentsDir, entry.name, "body.md");
|
|
276
|
+
if (!existsSync(bodyPath)) continue;
|
|
277
|
+
const fm = parseFrontmatterRaw(readFileSync(bodyPath, "utf-8"));
|
|
278
|
+
entries.push({
|
|
279
|
+
kind: "agent",
|
|
280
|
+
name: entry.name,
|
|
281
|
+
description: typeof fm?.description === "string" ? fm.description : "",
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Skills
|
|
287
|
+
const skillsDir = join(ASSETS_DIR, "skills");
|
|
288
|
+
if (existsSync(skillsDir)) {
|
|
289
|
+
for (const entry of readdirSync(skillsDir, { withFileTypes: true })) {
|
|
290
|
+
if (!entry.isDirectory()) continue;
|
|
291
|
+
const bodyPath = join(skillsDir, entry.name, "body.md");
|
|
292
|
+
if (!existsSync(bodyPath)) continue;
|
|
293
|
+
const fm = parseFrontmatterRaw(readFileSync(bodyPath, "utf-8"));
|
|
294
|
+
entries.push({
|
|
295
|
+
kind: "skill",
|
|
296
|
+
name: entry.name,
|
|
297
|
+
description: typeof fm?.description === "string" ? fm.description : "",
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Hooks
|
|
303
|
+
const hooksDir = join(ASSETS_DIR, "hooks");
|
|
304
|
+
if (existsSync(hooksDir)) {
|
|
305
|
+
for (const entry of readdirSync(hooksDir, { withFileTypes: true })) {
|
|
306
|
+
if (!entry.isDirectory()) continue;
|
|
307
|
+
const metaPath = join(hooksDir, entry.name, "meta.yml");
|
|
308
|
+
if (!existsSync(metaPath)) continue;
|
|
309
|
+
let description = "";
|
|
310
|
+
try {
|
|
311
|
+
const meta = parseYaml(readFileSync(metaPath, "utf-8")) as Record<string, unknown>;
|
|
312
|
+
description = typeof meta?.description === "string" ? meta.description : "";
|
|
313
|
+
} catch {
|
|
314
|
+
// ignore parse errors in list
|
|
315
|
+
}
|
|
316
|
+
entries.push({ kind: "hook", name: entry.name, description });
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return entries;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export async function runList(argv: string[]): Promise<void> {
|
|
324
|
+
const flags = parseFlags(argv);
|
|
325
|
+
|
|
326
|
+
if (flags.help) {
|
|
327
|
+
console.log(HELP_LIST);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const entries = collectListEntries();
|
|
332
|
+
const agents = entries.filter((e) => e.kind === "agent");
|
|
333
|
+
const skills = entries.filter((e) => e.kind === "skill");
|
|
334
|
+
const hooks = entries.filter((e) => e.kind === "hook");
|
|
335
|
+
|
|
336
|
+
console.log(`Agents (${agents.length}):`);
|
|
337
|
+
for (const e of agents) {
|
|
338
|
+
console.log(` ${e.name.padEnd(20)} ${e.description}`);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
console.log(`\nSkills (${skills.length}):`);
|
|
342
|
+
for (const e of skills) {
|
|
343
|
+
console.log(` ${e.name.padEnd(20)} ${e.description}`);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
console.log(`\nHooks (${hooks.length}):`);
|
|
347
|
+
for (const e of hooks) {
|
|
348
|
+
console.log(` ${e.name.padEnd(20)} ${e.description}`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// ---------------------------------------------------------------------------
|
|
353
|
+
// Subcommand: validate
|
|
354
|
+
// ---------------------------------------------------------------------------
|
|
355
|
+
|
|
356
|
+
export interface ValidationResult {
|
|
357
|
+
ok: boolean;
|
|
358
|
+
errors: string[];
|
|
359
|
+
warnings: string[];
|
|
360
|
+
checked: number;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export function runValidateSync(): ValidationResult {
|
|
364
|
+
const errors: string[] = [];
|
|
365
|
+
const warnings: string[] = [];
|
|
366
|
+
let checked = 0;
|
|
367
|
+
|
|
368
|
+
// Validate agents
|
|
369
|
+
const agentsDir = join(ASSETS_DIR, "agents");
|
|
370
|
+
if (existsSync(agentsDir)) {
|
|
371
|
+
for (const entry of readdirSync(agentsDir, { withFileTypes: true })) {
|
|
372
|
+
if (!entry.isDirectory()) continue;
|
|
373
|
+
const bodyPath = join(agentsDir, entry.name, "body.md");
|
|
374
|
+
if (!existsSync(bodyPath)) {
|
|
375
|
+
errors.push(`agents/${entry.name}: missing body.md`);
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
checked++;
|
|
379
|
+
const raw = readFileSync(bodyPath, "utf-8");
|
|
380
|
+
const fm = parseFrontmatterRaw(raw);
|
|
381
|
+
if (!fm) {
|
|
382
|
+
errors.push(`agents/${entry.name}/body.md: missing or malformed frontmatter`);
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
for (const field of ["id", "name", "category", "model_tier"] as const) {
|
|
386
|
+
if (!fm[field]) {
|
|
387
|
+
errors.push(`agents/${entry.name}/body.md: missing required field "${field}"`);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Validate skills
|
|
394
|
+
const skillsDir = join(ASSETS_DIR, "skills");
|
|
395
|
+
if (existsSync(skillsDir)) {
|
|
396
|
+
for (const entry of readdirSync(skillsDir, { withFileTypes: true })) {
|
|
397
|
+
if (!entry.isDirectory()) continue;
|
|
398
|
+
const bodyPath = join(skillsDir, entry.name, "body.md");
|
|
399
|
+
if (!existsSync(bodyPath)) {
|
|
400
|
+
errors.push(`skills/${entry.name}: missing body.md`);
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
checked++;
|
|
404
|
+
const raw = readFileSync(bodyPath, "utf-8");
|
|
405
|
+
const fm = parseFrontmatterRaw(raw);
|
|
406
|
+
if (!fm) {
|
|
407
|
+
errors.push(`skills/${entry.name}/body.md: missing or malformed frontmatter`);
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
for (const field of ["id", "name"] as const) {
|
|
411
|
+
if (!fm[field]) {
|
|
412
|
+
errors.push(`skills/${entry.name}/body.md: missing required field "${field}"`);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Validate capability-matrix.yml
|
|
419
|
+
const capMatrixPath = join(ASSETS_DIR, "capability-matrix.yml");
|
|
420
|
+
if (!existsSync(capMatrixPath)) {
|
|
421
|
+
warnings.push(`capability-matrix.yml: not found at ${capMatrixPath}`);
|
|
422
|
+
} else {
|
|
423
|
+
checked++;
|
|
424
|
+
try {
|
|
425
|
+
const parsed = parseYaml(readFileSync(capMatrixPath, "utf-8")) as Record<string, unknown>;
|
|
426
|
+
if (!parsed?.capabilities) {
|
|
427
|
+
errors.push(`capability-matrix.yml: missing 'capabilities' top-level key`);
|
|
428
|
+
}
|
|
429
|
+
} catch (err) {
|
|
430
|
+
errors.push(`capability-matrix.yml: YAML parse error — ${String(err)}`);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Validate tools/tool-name-map.yml
|
|
435
|
+
const toolMapPath = join(ASSETS_DIR, "tools", "tool-name-map.yml");
|
|
436
|
+
if (!existsSync(toolMapPath)) {
|
|
437
|
+
warnings.push(`tool-name-map.yml: not found at ${toolMapPath}`);
|
|
438
|
+
} else {
|
|
439
|
+
checked++;
|
|
440
|
+
try {
|
|
441
|
+
const parsed = parseYaml(readFileSync(toolMapPath, "utf-8")) as Record<string, unknown>;
|
|
442
|
+
if (!parsed?.tools && !parsed?.invocations) {
|
|
443
|
+
warnings.push(`tool-name-map.yml: neither 'tools' nor 'invocations' top-level key found`);
|
|
444
|
+
}
|
|
445
|
+
} catch (err) {
|
|
446
|
+
errors.push(`tool-name-map.yml: YAML parse error — ${String(err)}`);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return { ok: errors.length === 0, errors, warnings, checked };
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
export async function runValidate(argv: string[]): Promise<void> {
|
|
454
|
+
const flags = parseFlags(argv);
|
|
455
|
+
|
|
456
|
+
if (flags.help) {
|
|
457
|
+
console.log(HELP_VALIDATE);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const result = runValidateSync();
|
|
462
|
+
|
|
463
|
+
console.log(`[nexus-core validate] Checked ${result.checked} assets`);
|
|
464
|
+
|
|
465
|
+
for (const w of result.warnings) {
|
|
466
|
+
process.stderr.write(` WARN ${w}\n`);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (result.ok) {
|
|
470
|
+
console.log(` OK — no errors found`);
|
|
471
|
+
} else {
|
|
472
|
+
for (const e of result.errors) {
|
|
473
|
+
process.stderr.write(` ERROR ${e}\n`);
|
|
474
|
+
}
|
|
475
|
+
process.stderr.write(`[nexus-core validate] ${result.errors.length} error(s) found\n`);
|
|
476
|
+
process.exit(1);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// ---------------------------------------------------------------------------
|
|
481
|
+
// Subcommand: mcp
|
|
482
|
+
// ---------------------------------------------------------------------------
|
|
483
|
+
|
|
484
|
+
export async function runMcp(argv: string[]): Promise<void> {
|
|
485
|
+
const flags = parseFlags(argv);
|
|
486
|
+
|
|
487
|
+
if (flags.help) {
|
|
488
|
+
console.log(HELP_MCP);
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Forward to MCP server main()
|
|
493
|
+
const { main } = await import("../src/mcp/server.js");
|
|
494
|
+
await main();
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// ---------------------------------------------------------------------------
|
|
498
|
+
// Main dispatcher
|
|
499
|
+
// ---------------------------------------------------------------------------
|
|
500
|
+
|
|
501
|
+
export async function main(argv: string[]): Promise<void> {
|
|
502
|
+
const cmd = argv[0];
|
|
503
|
+
const rest = argv.slice(1);
|
|
504
|
+
|
|
505
|
+
switch (cmd) {
|
|
506
|
+
case "sync":
|
|
507
|
+
return runSync(rest);
|
|
508
|
+
|
|
509
|
+
case "init":
|
|
510
|
+
return runInit(rest);
|
|
511
|
+
|
|
512
|
+
case "list":
|
|
513
|
+
return runList(rest);
|
|
514
|
+
|
|
515
|
+
case "validate":
|
|
516
|
+
return runValidate(rest);
|
|
517
|
+
|
|
518
|
+
case "mcp":
|
|
519
|
+
return runMcp(rest);
|
|
520
|
+
|
|
521
|
+
case "--help":
|
|
522
|
+
case "-h":
|
|
523
|
+
case undefined:
|
|
524
|
+
console.log(HELP_MAIN);
|
|
525
|
+
return;
|
|
526
|
+
|
|
527
|
+
default:
|
|
528
|
+
process.stderr.write(`[nexus-core] Unknown command: ${cmd}\n`);
|
|
529
|
+
process.stderr.write(`Run \`nexus-core --help\` for available commands.\n`);
|
|
530
|
+
process.exit(1);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// ---------------------------------------------------------------------------
|
|
535
|
+
// Direct execution
|
|
536
|
+
// ---------------------------------------------------------------------------
|
|
537
|
+
|
|
538
|
+
if (
|
|
539
|
+
import.meta.url === `file://${process.argv[1]}` ||
|
|
540
|
+
process.argv[1]?.endsWith("cli.ts") ||
|
|
541
|
+
process.argv[1]?.endsWith("cli.js")
|
|
542
|
+
) {
|
|
543
|
+
main(process.argv.slice(2)).catch((err: unknown) => {
|
|
544
|
+
process.stderr.write(`[nexus-core] FATAL: ${String(err)}\n`);
|
|
545
|
+
process.exit(1);
|
|
546
|
+
});
|
|
547
|
+
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
name: architect
|
|
2
|
-
description: Technical design — evaluates How, reviews architecture, advises on
|
|
3
|
-
implementation approach
|
|
4
|
-
task: Architecture, technical design, code review
|
|
5
|
-
alias_ko: 아키텍트
|
|
6
|
-
category: how
|
|
7
|
-
resume_tier: persistent
|
|
8
|
-
model_tier: high
|
|
9
|
-
capabilities:
|
|
10
|
-
- no_file_edit
|
|
11
|
-
- no_task_create
|
|
12
|
-
- no_task_update
|
|
13
|
-
id: architect
|
package/agents/designer/meta.yml
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
name: designer
|
|
2
|
-
description: UX/UI design — evaluates user experience, interaction patterns, and
|
|
3
|
-
how users will experience the product
|
|
4
|
-
task: UI/UX design, interaction patterns, user experience
|
|
5
|
-
alias_ko: 디자이너
|
|
6
|
-
category: how
|
|
7
|
-
resume_tier: persistent
|
|
8
|
-
model_tier: high
|
|
9
|
-
capabilities:
|
|
10
|
-
- no_file_edit
|
|
11
|
-
- no_task_create
|
|
12
|
-
- no_task_update
|
|
13
|
-
id: designer
|
package/agents/engineer/meta.yml
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
name: engineer
|
|
2
|
-
description: Implementation — writes code, debugs issues, follows specifications
|
|
3
|
-
from Lead and architect
|
|
4
|
-
task: Code implementation, edits, debugging
|
|
5
|
-
alias_ko: 엔지니어
|
|
6
|
-
category: do
|
|
7
|
-
resume_tier: bounded
|
|
8
|
-
model_tier: standard
|
|
9
|
-
capabilities:
|
|
10
|
-
- no_task_create
|
|
11
|
-
id: engineer
|
package/agents/postdoc/meta.yml
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
name: postdoc
|
|
2
|
-
description: Research methodology and synthesis — designs investigation
|
|
3
|
-
approach, evaluates evidence quality, writes synthesis documents
|
|
4
|
-
task: Research methodology, evidence synthesis
|
|
5
|
-
alias_ko: 포닥
|
|
6
|
-
category: how
|
|
7
|
-
resume_tier: persistent
|
|
8
|
-
model_tier: high
|
|
9
|
-
capabilities:
|
|
10
|
-
- no_file_edit
|
|
11
|
-
- no_task_create
|
|
12
|
-
- no_task_update
|
|
13
|
-
id: postdoc
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
name: researcher
|
|
2
|
-
description: Independent investigation — conducts web searches, gathers
|
|
3
|
-
evidence, and reports findings with citations
|
|
4
|
-
task: Web search, independent investigation
|
|
5
|
-
alias_ko: 리서처
|
|
6
|
-
category: do
|
|
7
|
-
resume_tier: persistent
|
|
8
|
-
model_tier: standard
|
|
9
|
-
capabilities:
|
|
10
|
-
- no_file_edit
|
|
11
|
-
- no_task_create
|
|
12
|
-
id: researcher
|
package/agents/reviewer/meta.yml
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
name: reviewer
|
|
2
|
-
description: Content verification — validates accuracy, checks facts, confirms
|
|
3
|
-
grammar and format of non-code deliverables
|
|
4
|
-
task: Content verification, fact-checking, grammar review
|
|
5
|
-
alias_ko: 리뷰어
|
|
6
|
-
category: check
|
|
7
|
-
resume_tier: ephemeral
|
|
8
|
-
model_tier: standard
|
|
9
|
-
capabilities:
|
|
10
|
-
- no_file_edit
|
|
11
|
-
- no_task_create
|
|
12
|
-
id: reviewer
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
name: strategist
|
|
2
|
-
description: Business strategy — evaluates market positioning, competitive
|
|
3
|
-
landscape, and business viability of decisions
|
|
4
|
-
task: Business strategy, market analysis, competitive positioning
|
|
5
|
-
alias_ko: 전략가
|
|
6
|
-
category: how
|
|
7
|
-
resume_tier: persistent
|
|
8
|
-
model_tier: high
|
|
9
|
-
capabilities:
|
|
10
|
-
- no_file_edit
|
|
11
|
-
- no_task_create
|
|
12
|
-
- no_task_update
|
|
13
|
-
id: strategist
|
package/agents/tester/meta.yml
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
name: tester
|
|
2
|
-
description: Testing and verification — tests, verifies, validates stability and
|
|
3
|
-
security of implementations
|
|
4
|
-
task: Testing, verification, security review
|
|
5
|
-
alias_ko: 테스터
|
|
6
|
-
category: check
|
|
7
|
-
resume_tier: ephemeral
|
|
8
|
-
model_tier: standard
|
|
9
|
-
capabilities:
|
|
10
|
-
- no_file_edit
|
|
11
|
-
- no_task_create
|
|
12
|
-
id: tester
|
package/agents/writer/meta.yml
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
name: writer
|
|
2
|
-
description: Technical writing — transforms research findings, code, and
|
|
3
|
-
analysis into clear documents and presentations for the intended audience
|
|
4
|
-
task: Technical writing, documentation, presentations
|
|
5
|
-
alias_ko: 라이터
|
|
6
|
-
category: do
|
|
7
|
-
resume_tier: bounded
|
|
8
|
-
model_tier: standard
|
|
9
|
-
capabilities:
|
|
10
|
-
- no_task_create
|
|
11
|
-
id: writer
|