xiaoju
d81a30f051
chore(workflow): post-extraction cleanup
...
- IPC parse functions: replace whole-object 'as' casts with per-field narrowing
- WorkflowConfig: remove duplicate from core, re-export from @uncaged/workflow
- drainTimeoutMs: change from optional param to T | null convention
- Remove duplicate WorkflowWorkerOutboundMessage, keep WorkflowChildToParentMessage
Fixes #325
2026-05-05 13:52:03 +00:00
xiaoju
4a43a7f3dd
refactor: update all consumers to import from @uncaged/workflow
...
- workflow-utils, workflow-meta: import workflow types from @uncaged/workflow
- adapter-cursor, adapter-hermes: same
- cli: same
- core: remove workflow re-exports, no longer depends on @uncaged/workflow
Phase 5+6 of #320 , Testing: #323
2026-05-05 11:01:08 +00:00
xiaoju
cee65bbd87
refactor(workflow): move IPC, worker, manager from daemon to @uncaged/workflow
...
- Move workflow IPC types (StartThread, ResumeThread, etc.) to workflow/ipc.ts
- Move workflow-worker.ts, workflow-manager.ts, workflow-manager-support.ts
- Move worker-runtime.ts and worker-signals.ts (shared infrastructure)
- Daemon now imports workflow runtime from @uncaged/workflow
- Export WORKFLOW_WORKER_PATH for daemon to spawn workers
Phase 3+4 of #320 , Testing: #322
2026-05-05 10:41:59 +00:00
xiaoju
591be21bb0
refactor(workflow): scaffold @uncaged/workflow, move types from core
...
- Create packages/workflow/ with types.ts (from core/workflow.ts) and config.ts
- Core re-exports workflow types from @uncaged/workflow
- Delete packages/core/src/workflow.ts
Phase 1+2 of #320 , Testing: #321
2026-05-05 10:27:08 +00:00
xiaoju
8dd82d99da
refactor(core): remove WorkflowTrigger from SenseTrigger — shell only
...
Senses trigger shell commands only. Workflows are invoked via CLI.
SenseTrigger is now { command: string } — no discriminated union.
Closes #318
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-05-02 12:33:38 +00:00
xiaoju
52a03d7de4
refactor(core): rename workflow→trigger in sense return, capture shell stderr
...
Co-authored-by: Cursor <cursoragent@cursor.com >
2026-05-02 10:47:22 +00:00
xiaoju
b9b804eac5
feat(core): sense trigger supports arbitrary shell commands
...
Extend SenseComputeReturn to support shell triggers in addition to workflow
triggers via a discriminated union (kind: 'shell' | 'workflow').
Shell triggers execute a command string in the sense worker subprocess
(spawned detached). The kernel logs 'shell-launch' events without involving
the workflow manager.
Breaking change: WorkflowTrigger now requires kind: 'workflow'.
New ShellTrigger type: { kind: 'shell', command: string }.
SenseTrigger = WorkflowTrigger | ShellTrigger.
Closes #315
2026-05-02 10:00:23 +00:00
xiaoju
02c5e8bea6
fix(daemon): harden state persistence, ReadonlyArray triggers
...
1. writeState: atomic write via temp file + rename
2. readState: distinguish missing file vs corrupt JSON (warn on error)
3. executeCompute: write disk before updating memory state
4. SenseInfo.triggers: ReadonlyArray<string>
5. CLAUDE.md: added Sense State Persistence docs
Fixes #313
2026-05-01 12:01:50 +00:00
xiaoju
fc7fc9158c
docs: update all docs/conventions for stateful sense, remove stale refs
...
Phase 4 of RFC #308 : Stateful Sense refactor.
- CLAUDE.md: updated diagram, tables, examples (no more Signal)
- Cleaned stale Signal Bus / DrizzleDB / _signals / retention refs
across READMEs, .cursor rules, copilot instructions, .knowledge
- Removed drizzle-orm from core package.json (no longer used)
- Updated pnpm-lock.yaml
Refs #308
2026-05-01 10:09:01 +00:00
xiaoju
e789c7bb34
refactor(core): stateful sense types — remove Signal, add initialState
...
Phase 1 of RFC #308 : Stateful Sense refactor.
- SenseComputeFn<S> now takes state and returns { state, workflow }
- SenseModule<S> exports compute + initialState (no more table)
- Removed: Signal type, ComputeResult, RoutedSenseOutput,
routeSenseComputeOutput, retention/DEFAULT_SENSE_SIGNAL_RETENTION
- Updated isSenseInfo (removed lastSignalTimestamp)
Refs #308 , closes #309
2026-05-01 09:43:13 +00:00
xiaomo
49f3d91d1b
chore: dead code cleanup — remove unused exports and fix stale docs
...
- Delete createEchoAgent (daemon, never referenced)
- Delete isDryRun (workflow-utils, deprecated, always false)
- Delete KNOWN_AGENT_ADAPTER_IDS (core, never referenced)
- Remove parseDurationStringToMs, labelSenseTrigger from core public API
- Remove spawnSafe re-export from workflow-utils
- Fix core/README.md stale API names
- Clean stale hermes-options.ts comment
Closes #302
2026-04-30 14:29:45 +00:00
xiaomo
0d78df89b1
refactor(core): consolidate file structure — 22 files → 6 ( closes #273 )
2026-04-30 09:15:18 +00:00
xiaomo
3e51335d91
refactor(core): RFC-005 Phase 1 — ThreadContext, AgentFn, Role signature ( closes #268 )
2026-04-30 06:54:03 +00:00
xiaoju
b27a6aced8
feat: sense compute returns ComputeResult<T> with workflow trigger support
...
- SenseComputeFn returns ComputeResult<T> = null | { signal, workflow }
- sense-runtime persists result.signal, not result itself
- sense-worker sends workflow trigger message when workflow is non-null
- New SenseWorkflowTriggerMessage in IPC protocol
- Knowledge card updated to match
— 小橘 🍊 (NEKO Team)
2026-04-30 00:37:16 +00:00
xiaoju
748df10e6a
fix: remove AbortSignal from SenseComputeFn
...
Compute is truly zero-arg now: () => Promise<T | null>.
Runtime handles timeout via Promise.race, sense doesn't need signal.
— 小橘 🍊 (NEKO Team)
2026-04-30 00:22:57 +00:00
xiaoju
8c9adf08c5
refactor: pure sense compute — no db, no peers
...
SenseComputeFn is now (signal: AbortSignal) => Promise<T | null>.
sense-runtime handles db.insert when compute returns non-null.
Senses export { compute, table } — SenseModule type added to core.
Closes #264
Refs #260
— 小橘 🍊 (NEKO Team)
2026-04-30 00:07:49 +00:00
xiaoju
e287e07dab
feat: add sense contract types to @uncaged/nerve-core
...
Export SenseComputeFn, SenseComputeOptions, SenseBlobStore,
SensePeerMap — formalizing the compute function signature that
senses must implement.
Closes #262
Refs #260
— 小橘 🍊 (NEKO Team)
2026-04-29 15:11:49 +00:00
xiaoju
9b4ab6225a
refactor(core): remove WorkflowSpec and compileWorkflowSpec
...
Add createRole to workflow-utils wrapping AgentFn, Zod meta, and extractMetaOrThrow.
Refs #252
Signed-off-by: 小橘 🍊 (NEKO Team) <dev@uncaged.ai >
Made-with: Cursor
2026-04-29 09:54:13 +00:00
小橘 🍊(NEKO Team)
3d02ea20ad
fix(core): consolidate spawn-safe into nerve-core
...
Move spawnSafe, nerveCommandEnv, and related types to @uncaged/nerve-core.
Update adapter-cursor, adapter-hermes, and workflow-utils to consume from core.
Refs #247
Made-with: Cursor
2026-04-29 09:14:28 +00:00
xiaoju
ede59ebcc2
feat(core): remove AgentRegistry, roles declare adapter directly
...
RoleSpec uses adapter: AgentFn; timeouts are configured via adapter factories.
nerve.yaml no longer accepts agents:; extract merge is global to role only.
Added cursorAdapter/hermesAdapter defaults; removed daemon registry and deps.
Signed-off-by: 小橘 🍊 (NEKO Team)
Made-with: Cursor
2026-04-29 08:40:37 +00:00
xiaoju
b7d9a37981
feat: RFC-003 adapter plugin architecture + dynamic prompts
...
AgentRegistry plugin model:
- createAgentRegistry(agents, adapterFactories) — second param for adapter map
- Echo adapter built-in, cursor/hermes via factory injection
- Unknown type throws with available adapter list
Dynamic prompts:
- RoleSpec.prompt: string | ((start, messages) => Promise<string>)
- compileWorkflowSpec handles both static and dynamic prompts
Adapter packages:
- @uncaged/nerve-adapter-cursor — cursor-agent CLI spawn
- @uncaged/nerve-adapter-hermes — hermes CLI subagent spawn
- Each with own spawn-safe (inline, avoids circular dep)
- Moved spawn logic from workflow-utils, kept role factories as thin wrappers
Kernel integration:
- defaultAgentAdapterFactories() registers cursor + hermes
- Hot-reload passes factories on rebuild
Ref: #234
2026-04-29 07:24:19 +00:00
xiaoju
62434847c4
feat(cli,core): RFC-003 Phase 6 — Knowledge Layer + review fixes
...
Knowledge Layer:
- knowledge.yaml parser in core (include/exclude globs)
- Chunking: markdown (by heading), TypeScript/JS (by function/block)
- knowledge.db: SQLite storage for chunks + embeddings (node:sqlite)
- CLI: nerve knowledge sync, nerve knowledge query
- Scoping: -r (specific repo), -g (global search), mutually exclusive
- Repo registry (~/.nerve-knowledge-registry.json) for global search
- Placeholder embedding (content hash) until remote service ready
- Word-overlap similarity for query ranking
Review fixes (from PR #241 feedback):
- KNOWN_AGENT_ADAPTER_IDS: add cursor/hermes/codex + sync docs
- collectWorkflowSpecAgentReferences: document regex comment false-positive
- assertZodMetaSchemas: one-time compile-time validation utility
Closes #240
Ref: #234
2026-04-29 05:39:00 +00:00
xiaoju
a1dda1d731
feat(daemon,cli): RFC-003 Phase 5 — Integration (hot-reload + validate)
...
- Kernel: rebuild AgentRegistry on config hot-reload, log agent_registry_reload
- Running threads unaffected, new threads use rebuilt registry
- nerve validate: check agent name refs in WorkflowSpec source files
- nerve validate: verify adapter type is known (KNOWN_AGENT_ADAPTER_IDS)
- nerve validate: require extract config when WorkflowSpec agent refs exist
- Tests: kernel reload (mock), validate (missing/valid/extract/adapter)
Closes #239
Ref: #234
2026-04-29 05:23:59 +00:00
xiaoju
1218b5ddbd
feat(core,daemon): RFC-003 Phase 4 — WorkflowSpec Compiler
...
- WorkflowSpec + RoleSpec types in packages/core
- compileWorkflowSpec: WorkflowSpec → WorkflowDefinition (daemon)
- resolveRoleTimeoutMs: two-level timeout (role override > agent default)
- parseDurationStringToMs extracted to shared duration.ts
- AgentRegistry.getAgentConfig for timeout lookup
- Tests: 10 new cases (compile shape, agent→extract flow, timeout resolution)
- Backward compat: hand-written Role<Meta> unchanged
Closes #238
Ref: #234
2026-04-29 05:11:29 +00:00
xiaoju
136aafa209
feat(workflow-utils): RFC-003 Phase 3 — Extract Layer
...
- llmExtractWithRetry: retry-once on parse failure with error context
- mergeExtractConfig: three-level merge (global → agent → role)
- extractMetaOrThrow + createLlmExtractFn: ExtractFn factory
- ZodMetaSchema bridges core Schema<T> with runtime Zod validation
- Tests: 8 new cases (success/retry/throw/merge/factory)
- core tsconfig: add DOM lib for AbortSignal declaration emit
Closes #237
Ref: #234
2026-04-29 04:59:47 +00:00
xiaoju
36e5aed1b1
feat(core): RFC-003 Phase 1 — agent config types + nerve.yaml schema
...
- Add AgentFn, WorkflowContext (workdir + AbortSignal), ExtractFn, ExtractError
- Add AgentConfig, ExtractConfig types to NerveConfig
- Extend parseNerveConfig: agents (kebab-case keys) + extract sections
- Export all new types from @nerve/core
- Add config parse tests (7 new tests)
- Update all existing test fixtures with agents/extract fields
Closes #235
Ref: #234
2026-04-29 04:43:08 +00:00
xiaomo
b4c78a62aa
Merge pull request 'feat(workflow-utils): role factory templates #208 ' ( #209 ) from feat/208-role-factories into main
2026-04-28 01:55:14 +00:00
xiaoju
2529c68062
feat(workflow-utils): role factory templates — createCursorRole, createHermesRole, createLlmRole, createReActRole
...
- Add role-types.ts with all shared types (CliPromptFn, LlmPromptFn, MetaExtractConfig, etc.)
- Add role-factories.ts with 4 factory functions
- Add llm-chat.ts with chatCompletionText and reActIterativeChat
- Add hermes-agent.ts and hermes-options.ts for Hermes CLI integration
- Add threadId to StartStep meta (core + daemon)
- Add model param to cursorAgent options
- Tests for all 4 factories
Refs #208
2026-04-28 01:50:44 +00:00
xiaomo
e159a9b7ca
refactor: redesign workflow trigger — signal entails workflow ( #204 )
...
Breaking change: compute() returns null | { signal: T; workflow: WorkflowTrigger | null }
- WorkflowTrigger is a structured type (name, maxRounds, prompt, dryRun)
- Signal is always emitted before workflow launch (causal chain)
- CLI: nerve workflow trigger <name> --max-rounds N --prompt '...' --dry-run
- Remove pipe-separated directive format
Fixes #204
2026-04-27 13:23:31 +00:00
xiaoju
b269f76b33
refactor(daemon): rename reflex-scheduler → sense-scheduler
...
Rename ReflexScheduler to SenseScheduler, update all file names,
imports, comments, test descriptions, and log source values.
Fixes #202
2026-04-27 12:07:22 +00:00
xiaoju
2b2895e5be
refactor: remove legacy reflexes backward-compat code
...
BREAKING CHANGE: NerveConfig no longer has 'reflexes' field.
SenseReflexConfig/ReflexConfig types removed.
Config with top-level 'reflexes' array now errors instead of migrating.
Use sense-level 'interval' and 'on' fields instead.
- Remove reflexes from NerveConfig type
- Remove legacy parsing, deprecation warning, buildReflexesFromSenses
- Simplify reflex-scheduler to only read sense-level config
- Rename senseTriggerLabelsWithFallback → senseTriggerLabels
- Delete all legacy reflexes test cases
- -639/+114 lines
Fixes #199
2026-04-27 11:11:37 +00:00
xiaoju
ef40512977
refactor(daemon): reflex-scheduler reads from sense config with legacy fallback
...
- Scheduler iterates config.senses directly for interval/on
- Falls back to config.reflexes when sense has no inline triggers
- kernel.ts uses senseTriggerLabelsWithFallback for display
- New core export: senseTriggerLabelsWithFallback
- All 166 daemon tests pass
Fixes #194
2026-04-27 10:46:12 +00:00
xiaoju
d0cc8c0840
feat(core): backward-compat parsing for legacy reflexes array
...
- Merge top-level reflexes into sense-level interval/on fields
- Emit deprecation warning when legacy reflexes detected
- Deduplicate on[] triggers, detect interval conflicts
- Add tests for compat parsing, merge, and conflict cases
Fixes #193
2026-04-27 10:40:46 +00:00
xiaoju
81663ad524
fix(core): remove stale import process breaking core build
...
Fixes #191
2026-04-27 10:33:36 +00:00
xiaoju
c6c3e0142d
chore: bump version to 0.5.0
...
小橘 🍊 (NEKO Team)
2026-04-27 09:40:34 +00:00
xiaoju
03e103d400
refactor: move experimental-warning-suppression from core to daemon
...
core package should remain platform-agnostic without direct process access.
The suppression module belongs in daemon where Node.js APIs are expected.
小橘 🍊 (NEKO Team)
2026-04-27 09:30:16 +00:00
xiaomo
d70e74afde
fix: suppress ExperimentalWarning for node:sqlite ( #179 )
...
Add side-effect module in @uncaged/nerve-core that filters ExperimentalWarning
from process.emit. Imported at all entry points: CLI, daemon bootstrap,
sense-worker, and workflow-worker.
2026-04-27 08:17:52 +00:00
xingyue
63a54d4641
feat(daemon): _signals table retention policy ( #152 )
...
- Add `retention` field to SenseConfig (default 10000 max rows)
- Parse optional `retention` positive integer in nerve.yaml sense config
- Prune old _signals rows every 100 inserts for amortized performance
- Pass retention from config through sense-worker to openSenseDb
- Add unit tests for config parsing and runtime pruning
2026-04-27 15:44:33 +08:00
xingyue
913f9ed57d
fix: rename threadId to runId in kill-workflow API
...
The /api/kill-workflow endpoint and all callers (dashboard, HttpTransport)
now consistently use 'runId' instead of 'threadId', matching the handler
name killWorkflowByRunId.
Fixes review feedback on PR #138 .
2026-04-25 15:50:56 +08:00
xingyue
69e50d8339
feat(dashboard): Phase 3 — embedded web dashboard
...
- Single-file dark-theme HTML dashboard (569 lines, zero deps)
- GET / serves dashboard HTML (no auth required, token handled in JS)
- Auto-poll every 5s: health, senses, workflows
- Trigger/Kill buttons with confirmation + toast notifications
- Bearer token input persisted in localStorage
- Connection status indicator (green/red dot)
- Responsive layout for mobile
- SenseInfo gains triggers[] field, WorkflowStatus gains activeRunIds[]
- rslib copies dashboard.html to dist/
Refs #133
2026-04-25 15:01:11 +08:00
xingyue
203cd8d3c9
feat(http-api): Phase 2 — CLI remote access + bearer token auth
...
- Bearer token auth middleware with timingSafeEqual
- Enforce api.token when host is non-loopback (security)
- api.host config option (default 127.0.0.1)
- HttpTransport implementing DaemonTransport interface
- CLI --host and --api-token global flags for remote access
- Request body size limit (1MB, 413 on overflow)
- Deduplicate type guards to @uncaged/nerve-core
- 322 tests passing
Refs #133
2026-04-25 14:25:36 +08:00
xingyue
2c262fc8e3
fix: resolve biome lint issues (format, imports, parameter property, complexity)
2026-04-25 14:07:44 +08:00
xingyue
6d74260201
feat(core,daemon,cli): HTTP API + transport interface + workflow list ( #133 Phase 1)
...
- Add WorkflowStatus, HealthInfo types to core IPC protocol
- Add DaemonTransport interface (core/daemon-transport.ts)
- Add list-workflows and health IPC handlers
- WorkflowManager.listWorkflows() exposes runtime status
- Kernel: getHealth(), optional HTTP API server (--port / api.port)
- CLI: nerve workflow list command via IPC
- daemon-client: UnixTransport implements DaemonTransport
Closes: Phase 1 of #133
2026-04-25 14:07:31 +08:00
xiaoju
01d7435c4a
feat: workflow exit codes & kill mechanism
...
- Add exit_code to workflow_runs (0=success, 1=role error, 2=maxRounds, 137=killed, 255=crash)
- Expand status enum: started/completed/failed/killed
- Add kill-thread IPC message for graceful workflow termination
- Add 'nerve workflow kill <runId>' CLI command
- Show exit_code in 'nerve workflow list' output
Fixes #121
2026-04-25 03:57:26 +00:00
xiaoju
418ae6a073
refactor(core): SenseResult generic + split types.ts into config/sense/workflow
...
- SenseResult<T = unknown> with payload: T
- types.ts split into config.ts (types), sense.ts, workflow.ts
- Original config.ts (parseNerveConfig) moved to parse-nerve-config.ts
- index.ts re-exports from new modules, external API unchanged
- daemon-ipc-protocol.ts imports SenseInfo from sense.ts
Fixes #111
2026-04-25 02:56:55 +00:00
xiaoju
3ce9e3a846
refactor(core): restructure ModeratorContext to { start, steps }
...
- ModeratorContext: discriminated union → { start: StartStep; steps: RoleStep<M>[] }
- Moderator signature: (context, round, maxRounds) → (context)
- round derivable from steps.length, maxRounds from start.meta.maxRounds
- workflow-worker.ts: build steps array, pass full context to moderator
- Remove unused ModeratorContext import from workflow-worker
- Update README.md
Refs #110
2026-04-25 02:48:28 +00:00
xiaoju
beada2ae09
refactor(core): rename RoleSignal → RoleStep, StartSignal → StartStep
...
- RoleStep now includes content and timestamp fields (aligned with StartStep)
- ModeratorContext.signal → ModeratorContext.step
- workflow-utils: start-signal.ts → start-step.ts, isDryRun updated
Fixes #109
2026-04-25 02:34:33 +00:00
xiaoju
020a1bfe85
refactor(core): remove unnecessary | null, unify timestamp naming
...
- SenseReflexConfig.on: string[] | null → string[] (empty = no conditions)
- NerveConfig.workflows: Record | null → Record (empty = no workflows)
- Signal.ts → Signal.timestamp
- SenseInfo.lastSignalTs → SenseInfo.lastSignalTimestamp
- All consumers across daemon/cli/store updated
- parseNerveConfig: on defaults to [], workflows defaults to {}
Fixes #108
2026-04-25 01:52:58 +00:00
xiaoju
c4dc707eb0
feat(core,daemon,cli): add dryRun thread-level parameter to StartSignal
...
- StartSignal.meta gains dryRun: boolean (alongside maxRounds)
- DaemonIpcTriggerWorkflowRequest includes dryRun, parsed with default false
- CLI parses dryRun from --payload JSON, passes through daemon client
- workflow-worker/workflow-manager propagate dryRun through full IPC chain
- Sense-triggered workflows default to dryRun: false
- workflow-utils exports isDryRun(start) helper
- All tests updated, 376 pass
Fixes #101
2026-04-24 23:45:29 +00:00
xiaoju
e9e6df2f5a
refactor(core,daemon): extract StartSignal as independent Role parameter
...
- Role<Meta> now takes (start: StartSignal, messages: WorkflowMessage[])
- messages no longer contains the __start__ frame
- Add ModeratorContext<M> discriminated union (kind: start | step)
- Moderator receives typed context instead of raw StartSignal | RoleSignal union
- workflow-worker separates start from role messages throughout
Refs #100
2026-04-24 23:14:45 +00:00