fix: use effect.kind as fallback for effect type display
CI / test (push) Has been cancelled

This commit is contained in:
2026-04-17 21:26:15 +08:00
parent ba31086c30
commit 6e8b2b7ba6
14 changed files with 60 additions and 62 deletions
+4 -3
View File
@@ -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);
+12 -9
View File
@@ -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)`);
+1 -1
View File
@@ -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';
+11 -11
View File
@@ -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, '../../../..');
+6 -2
View File
@@ -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,
),
+1 -2
View File
@@ -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 {
+7 -7
View File
@@ -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(
+2 -9
View File
@@ -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;
+2 -2
View File
@@ -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,形成死循环
},
};