diff --git a/workflows/sense-generator/roles/coder/index.ts b/workflows/sense-generator/roles/coder/index.ts index 5c9966d..dc670a1 100644 --- a/workflows/sense-generator/roles/coder/index.ts +++ b/workflows/sense-generator/roles/coder/index.ts @@ -1,13 +1,8 @@ import { createCursorRole } from "@uncaged/nerve-workflow-utils"; -import { readFileSync } from "node:fs"; -import { join, dirname } from "node:path"; -import { fileURLToPath } from "node:url"; import { resolveDashScopeProvider, NERVE_ROOT, SENSES_DIR } from "../shared.js"; import { coderMetaSchema } from "../types.js"; import type { SenseMeta } from "../types.js"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const PROMPT = readFileSync(join(__dirname, "prompt.md"), "utf-8"); +import { coderPrompt } from "./prompt.js"; export async function buildCoderRole() { const provider = await resolveDashScopeProvider(); @@ -17,11 +12,7 @@ export async function buildCoderRole() { return createCursorRole({ cwd: NERVE_ROOT, mode: "default", - prompt: async (threadId) => - PROMPT - .replace("{{threadId}}", threadId) - .replace("{{sensesDir}}", SENSES_DIR) - .replace("{{nerveRoot}}", NERVE_ROOT), + prompt: async (threadId) => coderPrompt({ threadId, sensesDir: SENSES_DIR, nerveRoot: NERVE_ROOT }), extract: { provider, schema: coderMetaSchema }, }); } diff --git a/workflows/sense-generator/roles/coder/prompt.md b/workflows/sense-generator/roles/coder/prompt.md deleted file mode 100644 index b8ac1dd..0000000 --- a/workflows/sense-generator/roles/coder/prompt.md +++ /dev/null @@ -1,10 +0,0 @@ -Read the workflow thread for the planner's sense design: `nerve thread {{threadId}}` - -Implement the sense. Create exactly: -1. The sense directory under {{sensesDir}}// -2. index.js — export async function compute(db, _peers), import schema from "./schema.ts" -3. schema.ts — drizzle-orm/sqlite-core -4. migrations/0001_init.sql — must match schema.ts -5. Update {{nerveRoot}}/nerve.yaml — add sense config + reflex entry - -Follow the patterns from existing senses. Create all files now. diff --git a/workflows/sense-generator/roles/coder/prompt.ts b/workflows/sense-generator/roles/coder/prompt.ts new file mode 100644 index 0000000..676a10e --- /dev/null +++ b/workflows/sense-generator/roles/coder/prompt.ts @@ -0,0 +1,16 @@ +export function coderPrompt(vars: { + threadId: string; + sensesDir: string; + nerveRoot: string; +}): string { + return `Read the workflow thread for the planner's sense design: \`nerve thread ${vars.threadId}\` + +Implement the sense. Create exactly: +1. The sense directory under ${vars.sensesDir}// +2. index.js — export async function compute(db, _peers), import schema from "./schema.ts" +3. schema.ts — drizzle-orm/sqlite-core +4. migrations/0001_init.sql — must match schema.ts +5. Update ${vars.nerveRoot}/nerve.yaml — add sense config + reflex entry + +Follow the patterns from existing senses. Create all files now.`; +} diff --git a/workflows/sense-generator/roles/planner/index.ts b/workflows/sense-generator/roles/planner/index.ts index b52cb84..ae0ee0e 100644 --- a/workflows/sense-generator/roles/planner/index.ts +++ b/workflows/sense-generator/roles/planner/index.ts @@ -1,13 +1,9 @@ import { createCursorRole } from "@uncaged/nerve-workflow-utils"; -import { readFileSync } from "node:fs"; -import { join, dirname } from "node:path"; -import { fileURLToPath } from "node:url"; import { resolveDashScopeProvider, buildSenseExamples, getNerveYaml, NERVE_ROOT } from "../shared.js"; import { plannerMetaSchema } from "../types.js"; import type { SenseMeta } from "../types.js"; +import { plannerPrompt } from "./prompt.js"; -const __dirname = dirname(fileURLToPath(import.meta.url)); -const PROMPT = readFileSync(join(__dirname, "prompt.md"), "utf-8"); const senseExamples = buildSenseExamples(); const nerveYaml = getNerveYaml(); @@ -19,11 +15,7 @@ export async function buildPlannerRole() { return createCursorRole({ cwd: NERVE_ROOT, mode: "ask", - prompt: async (threadId) => - PROMPT - .replace("{{threadId}}", threadId) - .replace("{{senseExamples}}", senseExamples) - .replace("{{nerveYaml}}", nerveYaml), + prompt: async (threadId) => plannerPrompt({ threadId, senseExamples, nerveYaml }), extract: { provider, schema: plannerMetaSchema }, }); } diff --git a/workflows/sense-generator/roles/planner/prompt.md b/workflows/sense-generator/roles/planner/prompt.md deleted file mode 100644 index 434e6ef..0000000 --- a/workflows/sense-generator/roles/planner/prompt.md +++ /dev/null @@ -1,21 +0,0 @@ -You are planning a new Nerve sense. - -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: - -## Sense Design -### Name — kebab-case -### Fields — name, type (integer/real/text), description -### Compute Logic — step-by-step, specific Node.js APIs or shell commands -### Trigger Config — group, interval, throttle, timeout - -Reference senses: -{{senseExamples}} - -Current nerve.yaml: -```yaml -{{nerveYaml}} -``` - -Output ONLY the plan. Be precise and implementation-ready. diff --git a/workflows/sense-generator/roles/planner/prompt.ts b/workflows/sense-generator/roles/planner/prompt.ts new file mode 100644 index 0000000..d7a2bfb --- /dev/null +++ b/workflows/sense-generator/roles/planner/prompt.ts @@ -0,0 +1,27 @@ +export function plannerPrompt(vars: { + 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}\` + +Pick a good kebab-case name for this sense. Produce a PLAN (not code) in markdown: + +## Sense Design +### Name — kebab-case +### Fields — name, type (integer/real/text), description +### Compute Logic — step-by-step, specific Node.js APIs or shell commands +### Trigger Config — group, interval, throttle, timeout + +Reference senses: +${vars.senseExamples} + +Current nerve.yaml: +\`\`\`yaml +${vars.nerveYaml} +\`\`\` + +Output ONLY the plan. Be precise and implementation-ready.`; +}