Commit Graph

10 Commits

Author SHA1 Message Date
cb7b3bb5fe feat(channel-discovery): add purpose column + PATCH /api/channels/:id
Adds a free-form 'purpose' text field on Channel so agents (or anyone
creating a channel via API) can describe what the channel is for —
'debate broadcasts', 'security alerts', etc. — and other agents can
later find the right channel by intent rather than channel id.

Wire:
  - Channel.purpose (text, nullable; TypeORM synchronize auto-adds)
  - POST /api/channels accepts optional 'purpose' in body
  - GET /api/channels returns purpose on every row (already returns the
    full entity via {...c})
  - PATCH /api/channels/:id { purpose } — member-or-public auth (mirrors
    the close() rule). Today only 'purpose' is patchable; other fields
    would get their own typed branch.

Frontend create form continues to omit the field — purpose stays optional.
This pairs with Fabric.OpenclawPlugin's fabric-channel-set-purpose tool +
fabric-channel-list returning purpose, so agent workflows can say 'find
an announce channel about X' instead of pinning a UUID.
2026-05-23 19:22:00 +01:00
b3fcefb5ec feat(channels): bypass-list for discuss/work rotation
- channel_turn_state.bypass_user_ids: order and bypass form a disjoint
  partition of the channel members; bypass excluded from rotation.
- initForChannel(channelId, members, bypass=[]) computes order = members
  − bypass; create() passes bypassUserIds (∩ members) for discuss/work.
- pushFrame() enforces mention nesting cap: max 4 sub-frames (5 levels
  incl. root); overflow evicts the bottom-most (root->A..D + E => root->B..E).
- mention sites use pushFrame so bypass members are only transiently
  pulled in via @-mention, then return to bypass on pop.
- moveToBypass(): move an order member to bypass mid-rotation; if current
  speaker, successor takes over. onMemberRemoved also strips bypass.
- POST /channels/:id/bypass; GET :id/members now returns {userId,bypass}.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 19:26:18 +01:00
8c41d23a9c refactor: migrate to ES modules
package.json type=module, tsconfig module/moduleResolution=NodeNext,
target es2022, explicit .js on all relative imports. Center: jsonwebtoken
& bcryptjs switched to default imports (ESM/CJS interop). Verified:
builds, boots, full auth + plugin round-trip work under ESM.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 18:47:36 +01:00
9670da400e feat(guild): closed channel (discussion-complete support)
Channel.closed; POST /channels/:id/close (member-only); message/command
posts on closed channel -> 409 {error:channel_closed}; GET history still
allowed; listForUser carries closed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 16:52:43 +01:00
182cfb3c41 feat(guild): GET /channels/:id/members
List explicit channel members (userIds) for the split members sidebar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 15:00:24 +01:00
6b993522cf feat(guild): wake_mapping, per-recipient wakeup, discuss/work turn engine, channel join/leave
- wake_mapping table; triage onDuty (auto-added member) / custom listeners
- per-recipient wakeup metadata on message.created (one message-id; added
  only at push). Rules: author=false; triage/custom=wake_mapping only;
  general=all; report=none
- discuss/work rotation: channel_turn_state (order/currentSpeaker/round
  events/cross-round no-reply streak); null activation, queue-jump,
  /no-reply pass, all-/no-reply pause, end-of-round shuffle (trailing
  no-reply run to tail, head shuffled, first != last normal speaker)
- slash-command registry (/no-reply, /force-proceed); registered commands
  intercepted and never delivered; guild-authored /ack persisted
- POST /channels/:id/join|leave; leave cleans channel_members, wake_mapping
  and turn-state order

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:51:09 +01:00
605d3ac092 feat(guild): required channel x_type enum
Channel.x_type enum(general|work|report|discuss|triage|custom); required
and validated on channel creation (400 if missing/invalid).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 09:35:36 +01:00
774dff11ba feat(guild): channel membership + public visibility
- new channel_members table; creator always added, plus selected members
- Channel.isPublic (default false): public channels visible to all guild
  members; non-public only to explicit members
- GET /channels filters to channels visible to the requesting user

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 09:09:41 +01:00
root
b27cb0c2e1 feat(guild): validate bearer tokens via center introspection 2026-05-13 07:59:57 +00:00
nav
d9c5175233 feat: bootstrap from Fabric monorepo 2026-05-13 07:06:03 +00:00