Following nerve-dev best practice: each role gets its own directory. Structure: index.ts — 31 lines (WorkflowDefinition + moderator) roles/planner/index.ts — 48 lines (createCursorRole) roles/coder/index.ts — 33 lines (createCursorRole) roles/tester/index.ts — 122 lines (hand-written smoke test) roles/shared.ts — 63 lines (providers, helpers) roles/types.ts — 5 lines (SenseMeta) Was: single 416-line index.ts Refs uncaged/nerve#210 小橘 🍊(NEKO Team)
64 lines
2.2 KiB
TypeScript
64 lines
2.2 KiB
TypeScript
import { spawnSafe } from "@uncaged/nerve-workflow-utils";
|
|
import { existsSync, readFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
|
|
export const HOME = process.env.HOME ?? "/home/azureuser";
|
|
export const NERVE_ROOT = join(HOME, ".uncaged-nerve");
|
|
export const SENSES_DIR = join(NERVE_ROOT, "senses");
|
|
|
|
export async function cfgGet(key: string): Promise<string | null> {
|
|
const result = await spawnSafe("cfg", ["get", key], {
|
|
cwd: NERVE_ROOT,
|
|
env: null,
|
|
timeoutMs: 10_000,
|
|
});
|
|
if (!result.ok) return null;
|
|
return result.value.stdout.trim() || null;
|
|
}
|
|
|
|
export async function resolveDashScopeProvider(): Promise<{
|
|
baseUrl: string;
|
|
apiKey: string;
|
|
model: string;
|
|
} | null> {
|
|
const apiKey = process.env.DASHSCOPE_API_KEY ?? (await cfgGet("DASHSCOPE_API_KEY"));
|
|
const baseUrl = process.env.DASHSCOPE_BASE_URL ?? (await cfgGet("DASHSCOPE_BASE_URL"));
|
|
const model = process.env.DASHSCOPE_MODEL ?? (await cfgGet("DASHSCOPE_MODEL")) ?? "qwen-plus";
|
|
if (!apiKey || !baseUrl) return null;
|
|
return { apiKey, baseUrl, model };
|
|
}
|
|
|
|
export function getNerveYaml(): string {
|
|
try {
|
|
return readFileSync(join(NERVE_ROOT, "nerve.yaml"), "utf-8");
|
|
} catch {
|
|
return "# nerve.yaml unavailable";
|
|
}
|
|
}
|
|
|
|
export 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");
|
|
}
|