Create a bot in the Discord Developer Portal.
+ + +Create a Slack App with Socket Mode enabled. Requires an App-Level token (xapp-) and Bot token (xoxb-).
+ Create a bot via @BotFather and paste the token below. +
+ + ++ WhatsApp uses QR code pairing (Baileys WebSocket protocol). No bot token required. + The instance must be running to display the QR code. +
+ +Scan with WhatsApp → Linked Devices → Link a Device
+Refreshing every 3s…
+ } @else { +Fetching QR code…
+ } +No instances yet. Create one →
+ } +Instance not found.
+ } + `, + styles: [` + .center-spinner { display: flex; justify-content: center; padding: 64px; } + .detail-page { display: flex; flex-direction: column; gap: 16px; } + .detail-header { display: flex; align-items: center; gap: 12px; } + .detail-title { display: flex; align-items: center; gap: 10px; } + .detail-title h1 { font-size: 22px; font-weight: 700; margin: 0; } + .spacer { flex: 1; } + .meta-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; } + .model-chip { font-size: 11px; padding: 2px 10px; border-radius: 999px; + background: rgba(59,130,246,.12); color: var(--accent-blue); } + .meta-item { display: flex; align-items: center; gap: 4px; font-size: 12px; color: var(--text-secondary); } + .meta-item mat-icon { font-size: 14px; width: 14px; height: 14px; } + .description { color: var(--text-secondary); font-size: 13px; } + .stats-bar { display: flex; gap: 24px; background: var(--bg-surface); + border: 1px solid var(--border); border-radius: var(--radius-md); padding: 12px 20px; } + .stat-item { display: flex; align-items: center; gap: 10px; flex: 1; } + .stat-l { font-size: 10px; color: var(--text-secondary); text-transform: uppercase; width: 28px; } + .bar-wrap { flex: 1; height: 6px; background: var(--border); border-radius: 3px; overflow: hidden; } + .bar { height: 100%; background: var(--accent-blue); border-radius: 3px; transition: width .5s ease; } + .bar.mem { background: var(--accent-green); } + .stat-v { font-size: 11px; color: var(--text-secondary); white-space: nowrap; } + .tab-body { padding: 20px 0; } + .error-state { color: var(--accent-red); } + `], +}) +export class InstanceDetailComponent implements OnInit { + readonly id = input.required{{ store.error() }}
+ } @else { +{{ logText() }}
+ Loading…
+ } + +No boards yet. Create one to get started.
+ } + } +Board not found.
+ } + `, + styles: [` + .center-spinner { display: flex; justify-content: center; padding: 64px; } + .board-page { display: flex; flex-direction: column; height: 100%; gap: 16px; } + .board-header { display: flex; align-items: center; gap: 12px; } + .board-title { font-size: 22px; font-weight: 700; margin: 0; } + .spacer { flex: 1; } + .card-count { font-size: 13px; color: var(--text-secondary); } + .columns-row { display: flex; gap: 16px; overflow-x: auto; align-items: flex-start; padding-bottom: 16px; } + .column { min-width: 260px; max-width: 260px; background: var(--bg-surface); + border: 1px solid var(--border); border-radius: var(--radius-md); + display: flex; flex-direction: column; } + .col-header { display: flex; align-items: center; gap: 8px; padding: 12px 14px 10px; + border-top: 3px solid var(--border); border-radius: var(--radius-md) var(--radius-md) 0 0; } + .col-name { font-weight: 600; font-size: 13px; flex: 1; } + .col-count { font-size: 11px; color: var(--text-secondary); + background: var(--border); padding: 1px 6px; border-radius: 999px; } + .wip-badge { font-size: 10px; color: var(--accent-amber); border: 1px solid var(--accent-amber); + padding: 1px 5px; border-radius: 999px; } + .cards-list { padding: 8px; display: flex; flex-direction: column; gap: 8px; + min-height: 80px; } + .card { background: var(--bg-base); border: 1px solid var(--border); border-radius: var(--radius-sm); + display: flex; cursor: grab; transition: box-shadow .15s; } + .card:hover { box-shadow: 0 2px 10px rgba(0,0,0,.25); } + .card.cdk-drag-dragging { opacity: .7; box-shadow: 0 6px 24px rgba(0,0,0,.4); } + .card-drag-handle { display: flex; align-items: flex-start; padding: 8px 4px 8px 6px; + cursor: grab; color: var(--text-secondary); } + .card-drag-handle mat-icon { font-size: 16px; width: 16px; height: 16px; } + .card-body { flex: 1; padding: 8px 10px 8px 0; } + .card-title { font-size: 13px; font-weight: 500; margin-bottom: 4px; line-height: 1.4; } + .card-desc { font-size: 11px; color: var(--text-secondary); margin-bottom: 6px; + display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } + .card-footer { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; } + .priority-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; } + .label-chip { font-size: 10px; padding: 1px 6px; border-radius: 999px; + background: rgba(59,130,246,.12); color: var(--accent-blue); } + .due-date { display: flex; align-items: center; gap: 2px; font-size: 11px; + color: var(--text-secondary); } + .due-date.overdue { color: var(--accent-red); } + .due-date mat-icon { font-size: 12px; width: 12px; height: 12px; } + .bot-icon { font-size: 12px; width: 12px; height: 12px; color: var(--accent-green); } + .empty-col { font-size: 12px; color: var(--text-secondary); text-align: center; + padding: 16px; border: 1px dashed var(--border); border-radius: var(--radius-sm); } + .card-placeholder { border: 2px dashed var(--accent-blue); border-radius: var(--radius-sm); + height: 60px; background: rgba(59,130,246,.06); } + .cdk-drop-list-dragging .card:not(.cdk-drag-placeholder) { transition: transform 250ms cubic-bezier(0,0,.2,1); } + .error-state { color: var(--accent-red); } + .overlay { position: fixed; inset: 0; background: rgba(0,0,0,.5); + display: flex; align-items: center; justify-content: center; z-index: 1000; } + .add-dialog { background: var(--bg-surface); border: 1px solid var(--border); + border-radius: var(--radius-md); padding: 24px; min-width: 380px; } + .add-dialog h2 { margin: 0 0 20px; font-size: 18px; font-weight: 700; } + .full-width { width: 100%; } + .half-width { width: 160px; } + .dialog-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px; } + `], +}) +export class KanbanBoardComponent implements OnInit, OnDestroy { + readonly id = input.required{{ rule.cronExpression }} → switch to
+ {{ rule.targetModel }}
+ } @else {
+ Manual override → {{ rule.targetModel }}
+ }
+ No auto-switch rules configured.
+ } + + @if (showForm()) { +No token usage recorded yet.
+ } +| Instance | ++ {{ instanceName(row.instanceId) }} + | +Model | +{{ row.model }} | +Total Tokens | +{{ row.totalTokens | number }} | +Est. Cost | +{{ (row.estimatedCostUsd ?? 0) | currency:'USD':'symbol':'1.4-4' }} | +Rules | +
+
+ |
+
|---|
Configure per-instance rules to automatically switch models based on token thresholds or a schedule.
+ @for (inst of instances(); track inst.id) { +No local models. Pull one above.
+ } +No learnings recorded yet.
+ } + + @if (auth.isOperator()) { +