From fc2ca13dc3c3a9deb7a8b9768fe9bacec99c54bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Tue, 28 Apr 2026 04:38:33 +0000 Subject: [PATCH] refactor: remove buildSenseExamples, use @uncaged/nerve-skills for agent discovery - Delete buildSenseExamples() (~25 lines of runtime file reading) - Remove senseExamples from BuildSenseGeneratorDeps and BuildPlannerDeps - Planner prompt now directs agent to read nerve-dev skill via npm package - Clean up unused existsSync import Closes xiaoju/nerve-workspace#2 --- workflows/sense-generator/build.ts | 4 +-- workflows/sense-generator/index.ts | 29 +------------------ .../sense-generator/roles/planner/index.ts | 5 ++-- .../sense-generator/roles/planner/prompt.ts | 12 ++++---- 4 files changed, 10 insertions(+), 40 deletions(-) diff --git a/workflows/sense-generator/build.ts b/workflows/sense-generator/build.ts index e9f31c4..3ceb7c9 100644 --- a/workflows/sense-generator/build.ts +++ b/workflows/sense-generator/build.ts @@ -10,7 +10,6 @@ export type BuildSenseGeneratorDeps = { provider: LlmProvider; nerveRoot: string; sensesDir: string; - senseExamples: string; nerveYaml: string; }; @@ -18,13 +17,12 @@ export function buildSenseGenerator({ provider, nerveRoot, sensesDir, - senseExamples, nerveYaml, }: BuildSenseGeneratorDeps): WorkflowDefinition { return { name: "sense-generator", roles: { - planner: buildPlannerRole({ provider, cwd: nerveRoot, senseExamples, nerveYaml }), + planner: buildPlannerRole({ provider, cwd: nerveRoot, nerveYaml }), coder: buildCoderRole({ provider, cwd: nerveRoot, sensesDir, nerveRoot }), tester: buildTesterRole({ provider, sensesDir, nerveRoot }), }, diff --git a/workflows/sense-generator/index.ts b/workflows/sense-generator/index.ts index 49e0842..73ddd30 100644 --- a/workflows/sense-generator/index.ts +++ b/workflows/sense-generator/index.ts @@ -1,4 +1,4 @@ -import { existsSync, readFileSync } from "node:fs"; +import { readFileSync } from "node:fs"; import { join } from "node:path"; import { spawnSafe } from "@uncaged/nerve-workflow-utils"; import { buildSenseGenerator } from "./build.js"; @@ -38,39 +38,12 @@ function getNerveYaml(): string { } } -function buildSenseExamples(): string { - const examples: string[] = []; - for (const name of ["cpu-usage", "linux-system-health"]) { - const dir = join(SENSES_DIR, name); - if (!existsSync(dir)) continue; - const indexFile = existsSync(join(dir, "index.js")) - ? readFileSync(join(dir, "index.js"), "utf-8") - : ""; - const schema = existsSync(join(dir, "schema.ts")) - ? readFileSync(join(dir, "schema.ts"), "utf-8") - : ""; - const migrationDir = join(dir, "migrations"); - let migration = ""; - if (existsSync(join(migrationDir, "0001_init.sql"))) { - migration = readFileSync(join(migrationDir, "0001_init.sql"), "utf-8"); - } - examples.push( - `### Example sense: ${name}\n\n` + - `**index.js:**\n\`\`\`js\n${indexFile}\n\`\`\`\n\n` + - `**schema.ts:**\n\`\`\`ts\n${schema}\n\`\`\`\n\n` + - `**migrations/0001_init.sql:**\n\`\`\`sql\n${migration}\n\`\`\``, - ); - } - return examples.join("\n\n---\n\n"); -} - // --- Wire up --- const workflow = buildSenseGenerator({ provider: { apiKey, baseUrl, model }, nerveRoot: NERVE_ROOT, sensesDir: SENSES_DIR, - senseExamples: buildSenseExamples(), nerveYaml: getNerveYaml(), }); diff --git a/workflows/sense-generator/roles/planner/index.ts b/workflows/sense-generator/roles/planner/index.ts index 8734c07..9194821 100644 --- a/workflows/sense-generator/roles/planner/index.ts +++ b/workflows/sense-generator/roles/planner/index.ts @@ -7,15 +7,14 @@ import { plannerPrompt } from "./prompt.js"; export type BuildPlannerDeps = { provider: LlmProvider; cwd: string; - senseExamples: string; nerveYaml: string; }; -export function buildPlannerRole({ provider, cwd, senseExamples, nerveYaml }: BuildPlannerDeps) { +export function buildPlannerRole({ provider, cwd, nerveYaml }: BuildPlannerDeps) { return createCursorRole({ cwd, mode: "ask", - prompt: async (threadId) => plannerPrompt({ threadId, senseExamples, nerveYaml }), + prompt: async (threadId) => plannerPrompt({ threadId, nerveYaml }), extract: { provider, schema: plannerMetaSchema }, }); } diff --git a/workflows/sense-generator/roles/planner/prompt.ts b/workflows/sense-generator/roles/planner/prompt.ts index d7a2bfb..dcfe0ed 100644 --- a/workflows/sense-generator/roles/planner/prompt.ts +++ b/workflows/sense-generator/roles/planner/prompt.ts @@ -1,11 +1,10 @@ -export function plannerPrompt(vars: { +export function plannerPrompt({ threadId, nerveYaml }: { threadId: string; - senseExamples: string; nerveYaml: string; }): string { return `You are planning a new Nerve sense. -Read the workflow thread for the user's request: \`nerve thread ${vars.threadId}\` +Read the workflow thread for the user's request: \`nerve thread ${threadId}\` Pick a good kebab-case name for this sense. Produce a PLAN (not code) in markdown: @@ -15,12 +14,13 @@ Pick a good kebab-case name for this sense. Produce a PLAN (not code) in markdow ### Compute Logic — step-by-step, specific Node.js APIs or shell commands ### Trigger Config — group, interval, throttle, timeout -Reference senses: -${vars.senseExamples} +For reference examples of existing senses (schema, compute logic, migrations), read the nerve-dev skill: +\`cat node_modules/@uncaged/nerve-skills/nerve-dev/SKILL.md\` +Also look at existing senses in the \`senses/\` directory for patterns. Current nerve.yaml: \`\`\`yaml -${vars.nerveYaml} +${nerveYaml} \`\`\` Output ONLY the plan. Be precise and implementation-ready.`;