feat: engine directory setup — independent bun package + ping-pong test
- package.json: file: link to pulse repo (not workspace:*) - .gitignore: node_modules + .pulse/ + dist/ - ping-pong workflow + test: validates engine can import pulse & run workflows - bun install: 9 packages via hardlink Ref: pulse#3
This commit is contained in:
parent
d81bbe223b
commit
a2b6731aa5
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules/
|
||||
.pulse/
|
||||
dist/
|
||||
35
bun.lock
Normal file
35
bun.lock
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "@upulse/engine",
|
||||
"dependencies": {
|
||||
"@uncaged/pulse": "file:../../repos/pulse/packages/pulse",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.2.0",
|
||||
"typescript": "^5.8.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@types/bun": ["@types/bun@1.3.12", "", { "dependencies": { "bun-types": "1.3.12" } }, "sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A=="],
|
||||
|
||||
"@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
|
||||
|
||||
"@uncaged/pulse": ["@uncaged/pulse@file:../../repos/pulse/packages/pulse", { "dependencies": { "jsonata": "^2.1.0", "zod": "^4.3.6" }, "devDependencies": { "@types/node": "^25.6.0", "bun-types": "latest", "typescript": "^6.0.2" } }],
|
||||
|
||||
"bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="],
|
||||
|
||||
"jsonata": ["jsonata@2.1.0", "", {}, "sha512-OCzaRMK8HobtX8fp37uIVmL8CY1IGc/a6gLsDqz3quExFR09/U78HUzWYr7T31UEB6+Eu0/8dkVD5fFDOl9a8w=="],
|
||||
|
||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
|
||||
|
||||
"zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
|
||||
|
||||
"@uncaged/pulse/typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="],
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,7 @@
|
||||
"test": "bun test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@uncaged/pulse": "workspace:*"
|
||||
"@uncaged/pulse": "file:../../repos/pulse/packages/pulse"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.8.0",
|
||||
|
||||
49
src/workflows/ping-pong.test.ts
Normal file
49
src/workflows/ping-pong.test.ts
Normal file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* ping-pong workflow test — validates engine can run workflows.
|
||||
*
|
||||
* 小橘 🍊 (NEKO Team)
|
||||
*/
|
||||
|
||||
import { afterEach, describe, expect, it } from 'bun:test';
|
||||
import { mkdtempSync, rmSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { createStore, createWorkflowRule } from '@uncaged/pulse';
|
||||
import { pingPong } from './ping-pong.js';
|
||||
|
||||
describe('ping-pong workflow', () => {
|
||||
let tmpDir: string;
|
||||
|
||||
afterEach(() => {
|
||||
if (tmpDir) rmSync(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('START → pong → END', async () => {
|
||||
tmpDir = mkdtempSync(join(tmpdir(), 'engine-test-'));
|
||||
const store = createStore({
|
||||
eventsDbPath: join(tmpDir, 'test.db'),
|
||||
objectsDir: join(tmpDir, 'objects'),
|
||||
});
|
||||
|
||||
const rule = createWorkflowRule(pingPong, store);
|
||||
|
||||
// Trigger
|
||||
const hash = store.putObject('ping');
|
||||
store.appendEvent({
|
||||
occurredAt: Date.now(),
|
||||
kind: 'ping-pong.__start__',
|
||||
key: 't1',
|
||||
hash,
|
||||
});
|
||||
|
||||
const r1 = await rule.tick();
|
||||
expect(r1.executed).toMatchObject([{ topicId: 't1', role: 'pong' }]);
|
||||
expect(r1.executed[0].content).toBe('pong: ping');
|
||||
|
||||
// No more work
|
||||
const r2 = await rule.tick();
|
||||
expect(r2.executed).toEqual([]);
|
||||
|
||||
store.close();
|
||||
});
|
||||
});
|
||||
28
src/workflows/ping-pong.ts
Normal file
28
src/workflows/ping-pong.ts
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Example: ping-pong workflow — validates engine setup.
|
||||
*
|
||||
* 小橘 🍊 (NEKO Team)
|
||||
*/
|
||||
|
||||
import { END, START, type Role, type WorkflowType } from '@uncaged/pulse/src/workflows/workflow-type.js';
|
||||
|
||||
type PingPongRoles = {
|
||||
pong: Role<{ echo: true }>;
|
||||
};
|
||||
|
||||
export const pingPong: WorkflowType<PingPongRoles> = {
|
||||
name: 'ping-pong',
|
||||
roles: {
|
||||
pong: async (chain) => {
|
||||
const start = chain.find((m) => m.role === '__start__');
|
||||
return {
|
||||
content: `pong: ${start?.content ?? ''}`,
|
||||
meta: { echo: true as const },
|
||||
};
|
||||
},
|
||||
},
|
||||
moderator: (output) => {
|
||||
if (output.role === START) return 'pong';
|
||||
return END;
|
||||
},
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user