Commit Graph

7 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
80ee9082f3 feat(guild): announce channel type + agent-presence + busy-discard
Phase 1 of DIALECTIC-V2 — adds Fabric infrastructure for
system-broadcast channels with HF-status-aware delivery filtering.

New channel x_type 'announce':
- channels.entity.ts + channels.service.ts + realtime.gateway.ts
  enum + union extended.
- computeDelivery() adds an 'announce' case: recipient with
  presence='busy' → 'skip' (discarded silently); other presences →
  'observer' (delivered, no wake). System-broadcast semantics —
  agents proactively check their announce inbox when they're ready,
  not interrupted out of band.
- messaging.controller POST guard: announce-type channels reject
  posts that don't present x-fabric-system-key header matching
  FABRIC_BACKEND_GUILD_SYSTEM_API_KEY env. Empty env = no system
  caller is valid (closed-by-default).

New entity + module agent_presences:
- agent-presence.entity.ts: per-user (userId PK) status enum
  (idle/on_call/busy/exhausted/offline/unknown), source tag, updatedAt
- agent-presence.service.ts: getStatus/getStatusMap (bulk for
  delivery-time fanout) + setStatus (upsert)
- agent-presence.controller.ts: GET + PUT /agents/:userId/presence
- agent-presence.module.ts: TypeORM forFeature + wired into AppModule
- buildTypeOrmConfig() entities list extended

RealtimeGateway wiring:
- New optional  field on the gateway (typed loosely to avoid
  circular import). RealtimeModule.onModuleInit() assigns from the
  injected AgentPresenceService — degrades gracefully (no busy-discard,
  treat all as 'unknown') if presence wiring is ever removed.
- emitMessageCreated pre-loads presence per fanout only when xType is
  'announce' (other xTypes bypass the lookup entirely).

Note: actual presence data writes come from Fabric.OpenclawPlugin's
presence-sync loop (separate commit on that submodule); without it,
all rows are 'unknown' and announce delivery falls through to the
default observer behavior (no busy filtering). System-only POST gate
is independent and works immediately.

See /home/hzhang/arch/DIALECTIC-V2-DESIGN.md sections 7 + 10 Phase 1.
2026-05-23 11:31:47 +01:00
b1f7467161 feat(guild): add 'dm' x-type (private 1:1, always-wake)
channel enum + X_TYPES + realtime XType gain 'dm'. dm channels are
forced private (never public) and non-unique (no dedup; create()
always makes a fresh one). computeWakeup: dm wakes every non-author
participant unconditionally (no rotation / no wake_mapping). The
message.created realtime payload now carries xType so the plugin can
treat dm specially.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 09:18:19 +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
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
nav
d9c5175233 feat: bootstrap from Fabric monorepo 2026-05-13 07:06:03 +00:00