@excitedjs/dreamux 0.16.0-beta.91 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.json CHANGED
@@ -1,6 +1,123 @@
1
1
  {
2
2
  "name": "@excitedjs/dreamux",
3
3
  "entries": [
4
+ {
5
+ "version": "0.16.0",
6
+ "tag": "@excitedjs/dreamux_v0.16.0",
7
+ "date": "Sat, 27 Jun 2026 12:09:24 GMT",
8
+ "comments": {
9
+ "minor": [
10
+ {
11
+ "comment": "Add cron scheduling for every conversational agent: each TeamLeader now owns a durable cron scheduler and cron MCP surface alongside the dispatcher scheduler. TeamLeader cron jobs are stored at `~/.dreamux/state/<dispatcher-id>/team/<team-id>/cron-jobs.json` while retaining the existing job schema and dispatcher_id validation; Team isolation is by path. Non-closed Team schedulers are eager-armed at dispatcher boot without starting TeamLeader runtimes, and a scheduled fire lazy-starts the TeamLeader through its own `scheduledInput` path. Closed/dissolved Teams are not armed, and `team.dissolve` deletes that Team's cron jobs. Regular Team members still receive no cron MCP. No Rebuild required; delete a Team's `cron-jobs.json` manually only if you intentionally want to clear that TeamLeader's scheduled tasks without dissolving the Team."
12
+ },
13
+ {
14
+ "comment": "Emit neutral disableFeatures for agent runtime launches: every agent receives userInterrupt (the model-facing ask-the-user tool, which would wedge a turn in a channel-only environment), and dispatcher and TeamLeader launches additionally receive cron so runtimes with native scheduling defer to Dreamux's role-gated cron MCP. Core emits only neutral feature names and preserves any launch-specific disabled features."
15
+ },
16
+ {
17
+ "comment": "BREAKING: Channel binding store v2 + (channel_id, target_key) routing (issue #209). The persisted channel-binding store (`~/.dreamux/state/<dispatcher>/team/channel-bindings.json`) moves to `version: 2`: flat rows now carry `channel_id`, a provider-owned `target_key`, `target_type`, `display`, `canonical_url`, and a `meta` object (Feishu `chat_id` / `chat_type` move OUT of top-level columns INTO `meta`), alongside the existing team/leader/active/timestamp fields. The active uniqueness key is `(channel_id, target_key)`; one channel target is active for at most one Team (re-binding reassigns it). Inbound routing and TeamLeader authorization now key on `(channel_id, target_key)`: a bound bindable target routes to its TeamLeader, an unbound target and any P2P (non-bindable) target route to the dispatcher, and a P2P target can never be bound to a TeamLeader. Targets are resolved by the channel provider's `resolveTarget(meta)` (Feishu maps `{ chat_id }` to a stable group target); `channel_id` is the dispatcher-local `dispatchers[].channels[].id`. Team MCP owns `bind_channel({ team_name, channel_id?, meta })` and `transfer_back({ channel_id?, meta })`; the channel-tool MCP shim does not own binding. Rebuild: 0.x does not migrate binding state — a pre-v2 `channel-bindings.json` fails loud at `dreamux serve` / `dreamux doctor` (and on access) with guidance to delete `~/.dreamux/state/<dispatcher>/team/channel-bindings.json` and re-bind the channel(s); Team records and all other state load unchanged."
18
+ },
19
+ {
20
+ "comment": "Provider-specific channel tool plumbing is neutralized: the old `feishu-mcp` CLI subcommand is replaced by the generic `channel-mcp` stdio shim, while binding stays on the Team MCP. A Channel provider's `mcpServerDescriptor` supplies static `tools/list` metadata plus the shim args (`channel-mcp --provider <ref> --channel-id <id> --dispatcher <id> ...`); `tools/call` forwards raw `{ name, arguments }` through the single neutral admin method `channel.invoke_tool`, which routes to the live `ChannelSession.handleTool` or `ChannelProvider.handleSessionlessTool`. Core names no provider tool or selector. The per-dispatcher shim log directory moves from `~/.dreamux/logs/feishu-mcp/` to `~/.dreamux/logs/channel-mcp/`. Rebuild: none required for stored state. MCP server descriptors are rendered at every dispatcher boot and same-release shim/server IPC is regenerated on `daemon restart`. The old `~/.dreamux/logs/feishu-mcp/` directory is rebuildable and safe to delete. Any saved automation invoking `dreamux feishu-mcp` directly must switch to `dreamux channel-mcp`; any binding automation must use the Team MCP `bind_channel` / `transfer_back` tools, not the channel-tool shim."
21
+ },
22
+ {
23
+ "comment": "BREAKING: Channel targets now route through explicit channel providers and Team MCP keeps ownership of Team binding (issue #209). The old Feishu-specific `team.bind_group` / `team.transfer_channel_back` helpers and create-time `team.create.bind_group` convenience are removed WITHOUT compatibility aliases; use the Team MCP `bind_channel({ team_name, channel_id?, meta })` and `transfer_back({ channel_id?, meta })` tools instead. The generic `channel-mcp` stdio shim is a provider-tool bridge only: it exposes provider-owned tools such as Feishu `reply` / `react` and forwards calls through the neutral `channel.invoke_tool` admin method. Binding state, routing, and authorization stay core-owned through the ChannelBindingStore; provider-specific chat identifiers live inside provider-owned target metadata. Rebuild: none required for Team records or ledgers, but any saved automation or prompt that calls the removed Feishu binding helpers MUST switch to the Team MCP channel-binding tools."
24
+ },
25
+ {
26
+ "comment": "Live multi-channel runtime routing (issue #209). A dispatcher may now declare more than one builtin:feishu channel; the dispatcher service runs one live session per channel, each connecting as its own bot from that channel's config {app_id, app_secret}. Inbound events route by the originating channel's channel_id plus the provider-resolved target — `(channel_id, target_key)` — so a message arriving on a secondary channel keys its binding under that channel. Outbound reply/react dispatch to a session by channel_id: a TeamLeader's reply egresses the bot of the channel its active binding names; a dispatcher reply uses the primary (first) channel. The dispatcher launch guard (assertRunnableChannelShape) now rejects only a channel naming an unwired (non-feishu) provider, not a >1 channel count; `bind_channel` requires an explicit channel_id when more than one channel is configured. The state row keeps the PRIMARY channel's bot identity. Single-channel dispatchers are unchanged. No config/state schema or path change and no operator action required. Not covered this slice: a dispatcher-initiated reply to a non-primary channel needs an explicit channel_id; cross-dispatcher bot_app_id uniqueness covers only the primary channel; non-feishu channel providers remain unwired."
27
+ },
28
+ {
29
+ "comment": "Multi-channel config support (issue #209): `dispatchers[].channels[]` now accepts more than one channel per dispatcher, requires unique dispatcher-local channel ids, and delegates provider-specific field validation to the selected channel provider's `readConfig` (resolved through the provider registry like agent runtimes; `builtin:feishu` is now a `channel` registry descriptor). Core no longer performs Feishu-specific channel *field* validation (non-empty `app_id`/`app_secret` and unknown-key rejection now fail loud from `@excitedjs/feishu-channel`, e.g. 'feishu channel config requires a non-empty app_id'), but core still owns the cross-dispatcher concern: two dispatchers (enabled or not) declaring the same Feishu `app_id` still fail loud at config load, the same story `dreamux serve` / `doctor` / `onboard` tell. No Rebuild required: a valid single-`builtin:feishu` config still loads and runs unchanged; only operators relying on the old core wording for empty/unknown Feishu fields will see new (channel-provider) error text. Live multi-channel routing is a follow-up slice, so a runnable dispatcher must still declare exactly one `builtin:feishu` channel — more than one channel, more than one feishu channel, or a non-feishu channel fails loud at the dispatcher runtime boundary (server start), not at config load."
30
+ },
31
+ {
32
+ "comment": "BREAKING: `dreamux onboard` is now provider-ref driven instead of Codex/Feishu specific. The old `--codex-bin`, `--bot-app-id`, and `--bot-app-secret` flags are removed; use `--agent`, `--agent-config-json`, `--channel`, and `--channel-config-json` so core writes provider-owned agent/channel config blocks without reading provider-specific fields. `dreamux doctor`, `dreamux onboard`, and `dreamux daemon install` now ask configured Agent Runtime and Channel providers for their own diagnostics and binary checks instead of hardcoding runtime-only checks in core. Rebuild: rerun `dreamux onboard` to recreate `~/.dreamux/config.json` when upgrading from an old Codex/Feishu-shaped local config."
33
+ },
34
+ {
35
+ "comment": "BREAKING: dispatchers[].channels[] now rejects two channels that use the same provider ref on one dispatcher (Decision #4, issue #209) — e.g. two builtin:feishu channels no longer load (config error: 'each provider may appear at most once per dispatcher'). This reverses the brief live multi-channel-per-provider capability. Rebuild: remove the duplicate-provider channel from ~/.dreamux/config.json (keep one) and re-run dreamux serve. The same change also RELAXES the former cross-dispatcher Feishu app_id uniqueness check — two dispatchers may now declare the same bot identity — and removes onboard's matching rollback-on-duplicate guard; that relaxation never blocks a previously valid config, so it requires no operator action."
36
+ },
37
+ {
38
+ "comment": "BREAKING: Replace the workspace-symlink bundled-skill model with role-gated runtime skill injection (issue #209 slice 6). `dreamux onboard` and dispatcher startup no longer create or write `<dispatcher cwd>/.codex/skills`; core now selects bundled `skillSources` for the Dispatcher and TeamLeader roles only and the runtime applies them (Codex via the app-server `skills/extraRoots/set` RPC after initialize and before thread start/resume, reapplied on restart; Claude Code via `--add-dir` for compatible sources). Ordinary teammates/team-members receive no bundled skills. Pre-existing old `.codex/skills` symlinks are NOT deleted and do not break startup — codex simply lists each bundled skill twice (an old repo-scoped copy plus the new user-scoped extra root). Rebuild: optionally delete `<dispatcher cwd>/.codex/skills` to remove the duplicate skill listing; no other action is required and dispatcher/teammate runtime behavior is otherwise unchanged."
39
+ },
40
+ {
41
+ "comment": "Runtime spawn env + log-path cleanup (issue #209 env-boundary decision). The agent-runtime spawn env is now the clean merge `{ ...process.env, ...injectEnv, ...extra_env }` (`injectEnv` is core's neutral, currently-empty host seam; `extra_env` is the provider's own config). Two operator-visible consequences: (1) the Codex app-server child no longer has `CODEX_HOME` stripped — it INHERITS the operator's ambient `CODEX_HOME` like vanilla codex, consistent with the 'dispatcher follows ~/.codex' invariant; an operator who set `CODEX_HOME` in their environment will now have codex use it. (2) core no longer prepends the dreamux package bin dir to the runtime PATH, so the model's bare `tm` invocation relies on the dreamux bins being on the ambient PATH (true for a global `npm install -g @excitedjs/dreamux`, which links `dreamux` and `tm`); the feishu/team/teammate MCP shims are unaffected (they spawn via an absolute path). Also relocates a TeamMate's app-server log to a flat `~/.dreamux/logs/codex-app-server/<runtime_id>.log` (and Claude Code stderr flat under `logs/claude-code/`); dispatcher log paths are byte-identical. Logs are rebuildable — old teammate logs simply remain at their old path. No operator action required."
42
+ },
43
+ {
44
+ "comment": "BREAKING: Channel binding tools move to the Team MCP (issue #209). Binding a channel to a Team/TeamLeader is a Dreamux core Team capability, so `bind_channel` and `transfer_back` now live on the Team MCP with a generalized parameter model — `bind_channel({ team_name, channel_id?, meta })` and `transfer_back({ channel_id?, meta })`, where `channel_id` selects the configured channel (optional; defaults to the dispatcher's sole channel) and `meta` is the provider-specific selector (Feishu: `{ chat_id }`), resolved by the channel's `resolveTarget(meta)` (group-only; `chat_type` is not required). Removed binding-specific `mcp.channel.*` admin methods are not aliased; agents discover binding on the Team MCP instead. The generic `channel-mcp` CLI still exists only as a provider-tool shim for surfaces such as Feishu `reply` / `react` / `list_chat_bots`; it does not own binding. Binding state, routing, P2P denial, and TeamLeader authorization remain core-owned and unchanged. Also: `builtin:claude-code` Dispatcher and TeamLeader launches now actually receive the bundled Dreamux skills via real `--add-dir` flags (previously they filtered to zero). The bundled skills are stored under `packages/dreamux/skills/.claude/skills/<name>/` so one shipped copy feeds both engines (Codex via `skills/extraRoots/set`, Claude Code via `--add-dir`); ordinary teammate/team_member roles still receive none, and there is no workspace mutation. Rebuild: no persisted state changes; any tooling or saved instructions that call removed binding methods under `mcp.channel.*` must switch to the Team MCP `bind_channel`/`transfer_back` (and pass the selector as `meta`, e.g. `{ \"chat_id\": \"...\" }`)."
45
+ },
46
+ {
47
+ "comment": "Add durable dispatcher-scoped scheduled tasks with a Cron MCP/admin surface, cron-jobs.json state, startup/doctor fail-loud validation, and defer-until-idle prompt-agent firing. Rebuild: cron-jobs.json is a new v1 persisted state file; if dreamux doctor reports it as incompatible, delete that file for the affected dispatcher and recreate scheduled jobs."
48
+ },
49
+ {
50
+ "comment": "BREAKING: restructure the dispatcher-service module to src/service/ with per-team TeammateCollection ownership and a symmetric per-agent state directory layout. DispatcherService now owns a teamScope=null TeammateCollection while each TeamService owns its own team-scoped collection (cached by team_id via TeamCollection.get, evicted on dissolve). State moves to a per-agent directory tree (team/<team>/teammate/<name>/ for members, the team leader at team/<team>/, dispatcher-owned teammates at teammate/<name>/); the legacy under-state leaves fail loud at startup with no migration (0.x policy).\nRebuild: delete ~/.dreamux/state and re-onboard the dispatcher."
51
+ },
52
+ {
53
+ "comment": "Team creation no longer fabricates a synthetic default TeamLeader prompt and auto-fires a turn. Previously `team.create` without an explicit `prompt` built a `\"You are the TeamLeader…\"` string and immediately submitted it, so a freshly created leader ran one throwaway turn before any real work or channel binding existed. Now the leader is started and left idle: its entity is persisted and recoverable from its record, and its runtime-native session materializes on start (eager runtimes, e.g. Codex) or on its first turn (lazy runtimes, e.g. Claude Code). Its first turn comes from a bound channel inbound, a dispatcher `send`, or an explicit `prompt` supplied at create time. The optional `team.create` `prompt` param is unchanged and still delivered as the leader's first turn when present. The `team.create` result `turn` is now `null` when no `prompt` was supplied."
54
+ }
55
+ ],
56
+ "patch": [
57
+ {
58
+ "comment": "Fix (completes #236): `team.dissolve` now syncs the cleaned worktree state to the TeamLeader and every member, so `team.status` / `teammate.status` no longer report `cleanup_state: managed-active` for a shared worktree that dissolve already removed (issue #237). Since a `team_member` / `team_leader` borrows the Team's one shared worktree and skips cleanup on its own `close` (#236), dissolve is the single authoritative cleanup site; it now propagates the identity `WorktreeManager.cleanup()` returned to the leader and members (via a new `TeammateService.applyWorktreeCleanup` / `TeammateOps.applyWorktreeCleanup`) so persisted and displayed state match reality everywhere. Behavior-only state-consistency fix; actual worktree cleanup was already correct."
59
+ },
60
+ {
61
+ "comment": "Fix: closing a team member (or the team leader outside dissolve) no longer cleans up the Team's shared worktree. A `team_member` / `team_leader` borrows the Team's one shared worktree (a member spawn injects the shared workspace; the leader sits at the team root), so `TeammateService.close()` used to run `WorktreeManager.cleanup()` on that shared worktree — `git worktree remove`-ing the live shared directory out from under the leader and every other member whenever it was `managed` + `delete-on-close` and clean/merged. close() now only cleans the worktree for a dispatcher-owned `teammate` (which owns its own worktree); the Team's shared worktree is owned by the Team and is cleaned exactly once at `dissolve`."
62
+ },
63
+ {
64
+ "comment": "Core feishu-name de-leak (issue #209): core no longer names the Feishu provider in its paths, log redaction, or dependency graph. The per-dispatcher channel log directory moves from `~/.dreamux/logs/feishu-channel/` to the neutral `~/.dreamux/logs/channel/` (path builders `feishuChannelLogDir`/`feishuChannelLogPath` -> `channelLogDir`/`channelLogPath`). The inbound-attachment cache is unchanged on disk (`~/.dreamux/cache/<id>/feishu-attachments/`) but core now passes only the neutral per-dispatcher cache root and the feishu-channel package owns the `feishu-attachments` subdir. Core drops its direct `@excitedjs/feishu-transport` dependency and the dead `pinoToTransportLogger` adapter (the channel package owns Feishu transport end-to-end); an ESLint guardrail now forbids core from importing the provider / Feishu-transport packages. Log redaction is a generic provider-agnostic secret policy (no `feishu.app_secret` by name). The dispatcher base prompt + team bind_channel tool descriptions are channel-generic (the `<channel source=...>` value carries the concrete provider). Rebuild: none required for state. The old `~/.dreamux/logs/feishu-channel/` directory is left orphaned (rebuildable logs; safe to delete); new channel logs land under `~/.dreamux/logs/channel/` on `daemon restart`."
65
+ },
66
+ {
67
+ "comment": "Core channel-config de-leak (issue #209). Core no longer reads or names any channel provider's config fields: the Feishu-specific config helpers (`dispatcherFeishuConfig` / `dispatcherFeishuChannels` / `dispatcherChannelId`), the `DispatcherFeishuConfig` type, and the dead `resolveBotSecret` / `DispatcherRow.bot_secret_ref` bot-secret-resolution path (orphaned by the channel-session convergence) are removed. A dispatcher's bot identity is now the channel provider's self-reported `getIdentity` (a neutral, opaque string core never interprets). Behavior change (issue #209 Decision #4): the former cross-dispatcher Feishu `app_id` uniqueness guard is removed — two dispatchers MAY now declare the same `app_id` (sharing one bot identity is an operator choice, not a config error), so `onboard` / `serve` / `doctor` no longer fail loud on a duplicate; an earlier #209 change file (multi-channel-config) described the now-superseded fail-loud behavior. Cross-process surface: the admin `dispatcher.status` response field `bot_app_id` is renamed to `channel_identity` (same value — the dispatcher's primary channel identity), and the matching `dispatcher ready` log field is renamed; the vestigial `bot-app-id` / `bot-secret-ref` flag-name mappings in the server-ctl admin CLI are removed (they mapped to params no admin method consumed, so removing them is a no-op). `channel_identity` is in-memory runtime state — `status.json` never carried it, so there is no state-file migration. No operator action required on upgrade."
68
+ },
69
+ {
70
+ "comment": "Fix: `DispatcherService.shutdown()` (via the teammate service `stopAll`) now drains in-flight best-effort settled-turn captures before resolving (issue #209 slice 6 repair). The settle hook dispatches the durable record/turns write (atomic temp+rename) fire-and-forget so it never perturbs the settle path; previously such a write could outlive shutdown and race teardown, surfacing as an ENOTEMPTY cleanup race on slower filesystems. Captures are now tracked and awaited at stop, so a caller awaiting shutdown observes no still-pending writes. No config/state schema or path change and no operator action required."
71
+ },
72
+ {
73
+ "comment": "Extract the built-in Claude Code runtime into the publishable @excitedjs/agent-runtime-claude-code package and depend on it by default (issue #209 slice 4). `builtin:claude-code` loads through the provider package loader/catalog and implements the neutral @excitedjs/dreamux-types AgentRuntimeProvider contract; core supplies only the neutral create-context values (identity, role, cwd, MCP descriptors, skill sources, state callbacks, path context, logger, and env injection seam). Claude Code-specific resident process, MCP config, diagnostics, config, and completion-delivery logic live in the runtime package. The builtin:claude-code alias, runtime semantics, config, paths, and state are unchanged; no operator action required on upgrade."
74
+ },
75
+ {
76
+ "comment": "Extract the built-in Codex runtime into the publishable @excitedjs/agent-runtime-codex package and depend on it by default (issue #209 slice 3). `builtin:codex` loads through the provider package loader/catalog and implements the neutral @excitedjs/dreamux-types AgentRuntimeProvider contract; core supplies only the neutral create-context values (identity, role, cwd, MCP descriptors, skill sources, state callbacks, path context, logger, and env injection seam). Codex-specific process, socket, handshake, diagnostics, config, and completion-delivery logic live in the runtime package. The builtin:codex alias, runtime semantics, config, paths, and state are unchanged; no operator action required on upgrade."
77
+ },
78
+ {
79
+ "comment": "Depend on the new declaration-only @excitedjs/dreamux-types package and re-export the provider-authoring contracts (provider ref/descriptor, agent-runtime, channel, turn, logger) from their existing internal paths (issue #209). Internal imports stay stable; no behavior change."
80
+ },
81
+ {
82
+ "comment": "Move the built-in Feishu channel implementation into the publishable @excitedjs/feishu-channel package and depend on it by default (issue #209 slice 5). Core resolves `builtin:feishu` through the Channel provider loader/catalog and passes the provider-validated config plus neutral host state/cache roots into `ChannelProvider.createSession`; there is no core-owned Feishu adapter path. The Feishu package owns the live session, target resolution, MCP descriptor, `reply` / `react` / `list_chat_bots` tool handlers, inbound normalization, access/trust behavior, and platform I/O. Routing, binding state, authorization, Team lifecycle, and the generic `channel.invoke_tool` conduit stay core-owned. No operator action required on upgrade."
83
+ },
84
+ {
85
+ "comment": "Refactor the external provider loader into a kind-agnostic package-loader skeleton (registry/provider-loader.ts) plus per-kind contract assertions for agentRuntime and channel, and add a channel provider loader that resolves builtin:feishu -> @excitedjs/feishu-channel through the shared built-in package alias map (issue #209). The public loadExternalAgentRuntimeProviders surface and its error classes/identities are unchanged; two contract-error message strings were reworded to be kind-neutral. The loader's already-loaded skip is implementation-aware, so a pre-registered built-in descriptor still gets its package implementation loaded. No production behavior change in this slice (config still feeds only npm: agentRuntime refs)."
86
+ },
87
+ {
88
+ "comment": "Support async Agent Runtime `readConfig` end-to-end (issue #209 types-API audit, F4). The host `AgentRuntimeProvider.readConfig` now allows `DispatcherProviderConfig | Promise<...>` and config load awaits it, matching `ChannelProvider.readConfig`; a rejected/thrown parse still fails loud. No operator-facing config/state change. Also drops two vestigial type re-exports from `agent-runtime/types.ts` that `@excitedjs/dreamux-types` no longer root-exports."
89
+ }
90
+ ],
91
+ "none": [
92
+ {
93
+ "comment": "Final-hardening test + docs only, no published-package change (issue #209): adds repo-wide package-boundary regression guards (tests/package-boundary-guards.test.ts) — Feishu/Lark SDK has a single owner, a default install bundles the builtin provider packages, and no provider/type package depends on @excitedjs/dreamux core — and records the epic acceptance inventory plus cited deferrals in the decision record. Nothing in the published package (the `files` allowlist) changes, so this carries no version bump and no changelog entry."
94
+ },
95
+ {
96
+ "comment": "Add a third gate (author-identity) to the Rush-managed pre-commit hook at common/git-hooks/pre-commit. The new gate mirrors the `commit-metadata` CI job semantics: it requires a well-formed non-local author email, allows *@users.noreply.github.com, and (optionally) rejects any email matching the operator-owned AUTHOR_EMAIL_DENYLIST_REGEX env var. Shortens the feedback loop for author-email misconfigurations from ~5 minutes (CI) to ~100 ms (pre-commit). Semantics deliberately match .github/workflows/ci.yml so local and CI agree on what a valid author identity is. No published package surface changes."
97
+ },
98
+ {
99
+ "comment": "Add `.github/workflows/promote-next.yml`, the operator-only manual gate for promoting the beta `next` branch into the stable `main` branch. The workflow enforces a strict fast-forward-only merge shape (topology guard + `git merge --ff-only`), pushes the fast-forwarded `main` back to origin using the built-in GITHUB_TOKEN, and relies on `release.yml` (`on.push.branches: [main, next]`) to then run the stable version+publish pipeline. No published package API changes; this is a release-process infrastructure change."
100
+ }
101
+ ],
102
+ "dependency": [
103
+ {
104
+ "comment": "Updating dependency \"@excitedjs/agent-runtime-claude-code\" to `0.2.0`"
105
+ },
106
+ {
107
+ "comment": "Updating dependency \"@excitedjs/agent-runtime-codex\" to `0.2.0`"
108
+ },
109
+ {
110
+ "comment": "Updating dependency \"@excitedjs/dreamux-types\" to `0.2.0`"
111
+ },
112
+ {
113
+ "comment": "Updating dependency \"@excitedjs/dreamux-utils\" to `0.2.0`"
114
+ },
115
+ {
116
+ "comment": "Updating dependency \"@excitedjs/feishu-channel\" to `1.0.0`"
117
+ }
118
+ ]
119
+ }
120
+ },
4
121
  {
5
122
  "version": "0.15.0",
6
123
  "tag": "@excitedjs/dreamux_v0.15.0",
package/CHANGELOG.md CHANGED
@@ -1,6 +1,42 @@
1
1
  # Change Log - @excitedjs/dreamux
2
2
 
3
- This log was last generated on Fri, 12 Jun 2026 07:04:47 GMT and should not be manually modified.
3
+ This log was last generated on Sat, 27 Jun 2026 12:09:24 GMT and should not be manually modified.
4
+
5
+ ## 0.16.0
6
+ Sat, 27 Jun 2026 12:09:24 GMT
7
+
8
+ ### Minor changes
9
+
10
+ - Add cron scheduling for every conversational agent: each TeamLeader now owns a durable cron scheduler and cron MCP surface alongside the dispatcher scheduler. TeamLeader cron jobs are stored at `~/.dreamux/state/<dispatcher-id>/team/<team-id>/cron-jobs.json` while retaining the existing job schema and dispatcher_id validation; Team isolation is by path. Non-closed Team schedulers are eager-armed at dispatcher boot without starting TeamLeader runtimes, and a scheduled fire lazy-starts the TeamLeader through its own `scheduledInput` path. Closed/dissolved Teams are not armed, and `team.dissolve` deletes that Team's cron jobs. Regular Team members still receive no cron MCP. No Rebuild required; delete a Team's `cron-jobs.json` manually only if you intentionally want to clear that TeamLeader's scheduled tasks without dissolving the Team.
11
+ - Emit neutral disableFeatures for agent runtime launches: every agent receives userInterrupt (the model-facing ask-the-user tool, which would wedge a turn in a channel-only environment), and dispatcher and TeamLeader launches additionally receive cron so runtimes with native scheduling defer to Dreamux's role-gated cron MCP. Core emits only neutral feature names and preserves any launch-specific disabled features.
12
+ - BREAKING: Channel binding store v2 + (channel_id, target_key) routing (issue #209). The persisted channel-binding store (`~/.dreamux/state/<dispatcher>/team/channel-bindings.json`) moves to `version: 2`: flat rows now carry `channel_id`, a provider-owned `target_key`, `target_type`, `display`, `canonical_url`, and a `meta` object (Feishu `chat_id` / `chat_type` move OUT of top-level columns INTO `meta`), alongside the existing team/leader/active/timestamp fields. The active uniqueness key is `(channel_id, target_key)`; one channel target is active for at most one Team (re-binding reassigns it). Inbound routing and TeamLeader authorization now key on `(channel_id, target_key)`: a bound bindable target routes to its TeamLeader, an unbound target and any P2P (non-bindable) target route to the dispatcher, and a P2P target can never be bound to a TeamLeader. Targets are resolved by the channel provider's `resolveTarget(meta)` (Feishu maps `{ chat_id }` to a stable group target); `channel_id` is the dispatcher-local `dispatchers[].channels[].id`. Team MCP owns `bind_channel({ team_name, channel_id?, meta })` and `transfer_back({ channel_id?, meta })`; the channel-tool MCP shim does not own binding. Rebuild: 0.x does not migrate binding state — a pre-v2 `channel-bindings.json` fails loud at `dreamux serve` / `dreamux doctor` (and on access) with guidance to delete `~/.dreamux/state/<dispatcher>/team/channel-bindings.json` and re-bind the channel(s); Team records and all other state load unchanged.
13
+ - Provider-specific channel tool plumbing is neutralized: the old `feishu-mcp` CLI subcommand is replaced by the generic `channel-mcp` stdio shim, while binding stays on the Team MCP. A Channel provider's `mcpServerDescriptor` supplies static `tools/list` metadata plus the shim args (`channel-mcp --provider <ref> --channel-id <id> --dispatcher <id> ...`); `tools/call` forwards raw `{ name, arguments }` through the single neutral admin method `channel.invoke_tool`, which routes to the live `ChannelSession.handleTool` or `ChannelProvider.handleSessionlessTool`. Core names no provider tool or selector. The per-dispatcher shim log directory moves from `~/.dreamux/logs/feishu-mcp/` to `~/.dreamux/logs/channel-mcp/`. Rebuild: none required for stored state. MCP server descriptors are rendered at every dispatcher boot and same-release shim/server IPC is regenerated on `daemon restart`. The old `~/.dreamux/logs/feishu-mcp/` directory is rebuildable and safe to delete. Any saved automation invoking `dreamux feishu-mcp` directly must switch to `dreamux channel-mcp`; any binding automation must use the Team MCP `bind_channel` / `transfer_back` tools, not the channel-tool shim.
14
+ - BREAKING: Channel targets now route through explicit channel providers and Team MCP keeps ownership of Team binding (issue #209). The old Feishu-specific `team.bind_group` / `team.transfer_channel_back` helpers and create-time `team.create.bind_group` convenience are removed WITHOUT compatibility aliases; use the Team MCP `bind_channel({ team_name, channel_id?, meta })` and `transfer_back({ channel_id?, meta })` tools instead. The generic `channel-mcp` stdio shim is a provider-tool bridge only: it exposes provider-owned tools such as Feishu `reply` / `react` and forwards calls through the neutral `channel.invoke_tool` admin method. Binding state, routing, and authorization stay core-owned through the ChannelBindingStore; provider-specific chat identifiers live inside provider-owned target metadata. Rebuild: none required for Team records or ledgers, but any saved automation or prompt that calls the removed Feishu binding helpers MUST switch to the Team MCP channel-binding tools.
15
+ - Live multi-channel runtime routing (issue #209). A dispatcher may now declare more than one builtin:feishu channel; the dispatcher service runs one live session per channel, each connecting as its own bot from that channel's config {app_id, app_secret}. Inbound events route by the originating channel's channel_id plus the provider-resolved target — `(channel_id, target_key)` — so a message arriving on a secondary channel keys its binding under that channel. Outbound reply/react dispatch to a session by channel_id: a TeamLeader's reply egresses the bot of the channel its active binding names; a dispatcher reply uses the primary (first) channel. The dispatcher launch guard (assertRunnableChannelShape) now rejects only a channel naming an unwired (non-feishu) provider, not a >1 channel count; `bind_channel` requires an explicit channel_id when more than one channel is configured. The state row keeps the PRIMARY channel's bot identity. Single-channel dispatchers are unchanged. No config/state schema or path change and no operator action required. Not covered this slice: a dispatcher-initiated reply to a non-primary channel needs an explicit channel_id; cross-dispatcher bot_app_id uniqueness covers only the primary channel; non-feishu channel providers remain unwired.
16
+ - Multi-channel config support (issue #209): `dispatchers[].channels[]` now accepts more than one channel per dispatcher, requires unique dispatcher-local channel ids, and delegates provider-specific field validation to the selected channel provider's `readConfig` (resolved through the provider registry like agent runtimes; `builtin:feishu` is now a `channel` registry descriptor). Core no longer performs Feishu-specific channel *field* validation (non-empty `app_id`/`app_secret` and unknown-key rejection now fail loud from `@excitedjs/feishu-channel`, e.g. 'feishu channel config requires a non-empty app_id'), but core still owns the cross-dispatcher concern: two dispatchers (enabled or not) declaring the same Feishu `app_id` still fail loud at config load, the same story `dreamux serve` / `doctor` / `onboard` tell. No Rebuild required: a valid single-`builtin:feishu` config still loads and runs unchanged; only operators relying on the old core wording for empty/unknown Feishu fields will see new (channel-provider) error text. Live multi-channel routing is a follow-up slice, so a runnable dispatcher must still declare exactly one `builtin:feishu` channel — more than one channel, more than one feishu channel, or a non-feishu channel fails loud at the dispatcher runtime boundary (server start), not at config load.
17
+ - BREAKING: `dreamux onboard` is now provider-ref driven instead of Codex/Feishu specific. The old `--codex-bin`, `--bot-app-id`, and `--bot-app-secret` flags are removed; use `--agent`, `--agent-config-json`, `--channel`, and `--channel-config-json` so core writes provider-owned agent/channel config blocks without reading provider-specific fields. `dreamux doctor`, `dreamux onboard`, and `dreamux daemon install` now ask configured Agent Runtime and Channel providers for their own diagnostics and binary checks instead of hardcoding runtime-only checks in core. Rebuild: rerun `dreamux onboard` to recreate `~/.dreamux/config.json` when upgrading from an old Codex/Feishu-shaped local config.
18
+ - BREAKING: dispatchers[].channels[] now rejects two channels that use the same provider ref on one dispatcher (Decision #4, issue #209) — e.g. two builtin:feishu channels no longer load (config error: 'each provider may appear at most once per dispatcher'). This reverses the brief live multi-channel-per-provider capability. Rebuild: remove the duplicate-provider channel from ~/.dreamux/config.json (keep one) and re-run dreamux serve. The same change also RELAXES the former cross-dispatcher Feishu app_id uniqueness check — two dispatchers may now declare the same bot identity — and removes onboard's matching rollback-on-duplicate guard; that relaxation never blocks a previously valid config, so it requires no operator action.
19
+ - BREAKING: Replace the workspace-symlink bundled-skill model with role-gated runtime skill injection (issue #209 slice 6). `dreamux onboard` and dispatcher startup no longer create or write `<dispatcher cwd>/.codex/skills`; core now selects bundled `skillSources` for the Dispatcher and TeamLeader roles only and the runtime applies them (Codex via the app-server `skills/extraRoots/set` RPC after initialize and before thread start/resume, reapplied on restart; Claude Code via `--add-dir` for compatible sources). Ordinary teammates/team-members receive no bundled skills. Pre-existing old `.codex/skills` symlinks are NOT deleted and do not break startup — codex simply lists each bundled skill twice (an old repo-scoped copy plus the new user-scoped extra root). Rebuild: optionally delete `<dispatcher cwd>/.codex/skills` to remove the duplicate skill listing; no other action is required and dispatcher/teammate runtime behavior is otherwise unchanged.
20
+ - Runtime spawn env + log-path cleanup (issue #209 env-boundary decision). The agent-runtime spawn env is now the clean merge `{ ...process.env, ...injectEnv, ...extra_env }` (`injectEnv` is core's neutral, currently-empty host seam; `extra_env` is the provider's own config). Two operator-visible consequences: (1) the Codex app-server child no longer has `CODEX_HOME` stripped — it INHERITS the operator's ambient `CODEX_HOME` like vanilla codex, consistent with the 'dispatcher follows ~/.codex' invariant; an operator who set `CODEX_HOME` in their environment will now have codex use it. (2) core no longer prepends the dreamux package bin dir to the runtime PATH, so the model's bare `tm` invocation relies on the dreamux bins being on the ambient PATH (true for a global `npm install -g @excitedjs/dreamux`, which links `dreamux` and `tm`); the feishu/team/teammate MCP shims are unaffected (they spawn via an absolute path). Also relocates a TeamMate's app-server log to a flat `~/.dreamux/logs/codex-app-server/<runtime_id>.log` (and Claude Code stderr flat under `logs/claude-code/`); dispatcher log paths are byte-identical. Logs are rebuildable — old teammate logs simply remain at their old path. No operator action required.
21
+ - BREAKING: Channel binding tools move to the Team MCP (issue #209). Binding a channel to a Team/TeamLeader is a Dreamux core Team capability, so `bind_channel` and `transfer_back` now live on the Team MCP with a generalized parameter model — `bind_channel({ team_name, channel_id?, meta })` and `transfer_back({ channel_id?, meta })`, where `channel_id` selects the configured channel (optional; defaults to the dispatcher's sole channel) and `meta` is the provider-specific selector (Feishu: `{ chat_id }`), resolved by the channel's `resolveTarget(meta)` (group-only; `chat_type` is not required). Removed binding-specific `mcp.channel.*` admin methods are not aliased; agents discover binding on the Team MCP instead. The generic `channel-mcp` CLI still exists only as a provider-tool shim for surfaces such as Feishu `reply` / `react` / `list_chat_bots`; it does not own binding. Binding state, routing, P2P denial, and TeamLeader authorization remain core-owned and unchanged. Also: `builtin:claude-code` Dispatcher and TeamLeader launches now actually receive the bundled Dreamux skills via real `--add-dir` flags (previously they filtered to zero). The bundled skills are stored under `packages/dreamux/skills/.claude/skills/<name>/` so one shipped copy feeds both engines (Codex via `skills/extraRoots/set`, Claude Code via `--add-dir`); ordinary teammate/team_member roles still receive none, and there is no workspace mutation. Rebuild: no persisted state changes; any tooling or saved instructions that call removed binding methods under `mcp.channel.*` must switch to the Team MCP `bind_channel`/`transfer_back` (and pass the selector as `meta`, e.g. `{ "chat_id": "..." }`).
22
+ - Add durable dispatcher-scoped scheduled tasks with a Cron MCP/admin surface, cron-jobs.json state, startup/doctor fail-loud validation, and defer-until-idle prompt-agent firing. Rebuild: cron-jobs.json is a new v1 persisted state file; if dreamux doctor reports it as incompatible, delete that file for the affected dispatcher and recreate scheduled jobs.
23
+ - BREAKING: restructure the dispatcher-service module to src/service/ with per-team TeammateCollection ownership and a symmetric per-agent state directory layout. DispatcherService now owns a teamScope=null TeammateCollection while each TeamService owns its own team-scoped collection (cached by team_id via TeamCollection.get, evicted on dissolve). State moves to a per-agent directory tree (team/<team>/teammate/<name>/ for members, the team leader at team/<team>/, dispatcher-owned teammates at teammate/<name>/); the legacy under-state leaves fail loud at startup with no migration (0.x policy).
24
+ Rebuild: delete ~/.dreamux/state and re-onboard the dispatcher.
25
+ - Team creation no longer fabricates a synthetic default TeamLeader prompt and auto-fires a turn. Previously `team.create` without an explicit `prompt` built a `"You are the TeamLeader…"` string and immediately submitted it, so a freshly created leader ran one throwaway turn before any real work or channel binding existed. Now the leader is started and left idle: its entity is persisted and recoverable from its record, and its runtime-native session materializes on start (eager runtimes, e.g. Codex) or on its first turn (lazy runtimes, e.g. Claude Code). Its first turn comes from a bound channel inbound, a dispatcher `send`, or an explicit `prompt` supplied at create time. The optional `team.create` `prompt` param is unchanged and still delivered as the leader's first turn when present. The `team.create` result `turn` is now `null` when no `prompt` was supplied.
26
+
27
+ ### Patches
28
+
29
+ - Fix (completes #236): `team.dissolve` now syncs the cleaned worktree state to the TeamLeader and every member, so `team.status` / `teammate.status` no longer report `cleanup_state: managed-active` for a shared worktree that dissolve already removed (issue #237). Since a `team_member` / `team_leader` borrows the Team's one shared worktree and skips cleanup on its own `close` (#236), dissolve is the single authoritative cleanup site; it now propagates the identity `WorktreeManager.cleanup()` returned to the leader and members (via a new `TeammateService.applyWorktreeCleanup` / `TeammateOps.applyWorktreeCleanup`) so persisted and displayed state match reality everywhere. Behavior-only state-consistency fix; actual worktree cleanup was already correct.
30
+ - Fix: closing a team member (or the team leader outside dissolve) no longer cleans up the Team's shared worktree. A `team_member` / `team_leader` borrows the Team's one shared worktree (a member spawn injects the shared workspace; the leader sits at the team root), so `TeammateService.close()` used to run `WorktreeManager.cleanup()` on that shared worktree — `git worktree remove`-ing the live shared directory out from under the leader and every other member whenever it was `managed` + `delete-on-close` and clean/merged. close() now only cleans the worktree for a dispatcher-owned `teammate` (which owns its own worktree); the Team's shared worktree is owned by the Team and is cleaned exactly once at `dissolve`.
31
+ - Core feishu-name de-leak (issue #209): core no longer names the Feishu provider in its paths, log redaction, or dependency graph. The per-dispatcher channel log directory moves from `~/.dreamux/logs/feishu-channel/` to the neutral `~/.dreamux/logs/channel/` (path builders `feishuChannelLogDir`/`feishuChannelLogPath` -> `channelLogDir`/`channelLogPath`). The inbound-attachment cache is unchanged on disk (`~/.dreamux/cache/<id>/feishu-attachments/`) but core now passes only the neutral per-dispatcher cache root and the feishu-channel package owns the `feishu-attachments` subdir. Core drops its direct `@excitedjs/feishu-transport` dependency and the dead `pinoToTransportLogger` adapter (the channel package owns Feishu transport end-to-end); an ESLint guardrail now forbids core from importing the provider / Feishu-transport packages. Log redaction is a generic provider-agnostic secret policy (no `feishu.app_secret` by name). The dispatcher base prompt + team bind_channel tool descriptions are channel-generic (the `<channel source=...>` value carries the concrete provider). Rebuild: none required for state. The old `~/.dreamux/logs/feishu-channel/` directory is left orphaned (rebuildable logs; safe to delete); new channel logs land under `~/.dreamux/logs/channel/` on `daemon restart`.
32
+ - Core channel-config de-leak (issue #209). Core no longer reads or names any channel provider's config fields: the Feishu-specific config helpers (`dispatcherFeishuConfig` / `dispatcherFeishuChannels` / `dispatcherChannelId`), the `DispatcherFeishuConfig` type, and the dead `resolveBotSecret` / `DispatcherRow.bot_secret_ref` bot-secret-resolution path (orphaned by the channel-session convergence) are removed. A dispatcher's bot identity is now the channel provider's self-reported `getIdentity` (a neutral, opaque string core never interprets). Behavior change (issue #209 Decision #4): the former cross-dispatcher Feishu `app_id` uniqueness guard is removed — two dispatchers MAY now declare the same `app_id` (sharing one bot identity is an operator choice, not a config error), so `onboard` / `serve` / `doctor` no longer fail loud on a duplicate; an earlier #209 change file (multi-channel-config) described the now-superseded fail-loud behavior. Cross-process surface: the admin `dispatcher.status` response field `bot_app_id` is renamed to `channel_identity` (same value — the dispatcher's primary channel identity), and the matching `dispatcher ready` log field is renamed; the vestigial `bot-app-id` / `bot-secret-ref` flag-name mappings in the server-ctl admin CLI are removed (they mapped to params no admin method consumed, so removing them is a no-op). `channel_identity` is in-memory runtime state — `status.json` never carried it, so there is no state-file migration. No operator action required on upgrade.
33
+ - Fix: `DispatcherService.shutdown()` (via the teammate service `stopAll`) now drains in-flight best-effort settled-turn captures before resolving (issue #209 slice 6 repair). The settle hook dispatches the durable record/turns write (atomic temp+rename) fire-and-forget so it never perturbs the settle path; previously such a write could outlive shutdown and race teardown, surfacing as an ENOTEMPTY cleanup race on slower filesystems. Captures are now tracked and awaited at stop, so a caller awaiting shutdown observes no still-pending writes. No config/state schema or path change and no operator action required.
34
+ - Extract the built-in Claude Code runtime into the publishable @excitedjs/agent-runtime-claude-code package and depend on it by default (issue #209 slice 4). `builtin:claude-code` loads through the provider package loader/catalog and implements the neutral @excitedjs/dreamux-types AgentRuntimeProvider contract; core supplies only the neutral create-context values (identity, role, cwd, MCP descriptors, skill sources, state callbacks, path context, logger, and env injection seam). Claude Code-specific resident process, MCP config, diagnostics, config, and completion-delivery logic live in the runtime package. The builtin:claude-code alias, runtime semantics, config, paths, and state are unchanged; no operator action required on upgrade.
35
+ - Extract the built-in Codex runtime into the publishable @excitedjs/agent-runtime-codex package and depend on it by default (issue #209 slice 3). `builtin:codex` loads through the provider package loader/catalog and implements the neutral @excitedjs/dreamux-types AgentRuntimeProvider contract; core supplies only the neutral create-context values (identity, role, cwd, MCP descriptors, skill sources, state callbacks, path context, logger, and env injection seam). Codex-specific process, socket, handshake, diagnostics, config, and completion-delivery logic live in the runtime package. The builtin:codex alias, runtime semantics, config, paths, and state are unchanged; no operator action required on upgrade.
36
+ - Depend on the new declaration-only @excitedjs/dreamux-types package and re-export the provider-authoring contracts (provider ref/descriptor, agent-runtime, channel, turn, logger) from their existing internal paths (issue #209). Internal imports stay stable; no behavior change.
37
+ - Move the built-in Feishu channel implementation into the publishable @excitedjs/feishu-channel package and depend on it by default (issue #209 slice 5). Core resolves `builtin:feishu` through the Channel provider loader/catalog and passes the provider-validated config plus neutral host state/cache roots into `ChannelProvider.createSession`; there is no core-owned Feishu adapter path. The Feishu package owns the live session, target resolution, MCP descriptor, `reply` / `react` / `list_chat_bots` tool handlers, inbound normalization, access/trust behavior, and platform I/O. Routing, binding state, authorization, Team lifecycle, and the generic `channel.invoke_tool` conduit stay core-owned. No operator action required on upgrade.
38
+ - Refactor the external provider loader into a kind-agnostic package-loader skeleton (registry/provider-loader.ts) plus per-kind contract assertions for agentRuntime and channel, and add a channel provider loader that resolves builtin:feishu -> @excitedjs/feishu-channel through the shared built-in package alias map (issue #209). The public loadExternalAgentRuntimeProviders surface and its error classes/identities are unchanged; two contract-error message strings were reworded to be kind-neutral. The loader's already-loaded skip is implementation-aware, so a pre-registered built-in descriptor still gets its package implementation loaded. No production behavior change in this slice (config still feeds only npm: agentRuntime refs).
39
+ - Support async Agent Runtime `readConfig` end-to-end (issue #209 types-API audit, F4). The host `AgentRuntimeProvider.readConfig` now allows `DispatcherProviderConfig | Promise<...>` and config load awaits it, matching `ChannelProvider.readConfig`; a rejected/thrown parse still fails loud. No operator-facing config/state change. Also drops two vestigial type re-exports from `agent-runtime/types.ts` that `@excitedjs/dreamux-types` no longer root-exports.
4
40
 
5
41
  ## 0.15.0
6
42
  Fri, 12 Jun 2026 07:04:47 GMT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@excitedjs/dreamux",
3
- "version": "0.16.0-beta.91",
3
+ "version": "0.16.0",
4
4
  "description": "Dreamux core host for multi-dispatcher agent orchestration through provider interfaces.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -27,11 +27,6 @@
27
27
  "CHANGELOG.json"
28
28
  ],
29
29
  "dependencies": {
30
- "@excitedjs/agent-runtime-claude-code": "0.2.0-beta.91",
31
- "@excitedjs/agent-runtime-codex": "0.2.0-beta.91",
32
- "@excitedjs/dreamux-types": "0.2.0-beta.91",
33
- "@excitedjs/dreamux-utils": "0.2.0-beta.91",
34
- "@excitedjs/feishu-channel": "1.0.0-beta.91",
35
30
  "@excitedjs/tm": "2.4.1",
36
31
  "croner": "^10.0.1",
37
32
  "smol-toml": "^1.6.1",
@@ -39,7 +34,12 @@
39
34
  "@clack/prompts": "^1.5.0",
40
35
  "execa": "^9.6.1",
41
36
  "pino": "^9.5.0",
42
- "plist": "^5.0.0"
37
+ "plist": "^5.0.0",
38
+ "@excitedjs/agent-runtime-claude-code": "0.2.0",
39
+ "@excitedjs/dreamux-types": "0.2.0",
40
+ "@excitedjs/dreamux-utils": "0.2.0",
41
+ "@excitedjs/agent-runtime-codex": "0.2.0",
42
+ "@excitedjs/feishu-channel": "1.0.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/node": "^22.10.0",