Compare commits

...

2 Commits

Author SHA1 Message Date
xiaoju 7f780f0642 chore: walkthrough cleanup — engines, types, mock fixes
- Add engines >= 22.5.0 to root and cli package.json (node:sqlite requirement)
- Remove unused @types/better-sqlite3 from cli devDeps (leftover from sql.js migration)
- Add files/publishConfig to core package.json (parity with other packages)
- Fix daemon test type errors: add getAllWorkflowRuns to mock LogStore,
  fix array destructuring on mock.calls, fix sense-runtime callback signatures

All 356 tests pass across all packages.

小橘 🍊(NEKO Team)
2026-04-23 09:08:24 +00:00
xiaomo 33e0d9a705 Merge pull request 'refactor(cli): replace sql.js with node:sqlite' (#66) from refactor/node-sqlite into main 2026-04-23 08:51:01 +00:00
9 changed files with 43 additions and 33 deletions
+3
View File
@@ -1,6 +1,9 @@
{ {
"name": "nerve", "name": "nerve",
"private": true, "private": true,
"engines": {
"node": ">=22.5.0"
},
"scripts": { "scripts": {
"build": "pnpm -r run build", "build": "pnpm -r run build",
"check": "biome check .", "check": "biome check .",
+3 -1
View File
@@ -1,5 +1,8 @@
{ {
"name": "@uncaged/nerve-cli", "name": "@uncaged/nerve-cli",
"engines": {
"node": ">=22.5.0"
},
"version": "0.1.8", "version": "0.1.8",
"type": "module", "type": "module",
"bin": { "bin": {
@@ -23,7 +26,6 @@
"citty": "^0.1.6" "citty": "^0.1.6"
}, },
"devDependencies": { "devDependencies": {
"@types/better-sqlite3": "^7.6.13",
"@types/node": "^22.0.0", "@types/node": "^22.0.0",
"@uncaged/nerve-daemon": "workspace:*", "@uncaged/nerve-daemon": "workspace:*",
"vitest": "^4.1.5" "vitest": "^4.1.5"
+4
View File
@@ -3,6 +3,10 @@
"version": "0.1.4", "version": "0.1.4",
"type": "module", "type": "module",
"main": "dist/index.js", "main": "dist/index.js",
"files": ["dist"],
"publishConfig": {
"access": "public"
},
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"scripts": { "scripts": {
"prepublishOnly": "bash ../../scripts/prepublish-check.sh", "prepublishOnly": "bash ../../scripts/prepublish-check.sh",
@@ -89,10 +89,11 @@ function makeLogStore(
} }
return activeRuns; return activeRuns;
}), }),
getTriggerPayload: vi.fn(() => ({ value: 42 })), getTriggerPayload: vi.fn((): unknown => ({ value: 42 })),
getThreadEvents: vi.fn(() => [{ type: "thread_start", triggerPayload: {} }]), getThreadEvents: vi.fn((): Array<{ type: string; [key: string]: unknown }> => [{ type: "thread_start", triggerPayload: {} }]),
archiveLogs: vi.fn(() => ({ days: [], vacuumed: false })), archiveLogs: vi.fn(() => ({ days: [], vacuumed: false })),
close: vi.fn(), close: vi.fn(),
getAllWorkflowRuns: vi.fn(() => []),
}; };
return store; return store;
} }
@@ -127,7 +128,7 @@ describe("WorkflowManager — crash recovery (Phase 3)", () => {
child.emit("exit", 1, null); child.emit("exit", 1, null);
const crashedCalls = logStore.upsertWorkflowRun.mock.calls.filter( const crashedCalls = logStore.upsertWorkflowRun.mock.calls.filter(
([entry]: [{ type: string }]) => entry.type === "crashed", (args: any[]) => (args[0] as { type: string }).type === "crashed",
); );
expect(crashedCalls).toHaveLength(2); expect(crashedCalls).toHaveLength(2);
@@ -216,10 +217,10 @@ describe("WorkflowManager — crash recovery (Phase 3)", () => {
// resume-thread should have been sent // resume-thread should have been sent
const resumeCalls = (secondChild.send as ReturnType<typeof vi.fn>).mock.calls.filter( const resumeCalls = (secondChild.send as ReturnType<typeof vi.fn>).mock.calls.filter(
([msg]: [unknown]) => (args: any[]) =>
msg !== null && args[0] !== null &&
typeof msg === "object" && typeof args[0] === "object" &&
(msg as Record<string, unknown>).type === "resume-thread", (args[0] as Record<string, unknown>).type === "resume-thread",
); );
expect(resumeCalls).toHaveLength(1); expect(resumeCalls).toHaveLength(1);
expect(resumeCalls[0][0]).toMatchObject({ expect(resumeCalls[0][0]).toMatchObject({
@@ -286,7 +287,7 @@ describe("WorkflowManager — crash recovery (Phase 3)", () => {
}); });
const appendCalls = logStore.append.mock.calls.filter( const appendCalls = logStore.append.mock.calls.filter(
([entry]: [{ type: string }]) => entry.type === "thread_command_event", (args: any[]) => (args[0] as { type: string }).type === "thread_command_event",
); );
expect(appendCalls).toHaveLength(1); expect(appendCalls).toHaveLength(1);
expect(appendCalls[0][0]).toMatchObject({ expect(appendCalls[0][0]).toMatchObject({
@@ -313,7 +314,7 @@ describe("WorkflowManager — crash recovery (Phase 3)", () => {
mgr.startWorkflow("my-wf", payload); mgr.startWorkflow("my-wf", payload);
const startedCall = logStore.upsertWorkflowRun.mock.calls.find( const startedCall = logStore.upsertWorkflowRun.mock.calls.find(
([entry]: [{ type: string }]) => entry.type === "started", (args: any[]) => (args[0] as { type: string }).type === "started",
); );
expect(startedCall).toBeDefined(); expect(startedCall).toBeDefined();
const logEntry = startedCall?.[0] as { payload: string | null }; const logEntry = startedCall?.[0] as { payload: string | null };
@@ -79,6 +79,7 @@ function makeLogStore() {
getThreadEvents: vi.fn(() => []), getThreadEvents: vi.fn(() => []),
archiveLogs: vi.fn(() => ({ days: [], vacuumed: false })), archiveLogs: vi.fn(() => ({ days: [], vacuumed: false })),
close: vi.fn(), close: vi.fn(),
getAllWorkflowRuns: vi.fn(() => []),
}; };
} }
@@ -126,7 +127,7 @@ describe("WorkflowManager — drainAndRespawn (Phase 3 hot reload)", () => {
await drainPromise; await drainPromise;
const interruptedCalls = logStore.upsertWorkflowRun.mock.calls.filter( const interruptedCalls = logStore.upsertWorkflowRun.mock.calls.filter(
([entry]: [{ type: string }]) => entry.type === "interrupted", (args: any[]) => (args[0] as { type: string }).type === "interrupted",
); );
expect(interruptedCalls).toHaveLength(2); expect(interruptedCalls).toHaveLength(2);
@@ -190,10 +191,10 @@ describe("WorkflowManager — drainAndRespawn (Phase 3 hot reload)", () => {
const newChild = mockChildren[1]; const newChild = mockChildren[1];
const resumeCalls = (newChild.send as ReturnType<typeof vi.fn>).mock.calls.filter( const resumeCalls = (newChild.send as ReturnType<typeof vi.fn>).mock.calls.filter(
([msg]: [unknown]) => (args: any[]) =>
msg !== null && args[0] !== null &&
typeof msg === "object" && typeof args[0] === "object" &&
(msg as Record<string, unknown>).type === "resume-thread", (args[0] as Record<string, unknown>).type === "resume-thread",
); );
expect(resumeCalls).toHaveLength(0); expect(resumeCalls).toHaveLength(0);
@@ -218,10 +219,10 @@ describe("WorkflowManager — drainAndRespawn (Phase 3 hot reload)", () => {
const newChild = mockChildren[1]; const newChild = mockChildren[1];
const startCalls = (newChild.send as ReturnType<typeof vi.fn>).mock.calls.filter( const startCalls = (newChild.send as ReturnType<typeof vi.fn>).mock.calls.filter(
([msg]: [unknown]) => (args: any[]) =>
msg !== null && args[0] !== null &&
typeof msg === "object" && typeof args[0] === "object" &&
(msg as Record<string, unknown>).type === "start-thread", (args[0] as Record<string, unknown>).type === "start-thread",
); );
expect(startCalls).toHaveLength(1); expect(startCalls).toHaveLength(1);
@@ -266,7 +267,7 @@ describe("Kernel — workflow hot reload via file-watcher (Phase 3)", () => {
// Kernel's handleWorkflowFileChange should log a workflow_reload event // Kernel's handleWorkflowFileChange should log a workflow_reload event
// We test this via the kernel itself // We test this via the kernel itself
const appendCalls = logStore.append.mock.calls; const appendCalls = logStore.append.mock.calls;
const startCall = appendCalls.find(([e]: [{ type: string }]) => e.type === "start"); const startCall = appendCalls.find((args: any[]) => (args[0] as { type: string }).type === "start");
expect(startCall).toBeDefined(); expect(startCall).toBeDefined();
const stopPromise = kernel.stop(); const stopPromise = kernel.stop();
@@ -78,6 +78,7 @@ function makeLogStore() {
appendWithWorkflowUpdate: vi.fn(), appendWithWorkflowUpdate: vi.fn(),
getWorkflowRun: vi.fn(() => null), getWorkflowRun: vi.fn(() => null),
getActiveWorkflowRuns: vi.fn(() => []), getActiveWorkflowRuns: vi.fn(() => []),
getAllWorkflowRuns: vi.fn(() => []),
getTriggerPayload: vi.fn(() => null), getTriggerPayload: vi.fn(() => null),
getThreadEvents: vi.fn(() => []), getThreadEvents: vi.fn(() => []),
archiveLogs: vi.fn(() => ({ days: [], vacuumed: false })), archiveLogs: vi.fn(() => ({ days: [], vacuumed: false })),
@@ -137,10 +138,10 @@ describe("kernel + workflowManager integration", () => {
// We need to check that a start-thread message was sent to the workflow worker // We need to check that a start-thread message was sent to the workflow worker
const workflowWorker = mockChildren.find((c) => const workflowWorker = mockChildren.find((c) =>
(c.send as ReturnType<typeof vi.fn>).mock.calls.some( (c.send as ReturnType<typeof vi.fn>).mock.calls.some(
([msg]: [unknown]) => (args: unknown[]) =>
msg !== null && args[0] !== null &&
typeof msg === "object" && typeof args[0] === "object" &&
(msg as Record<string, unknown>).type === "start-thread", (args[0] as Record<string, unknown>).type === "start-thread",
), ),
); );
expect(workflowWorker).toBeDefined(); expect(workflowWorker).toBeDefined();
@@ -212,10 +213,10 @@ describe("kernel + workflowManager integration", () => {
// No workflow worker should have been spawned (only the sense group worker) // No workflow worker should have been spawned (only the sense group worker)
const workflowWorkerSpawned = mockChildren.some((c) => const workflowWorkerSpawned = mockChildren.some((c) =>
(c.send as ReturnType<typeof vi.fn>).mock.calls.some( (c.send as ReturnType<typeof vi.fn>).mock.calls.some(
([msg]: [unknown]) => (args: unknown[]) =>
msg !== null && args[0] !== null &&
typeof msg === "object" && typeof args[0] === "object" &&
(msg as Record<string, unknown>).type === "start-thread", (args[0] as Record<string, unknown>).type === "start-thread",
), ),
); );
expect(workflowWorkerSpawned).toBe(false); expect(workflowWorkerSpawned).toBe(false);
@@ -10,7 +10,7 @@ import { describe, expect, it } from "vitest";
import { createBlobStore } from "../blob-store.js"; import { createBlobStore } from "../blob-store.js";
import { parseParentMessage } from "../ipc.js"; import { parseParentMessage } from "../ipc.js";
import { executeCompute, openPeerDb, openSenseDb, runMigrations } from "../sense-runtime.js"; import { executeCompute, openPeerDb, openSenseDb, runMigrations } from "../sense-runtime.js";
import type { DrizzleDB, PeerMap, SenseRuntime } from "../sense-runtime.js"; import type { ComputeFn, DrizzleDB, PeerMap, SenseRuntime } from "../sense-runtime.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Helpers // Helpers
@@ -168,7 +168,7 @@ describe("openPeerDb", () => {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
describe("executeCompute", () => { describe("executeCompute", () => {
function makeRuntime(computeFn: (db: DrizzleDB, peers: PeerMap) => Promise<unknown | null>): { function makeRuntime(computeFn: ComputeFn): {
runtime: SenseRuntime; runtime: SenseRuntime;
sqlite: Database.Database; sqlite: Database.Database;
} { } {
@@ -76,6 +76,7 @@ function makeLogStore() {
getThreadEvents: vi.fn(() => []), getThreadEvents: vi.fn(() => []),
archiveLogs: vi.fn(() => ({ days: [], vacuumed: false })), archiveLogs: vi.fn(() => ({ days: [], vacuumed: false })),
close: vi.fn(), close: vi.fn(),
getAllWorkflowRuns: vi.fn(() => []),
}; };
} }
-3
View File
@@ -27,9 +27,6 @@ importers:
specifier: ^0.1.6 specifier: ^0.1.6
version: 0.1.6 version: 0.1.6
devDependencies: devDependencies:
'@types/better-sqlite3':
specifier: ^7.6.13
version: 7.6.13
'@types/node': '@types/node':
specifier: ^22.0.0 specifier: ^22.0.0
version: 22.19.17 version: 22.19.17