feat(cli): nerve init installs @uncaged/nerve-skills and generates agent hints #212
@@ -3,7 +3,7 @@
|
||||
* No running daemon needed — just temp dirs with HOME manipulation.
|
||||
*/
|
||||
|
||||
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
|
||||
@@ -209,6 +209,10 @@ describe("e2e init", () => {
|
||||
expect(existsSync(join(nerveRoot, "senses", "cpu-usage", "migrations", "0001_init.sql"))).toBe(
|
||||
true,
|
||||
);
|
||||
expect(existsSync(join(nerveRoot, ".cursor", "rules", "nerve-skills.mdc"))).toBe(true);
|
||||
|
||||
const pkgJson = readFileSync(join(nerveRoot, "package.json"), "utf8");
|
||||
expect(pkgJson).toContain('"@uncaged/nerve-skills": "latest"');
|
||||
});
|
||||
|
||||
it("generated nerve.yaml passes validate", { timeout: 10_000 }, async () => {
|
||||
|
||||
@@ -50,6 +50,7 @@ const PACKAGE_JSON = `{
|
||||
"dependencies": {
|
||||
"@uncaged/nerve-core": "latest",
|
||||
"@uncaged/nerve-daemon": "latest",
|
||||
"@uncaged/nerve-skills": "latest",
|
||||
"drizzle-orm": "latest"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -68,6 +69,35 @@ nerve.pid
|
||||
node_modules/
|
||||
`;
|
||||
|
||||
const NERVE_SKILLS_MDC = `---
|
||||
description: >-
|
||||
Nerve skills package — where bundled Agent Skills live in this workspace and how to use them
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Nerve skills (\`@uncaged/nerve-skills\`)
|
||||
|
||||
This workspace lists **@uncaged/nerve-skills** in \`package.json\`. It ships **Agent Skills** (one directory per skill, each with a \`SKILL.md\`) for Nerve development and related tasks.
|
||||
|
||||
## After install
|
||||
|
||||
Run your package manager in this workspace (e.g. \`pnpm install\`, \`npm install\` — whatever \`nerve init\` used). Then skills are on disk at:
|
||||
|
||||
- \`node_modules/@uncaged/nerve-skills/<skill-id>/SKILL.md\`
|
||||
|
||||
Example (current catalog):
|
||||
|
||||
- **nerve-dev** — Nerve architecture, CLI, sense/workflow patterns, \`nerve.yaml\`, and conventions: read \`node_modules/@uncaged/nerve-skills/nerve-dev/SKILL.md\`.
|
||||
|
||||
## How to use in an agent
|
||||
|
||||
1. For tasks that match a skill’s **description** (in the \`SKILL.md\` frontmatter), open that \`SKILL.md\` and follow its structure and checklists.
|
||||
2. Prefer the skill as the **source of truth** for Nerve-specific conventions over generic assumptions.
|
||||
3. If the catalog grows, new skills appear as new sibling directories under \`node_modules/@uncaged/nerve-skills/\`.
|
||||
|
||||
Do not commit \`node_modules\`; the dependency is the supported way to get and update skills to match \`@uncaged/nerve-skills\` on npm.
|
||||
`;
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
const CPU_SCHEMA_TS = `import { integer, real, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
||||
@@ -276,6 +306,7 @@ async function runInitWorkspace(force: boolean, skipInstall = false): Promise<vo
|
||||
join(nerveRoot, "senses", "cpu-usage", "migrations", "0001_init.sql"),
|
||||
CPU_MIGRATION_SQL,
|
||||
);
|
||||
writeFile(join(nerveRoot, ".cursor", "rules", "nerve-skills.mdc"), NERVE_SKILLS_MDC);
|
||||
|
||||
if (!skipInstall) {
|
||||
process.stdout.write("Installing dependencies…\n");
|
||||
|
||||
Reference in New Issue
Block a user