This commit is contained in:
@@ -1,15 +1,16 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
/**
|
||||
* 向 Pulse Workflow Daemon 投递一个 meta workflow 任务。
|
||||
* 用法:bun run packages/pulse/src/bin/submit-task.ts <workflow> <topic-key> <task-file>
|
||||
*/
|
||||
|
||||
import { createStore } from '../store.js';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { homedir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { createStore } from '../store.js';
|
||||
|
||||
const [,, workflow, topicKey, taskFile] = process.argv;
|
||||
const [, , workflow, topicKey, taskFile] = process.argv;
|
||||
if (!workflow || !topicKey || !taskFile) {
|
||||
console.error('Usage: submit-task.ts <workflow> <topic-key> <task-file>');
|
||||
process.exit(1);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
/**
|
||||
* Pulse Workflow Daemon — 注册 workflow,定时 tick。
|
||||
*
|
||||
@@ -8,21 +9,21 @@
|
||||
* 小橘 🍊 (NEKO Team)
|
||||
*/
|
||||
|
||||
import { existsSync, mkdirSync } from 'node:fs';
|
||||
import { homedir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { createOpenAiLlmClient } from '../llm-client.js';
|
||||
import { createStore } from '../store.js';
|
||||
import { createWorkflowRule } from '../workflows/workflow-rule-adapter.js';
|
||||
import { createWorkflowTicker } from '../workflows/index.js';
|
||||
import { createCodingWorkflow } from '../workflows/coding.js';
|
||||
import { createWorkflowTicker } from '../workflows/index.js';
|
||||
import { createMetaWorkflow } from '../workflows/meta.js';
|
||||
import { createCursorRunner } from '../workflows/roles/agent-executor.js';
|
||||
import { createMetaArchitectRole } from '../workflows/roles/meta-architect-llm.js';
|
||||
import { createMetaCoderRole } from '../workflows/roles/meta-coder-cursor.js';
|
||||
import { createMetaPromoterRole } from '../workflows/roles/meta-promoter.js';
|
||||
import { createMetaReviewerRole } from '../workflows/roles/meta-reviewer-cursor.js';
|
||||
import { createMetaTesterRole } from '../workflows/roles/meta-tester.js';
|
||||
import { createMetaPromoterRole } from '../workflows/roles/meta-promoter.js';
|
||||
import { createCursorRunner } from '../workflows/roles/agent-executor.js';
|
||||
import { join } from 'node:path';
|
||||
import { mkdirSync, existsSync } from 'node:fs';
|
||||
import { homedir } from 'node:os';
|
||||
import { createWorkflowRule } from '../workflows/workflow-rule-adapter.js';
|
||||
|
||||
// ── Config ─────────────────────────────────────────────────────
|
||||
|
||||
@@ -68,7 +69,9 @@ const logStore = createStore({
|
||||
|
||||
// 1. Coding workflow (with mock roles for now)
|
||||
const codingWf = createCodingWorkflow();
|
||||
const codingRule = createWorkflowRule(codingWf, store, logStore, { cooldownMs: 0 });
|
||||
const codingRule = createWorkflowRule(codingWf, store, logStore, {
|
||||
cooldownMs: 0,
|
||||
});
|
||||
|
||||
// 2. Meta workflow (real LLM + Cursor roles)
|
||||
const metaWf = createMetaWorkflow({
|
||||
@@ -98,7 +101,7 @@ console.log('');
|
||||
// Initial tick
|
||||
const logTick = async () => {
|
||||
const before = Date.now();
|
||||
const result = await tick();
|
||||
const _result = await tick();
|
||||
const elapsed = Date.now() - before;
|
||||
const ts = new Date().toISOString().slice(11, 19);
|
||||
console.log(`[${ts}] tick done (${elapsed}ms)`);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* 小橘 🍊 (NEKO Team)
|
||||
*/
|
||||
|
||||
import { mkdtempSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import { mkdtempSync, readFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { createOpenAiLlmClient } from '../llm-client.js';
|
||||
|
||||
@@ -12,12 +12,6 @@ import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { createOpenAiLlmClient } from '../llm-client.js';
|
||||
import { createStore } from '../store.js';
|
||||
import type {
|
||||
MetaCoderMeta,
|
||||
MetaPromoterMeta,
|
||||
MetaReviewerMeta,
|
||||
MetaTesterMeta,
|
||||
} from '../workflows/meta.js';
|
||||
import { createMetaWorkflow } from '../workflows/meta.js';
|
||||
import { createMetaArchitectRole } from '../workflows/roles/meta-architect-llm.js';
|
||||
import { createWorkflowRule } from '../workflows/workflow-rule-adapter.js';
|
||||
|
||||
@@ -7,19 +7,19 @@
|
||||
* 小橘 🍊 (NEKO Team)
|
||||
*/
|
||||
|
||||
import { createOpenAiLlmClient } from '../llm-client.js';
|
||||
import { createStore } from '../store.js';
|
||||
import { createMetaArchitectRole } from '../workflows/roles/meta-architect-llm.js';
|
||||
import { createMetaCoderRole } from '../workflows/roles/meta-coder-cursor.js';
|
||||
import { createMetaReviewerRole } from '../workflows/roles/meta-reviewer-cursor.js';
|
||||
import { createMetaTesterRole } from '../workflows/roles/meta-tester.js';
|
||||
import { createMetaPromoterRole } from '../workflows/roles/meta-promoter.js';
|
||||
import { createCursorRunner } from '../workflows/roles/agent-executor.js';
|
||||
import { createWorkflowRule } from '../workflows/workflow-rule-adapter.js';
|
||||
import { createMetaWorkflow } from '../workflows/meta.js';
|
||||
import { readFileSync, mkdtempSync } from 'node:fs';
|
||||
import { mkdtempSync, readFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { createOpenAiLlmClient } from '../llm-client.js';
|
||||
import { createStore } from '../store.js';
|
||||
import { createMetaWorkflow } from '../workflows/meta.js';
|
||||
import { createCursorRunner } from '../workflows/roles/agent-executor.js';
|
||||
import { createMetaArchitectRole } from '../workflows/roles/meta-architect-llm.js';
|
||||
import { createMetaCoderRole } from '../workflows/roles/meta-coder-cursor.js';
|
||||
import { createMetaPromoterRole } from '../workflows/roles/meta-promoter.js';
|
||||
import { createMetaReviewerRole } from '../workflows/roles/meta-reviewer-cursor.js';
|
||||
import { createMetaTesterRole } from '../workflows/roles/meta-tester.js';
|
||||
import { createWorkflowRule } from '../workflows/workflow-rule-adapter.js';
|
||||
|
||||
const REPO_DIR = join(import.meta.dir, '../../../..');
|
||||
|
||||
|
||||
@@ -542,7 +542,9 @@ export async function runPulse<S extends { timestamp: number }, E>(options: {
|
||||
kind: 'effect',
|
||||
key: effectHash,
|
||||
hash: effectHash,
|
||||
meta: JSON.stringify({ type: (effect as any).type || 'unknown' }),
|
||||
meta: JSON.stringify({
|
||||
type: (effect as any).type || (effect as any).kind || 'unknown',
|
||||
}),
|
||||
codeRev,
|
||||
});
|
||||
}
|
||||
@@ -701,7 +703,9 @@ export async function runPulseV2<S extends { timestamp: number }, E>(options: {
|
||||
kind: 'effect',
|
||||
key: effectHash,
|
||||
hash: effectHash,
|
||||
meta: JSON.stringify({ type: (effect as any).type || 'unknown' }),
|
||||
meta: JSON.stringify({
|
||||
type: (effect as any).type || (effect as any).kind || 'unknown',
|
||||
}),
|
||||
codeRev,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -92,9 +92,7 @@ describe('coding-tdd WorkflowType', () => {
|
||||
|
||||
it('moderator: START → test-planner', () => {
|
||||
const wf = createTddCodingWorkflow();
|
||||
expect(wf.moderator({ role: START, meta: null }, 'x')).toBe(
|
||||
'test-planner',
|
||||
);
|
||||
expect(wf.moderator({ role: START, meta: null }, 'x')).toBe('test-planner');
|
||||
});
|
||||
|
||||
it('moderator: test-reviewer approved → test-coder', () => {
|
||||
@@ -111,7 +109,10 @@ describe('coding-tdd WorkflowType', () => {
|
||||
const wf = createTddCodingWorkflow();
|
||||
expect(
|
||||
wf.moderator(
|
||||
{ role: 'test-reviewer', meta: { verdict: 'rejected', feedback: 'no' } },
|
||||
{
|
||||
role: 'test-reviewer',
|
||||
meta: { verdict: 'rejected', feedback: 'no' },
|
||||
},
|
||||
'x',
|
||||
10,
|
||||
),
|
||||
@@ -122,7 +123,10 @@ describe('coding-tdd WorkflowType', () => {
|
||||
const wf = createTddCodingWorkflow();
|
||||
expect(
|
||||
wf.moderator(
|
||||
{ role: 'test-reviewer', meta: { verdict: 'rejected', feedback: 'no' } },
|
||||
{
|
||||
role: 'test-reviewer',
|
||||
meta: { verdict: 'rejected', feedback: 'no' },
|
||||
},
|
||||
'x',
|
||||
1,
|
||||
),
|
||||
|
||||
@@ -153,8 +153,7 @@ function tddCodingModerator(
|
||||
_topicId: string,
|
||||
remainingRounds?: number,
|
||||
): keyof TddCodingRoles | typeof END {
|
||||
const emergency =
|
||||
remainingRounds !== undefined && remainingRounds <= 1;
|
||||
const emergency = remainingRounds !== undefined && remainingRounds <= 1;
|
||||
|
||||
if (output.role === START) return 'test-planner';
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
*/
|
||||
|
||||
import { Database } from 'bun:sqlite';
|
||||
import { afterAll, beforeAll, describe, expect, test } from 'bun:test';
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
import { unlink } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { type CursorHealthResult, checkCursorHealth } from './cursor-health.js';
|
||||
import { checkCursorHealth } from './cursor-health.js';
|
||||
|
||||
describe('cursor-health', () => {
|
||||
function createTestDb(records: number[], baseTime = Date.now()): string {
|
||||
|
||||
@@ -71,17 +71,17 @@ import type { WorkflowRule } from './workflow-rule-adapter.js';
|
||||
* suitable for calling at the end of a runPulse tick cycle.
|
||||
*/
|
||||
export {
|
||||
createTddCodingWorkflow,
|
||||
type AutoTesterMeta,
|
||||
type CreateTddCodingWorkflowOpts,
|
||||
createTddCodingWorkflow,
|
||||
type ManualTesterMeta,
|
||||
type TddCloserMeta,
|
||||
type TddCoderMeta,
|
||||
type TddCodingRoles,
|
||||
type TddReviewerMeta,
|
||||
type TestCoderMeta,
|
||||
type TestPlannerMeta,
|
||||
type TestReviewerMeta,
|
||||
type TestCoderMeta,
|
||||
type TddCoderMeta,
|
||||
type AutoTesterMeta,
|
||||
type ManualTesterMeta,
|
||||
type TddReviewerMeta,
|
||||
type TddCloserMeta,
|
||||
} from './coding-tdd.js';
|
||||
|
||||
export function createWorkflowTicker(
|
||||
|
||||
@@ -8,16 +8,9 @@ import { mkdtempSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { createStore } from '../store.js';
|
||||
import {
|
||||
createMetaWorkflow,
|
||||
type MetaArchitectMeta,
|
||||
type MetaCoderMeta,
|
||||
type MetaPromoterMeta,
|
||||
type MetaReviewerMeta,
|
||||
type MetaTesterMeta,
|
||||
} from './meta.js';
|
||||
import { createMetaWorkflow } from './meta.js';
|
||||
import { createWorkflowRule } from './workflow-rule-adapter.js';
|
||||
import { END, START, type WorkflowMessage } from './workflow-type.js';
|
||||
import { END, START } from './workflow-type.js';
|
||||
|
||||
function mockStore() {
|
||||
const dir = mkdtempSync(join(tmpdir(), 'meta-wf-test-'));
|
||||
|
||||
@@ -42,7 +42,7 @@ export function createMetaTesterRole(
|
||||
opts: { repoDir: string },
|
||||
): Role<MetaTesterMeta> {
|
||||
return async (
|
||||
chain: WorkflowMessage[],
|
||||
_chain: WorkflowMessage[],
|
||||
): Promise<RoleResult<MetaTesterMeta>> => {
|
||||
// Step 1: Run build + test
|
||||
let testOutput: string;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* 小橘 🍊 (NEKO Team)
|
||||
*/
|
||||
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
|
||||
export interface ScaffoldOptions {
|
||||
@@ -49,7 +49,7 @@ export function scaffoldWorkflow(opts: ScaffoldOptions): string[] {
|
||||
|
||||
const moderatorCases = roles
|
||||
.map((r, i) => {
|
||||
const next = i < roles.length - 1 ? `'${roles[i + 1]}'` : 'END';
|
||||
const _next = i < roles.length - 1 ? `'${roles[i + 1]}'` : 'END';
|
||||
if (i === 0) return ` case START:\n return '${r}';`;
|
||||
return ` case '${roles[i - 1]}':\n return '${r}';`;
|
||||
})
|
||||
|
||||
@@ -299,7 +299,7 @@ describe('createWorkflowRule', () => {
|
||||
const loopType: WorkflowType<LoopRoles> = {
|
||||
name: 'loop',
|
||||
roles: {
|
||||
loop: async (chain) => {
|
||||
loop: async (_chain) => {
|
||||
execCount++;
|
||||
return {
|
||||
content: `Loop ${execCount}`,
|
||||
@@ -308,7 +308,7 @@ describe('createWorkflowRule', () => {
|
||||
},
|
||||
},
|
||||
// 无限循环的 moderator
|
||||
moderator: (output) => {
|
||||
moderator: (_output) => {
|
||||
return 'loop'; // 总是返回 loop,形成死循环
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user