@pellux/goodvibes-tui 0.24.1 → 0.26.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.md +8 -0
- package/README.md +1 -1
- package/docs/foundation-artifacts/operator-contract.json +2419 -1040
- package/package.json +2 -2
- package/src/daemon/handlers/calendar/caldav-client.ts +661 -0
- package/src/daemon/handlers/calendar/ics.ts +556 -0
- package/src/daemon/handlers/calendar/index.ts +316 -0
- package/src/daemon/handlers/context.ts +29 -0
- package/src/daemon/handlers/contracts.ts +77 -0
- package/src/daemon/handlers/credentials.ts +129 -0
- package/src/daemon/handlers/drafts/draft-store.ts +427 -0
- package/src/daemon/handlers/drafts/index.ts +17 -0
- package/src/daemon/handlers/drafts/register.ts +331 -0
- package/src/daemon/handlers/email/config.ts +164 -0
- package/src/daemon/handlers/email/imap-connector.ts +441 -0
- package/src/daemon/handlers/email/imap-parsing.ts +499 -0
- package/src/daemon/handlers/email/index.ts +43 -0
- package/src/daemon/handlers/email/read-handlers.ts +80 -0
- package/src/daemon/handlers/email/runtime.ts +140 -0
- package/src/daemon/handlers/email/smtp-connector.ts +557 -0
- package/src/daemon/handlers/email/validation.ts +147 -0
- package/src/daemon/handlers/email/write-handlers.ts +133 -0
- package/src/daemon/handlers/errors.ts +18 -0
- package/src/daemon/handlers/inbox/cursor-store.ts +290 -0
- package/src/daemon/handlers/inbox/index.ts +210 -0
- package/src/daemon/handlers/inbox/mapping.ts +192 -0
- package/src/daemon/handlers/inbox/poller.ts +155 -0
- package/src/daemon/handlers/inbox/provider-adapter.ts +156 -0
- package/src/daemon/handlers/inbox/providers/discord.ts +251 -0
- package/src/daemon/handlers/inbox/providers/email.ts +151 -0
- package/src/daemon/handlers/inbox/providers/imap-client.ts +300 -0
- package/src/daemon/handlers/inbox/providers/route-util.ts +23 -0
- package/src/daemon/handlers/inbox/providers/slack.ts +262 -0
- package/src/daemon/handlers/index.ts +107 -0
- package/src/daemon/handlers/register.ts +161 -0
- package/src/daemon/handlers/remote/backends/cloud-terminal.ts +142 -0
- package/src/daemon/handlers/remote/backends/docker.ts +79 -0
- package/src/daemon/handlers/remote/backends/index.ts +40 -0
- package/src/daemon/handlers/remote/backends/local-process.ts +113 -0
- package/src/daemon/handlers/remote/backends/process-runner.ts +127 -0
- package/src/daemon/handlers/remote/backends/ssh.ts +125 -0
- package/src/daemon/handlers/remote/backends/types.ts +97 -0
- package/src/daemon/handlers/remote/dispatcher.ts +181 -0
- package/src/daemon/handlers/remote/index.ts +119 -0
- package/src/daemon/handlers/remote/peer-registry.ts +357 -0
- package/src/daemon/handlers/remote/service.ts +191 -0
- package/src/daemon/handlers/routing/inbox-bridge.ts +71 -0
- package/src/daemon/handlers/routing/index.ts +261 -0
- package/src/daemon/handlers/routing/route-store.ts +319 -0
- package/src/daemon/handlers/routing/routing-resolver.ts +75 -0
- package/src/daemon/handlers/sqlite-store.ts +124 -0
- package/src/daemon/handlers/triage/index.ts +57 -0
- package/src/daemon/handlers/triage/integration.ts +212 -0
- package/src/daemon/handlers/triage/pipeline.ts +273 -0
- package/src/daemon/handlers/triage/scorer.ts +287 -0
- package/src/daemon/handlers/triage/tagger/discord.ts +186 -0
- package/src/daemon/handlers/triage/tagger/imap.ts +383 -0
- package/src/daemon/handlers/triage/tagger/index.ts +184 -0
- package/src/daemon/handlers/triage/tagger/shared.ts +70 -0
- package/src/daemon/handlers/triage/tagger/slack.ts +69 -0
- package/src/daemon/handlers/triage/types.ts +50 -0
- package/src/runtime/services.ts +48 -0
- package/src/version.ts +1 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Triage tagger — Slack provider.
|
|
3
|
+
//
|
|
4
|
+
// Applies a triage label as a Slack message reaction (reactions.add). The bot
|
|
5
|
+
// token is resolved per-apply from the daemon credential store and is never
|
|
6
|
+
// logged or returned. `already_reacted` is treated as idempotent success.
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
|
|
9
|
+
import type { HandlerContext } from '../../context.ts';
|
|
10
|
+
import type { DaemonCredentialStore } from '../../credentials.ts';
|
|
11
|
+
import { HandlerError } from '../../errors.ts';
|
|
12
|
+
import type { InboundChannelItem } from '../types.ts';
|
|
13
|
+
import type { ApplyTagsResult, TaggerProviderConfig } from './shared.ts';
|
|
14
|
+
import { slackEmojiForTag, stringMeta } from './shared.ts';
|
|
15
|
+
|
|
16
|
+
export async function applySlack(
|
|
17
|
+
item: InboundChannelItem,
|
|
18
|
+
tags: string[],
|
|
19
|
+
providers: TaggerProviderConfig,
|
|
20
|
+
credentials: DaemonCredentialStore,
|
|
21
|
+
fetchImpl: typeof fetch,
|
|
22
|
+
ctx: HandlerContext,
|
|
23
|
+
base: ApplyTagsResult,
|
|
24
|
+
): Promise<ApplyTagsResult> {
|
|
25
|
+
const cfg = providers.slack;
|
|
26
|
+
if (!cfg) return { ...base, reason: 'slack-not-configured' };
|
|
27
|
+
const channel = stringMeta(item, 'channelId') ?? item.conversationId;
|
|
28
|
+
const ts = stringMeta(item, 'ts') ?? stringMeta(item, 'messageTs');
|
|
29
|
+
if (!channel || !ts) return { ...base, reason: 'slack-missing-target' };
|
|
30
|
+
if (tags.length === 0) return { ...base, reason: 'no-tags' };
|
|
31
|
+
|
|
32
|
+
const token = await credentials.resolveConfigSecret(cfg.tokenConfigKey);
|
|
33
|
+
if (!token) return { ...base, reason: 'slack-no-credentials' };
|
|
34
|
+
|
|
35
|
+
const applied: string[] = [];
|
|
36
|
+
for (const tag of tags) {
|
|
37
|
+
const emoji = slackEmojiForTag(tag);
|
|
38
|
+
const response = await fetchImpl('https://slack.com/api/reactions.add', {
|
|
39
|
+
method: 'POST',
|
|
40
|
+
headers: {
|
|
41
|
+
Authorization: `Bearer ${token}`,
|
|
42
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
43
|
+
},
|
|
44
|
+
body: JSON.stringify({ channel, timestamp: ts, name: emoji }),
|
|
45
|
+
});
|
|
46
|
+
const payload = (await response.json().catch(() => ({}))) as {
|
|
47
|
+
ok?: boolean;
|
|
48
|
+
error?: string;
|
|
49
|
+
};
|
|
50
|
+
if (!response.ok) {
|
|
51
|
+
throw new HandlerError(
|
|
52
|
+
`Slack reactions.add HTTP ${response.status}`,
|
|
53
|
+
'TRIAGE_SLACK_TAG_FAILED',
|
|
54
|
+
502,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
// 'already_reacted' is an idempotent success for our purposes.
|
|
58
|
+
if (payload.ok !== true && payload.error !== 'already_reacted') {
|
|
59
|
+
ctx.logger.warn('triage: slack reaction rejected', { error: payload.error });
|
|
60
|
+
throw new HandlerError(
|
|
61
|
+
`Slack reactions.add rejected: ${payload.error ?? 'unknown'}`,
|
|
62
|
+
'TRIAGE_SLACK_TAG_FAILED',
|
|
63
|
+
502,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
applied.push(tag);
|
|
67
|
+
}
|
|
68
|
+
return { surface: item.surface, itemId: item.id, appliedTags: applied, skipped: false };
|
|
69
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Daemon-internal triage domain types.
|
|
3
|
+
//
|
|
4
|
+
// `InboundChannelItem` is the daemon-internal shape the inbox poller produces
|
|
5
|
+
// and the triage pipeline scores. It is NOT an SDK catalog contract: the
|
|
6
|
+
// published `channels.inbox.list` output schema (CHANNEL_INBOX_ITEM_SCHEMA) is
|
|
7
|
+
// owned by the SDK and never re-declared here. This is the internal poller
|
|
8
|
+
// item per the handoff doc — it carries `fromDigest` (never a raw sender id),
|
|
9
|
+
// `subjectPreview`/`bodyPreview` (PII-stripped, length-bounded) and an opaque
|
|
10
|
+
// `metadata` bag the tagger reads provider targeting from (imapUid, channelId,
|
|
11
|
+
// Slack ts, Discord messageId/threadId).
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
/** Triage label assigned by the scorer. */
|
|
15
|
+
export type TriageLabel = 'spam' | 'priority' | 'normal';
|
|
16
|
+
|
|
17
|
+
/** 1:1 vs group/channel/thread conversation hint (priority signal). */
|
|
18
|
+
export type ConversationKind = 'direct' | 'group' | 'channel' | 'thread' | 'service';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Internal inbound feed item. Mirrors the handoff `InboundChannelItem` shape
|
|
22
|
+
* plus the optional fields the scorer/tagger consult. `surface` is the provider
|
|
23
|
+
* family ('email' | 'imap' | 'slack' | 'discord' | ...) the tagger dispatches
|
|
24
|
+
* on; `provider` is the handoff-facing provider id. They are usually equal.
|
|
25
|
+
*/
|
|
26
|
+
export interface InboundChannelItem {
|
|
27
|
+
/** Stable, provider-scoped dedup key. */
|
|
28
|
+
readonly id: string;
|
|
29
|
+
/** Provider family the tagger dispatches on (email/imap/slack/discord/...). */
|
|
30
|
+
readonly surface: string;
|
|
31
|
+
/** Handoff-facing provider id ("slack" | "discord" | "email" | ...). */
|
|
32
|
+
readonly provider?: string;
|
|
33
|
+
readonly kind?: 'dm' | 'thread' | 'mention' | 'reaction';
|
|
34
|
+
/** SHA-256 first-N of sender external id — NEVER a raw identifier. */
|
|
35
|
+
readonly fromDigest?: string;
|
|
36
|
+
/** Conversation id (Slack/Discord channel, IMAP mailbox-scoped). */
|
|
37
|
+
readonly conversationId?: string;
|
|
38
|
+
readonly conversationKind?: ConversationKind;
|
|
39
|
+
/** Display subject (<= 200 chars). */
|
|
40
|
+
readonly subject?: string;
|
|
41
|
+
/** Display body preview (<= 500 chars, PII-stripped). Alias: bodyPreview. */
|
|
42
|
+
readonly snippet?: string;
|
|
43
|
+
/** Optional daemon route binding id. */
|
|
44
|
+
readonly routeId?: string;
|
|
45
|
+
/** Unix ms. */
|
|
46
|
+
readonly receivedAt?: number;
|
|
47
|
+
readonly unread?: boolean;
|
|
48
|
+
/** Opaque provider targeting bag (imapUid/uid, channelId, ts, messageId, threadId). */
|
|
49
|
+
readonly metadata?: Record<string, unknown>;
|
|
50
|
+
}
|
package/src/runtime/services.ts
CHANGED
|
@@ -87,6 +87,19 @@ import {
|
|
|
87
87
|
type WorkflowServices,
|
|
88
88
|
} from '@pellux/goodvibes-sdk/platform/tools';
|
|
89
89
|
import { WorkPlanStore } from '../work-plans/work-plan-store.ts';
|
|
90
|
+
import {
|
|
91
|
+
registerDaemonHandlers,
|
|
92
|
+
type DaemonHandlerSurfaces,
|
|
93
|
+
} from '../daemon/handlers/index.ts';
|
|
94
|
+
import type { HandlerContext, HandlerLogger } from '../daemon/handlers/context.ts';
|
|
95
|
+
import { createDaemonCredentialStore } from '../daemon/handlers/credentials.ts';
|
|
96
|
+
import { registerRouting } from '../daemon/handlers/routing/index.ts';
|
|
97
|
+
import { registerInboxMethods } from '../daemon/handlers/inbox/index.ts';
|
|
98
|
+
import { registerTriagedInbox } from '../daemon/handlers/triage/index.ts';
|
|
99
|
+
import { registerDraftMethods } from '../daemon/handlers/drafts/index.ts';
|
|
100
|
+
import { registerCalendar } from '../daemon/handlers/calendar/index.ts';
|
|
101
|
+
import { registerEmailMethods } from '../daemon/handlers/email/index.ts';
|
|
102
|
+
import { registerRemoteSurface } from '../daemon/handlers/remote/index.ts';
|
|
90
103
|
|
|
91
104
|
const REGULAR_KNOWLEDGE_DB_FILE = 'knowledge-wiki.sqlite';
|
|
92
105
|
const HOME_GRAPH_KNOWLEDGE_DB_FILE = 'knowledge-home-graph.sqlite';
|
|
@@ -215,6 +228,7 @@ export interface RuntimeServices {
|
|
|
215
228
|
readonly providerRegistry: ProviderRegistry;
|
|
216
229
|
readonly toolLLM: ToolLLM;
|
|
217
230
|
readonly distributedRuntime: DistributedRuntimeManager;
|
|
231
|
+
readonly daemonHandlers: DaemonHandlerSurfaces;
|
|
218
232
|
readonly remoteRunnerRegistry: RemoteRunnerRegistry;
|
|
219
233
|
readonly remoteSupervisor: RemoteSupervisor;
|
|
220
234
|
readonly sessionMemoryStore: SessionMemoryStore;
|
|
@@ -517,6 +531,39 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
517
531
|
approvalBridge: approvalBroker,
|
|
518
532
|
automationBridge: automationManager,
|
|
519
533
|
});
|
|
534
|
+
|
|
535
|
+
// Daemon handler surfaces: attach HOST handlers to the SDK-auto-registered
|
|
536
|
+
// builtin gateway descriptors (channels.* / email.* / calendar.*). The SDK
|
|
537
|
+
// owns every id/descriptor/schema; this only fills the handler slot via
|
|
538
|
+
// catalog.register(descriptor, handler, { replace: true }). Routing returns
|
|
539
|
+
// the resolver the inbox surface consumes; triage decorates channels.inbox.list.
|
|
540
|
+
// The remote surface reuses the SAME DistributedRuntimeManager the SDK facade
|
|
541
|
+
// injects, so its peer/work methods share one persistent store; remote.peers.*
|
|
542
|
+
// stay SDK-published routes (not catalog methods).
|
|
543
|
+
const handlerLogger: HandlerLogger = {
|
|
544
|
+
info: (message, meta) => console.info(message, meta ?? ''),
|
|
545
|
+
warn: (message, meta) => console.warn(message, meta ?? ''),
|
|
546
|
+
error: (message, meta) => console.error(message, meta ?? ''),
|
|
547
|
+
};
|
|
548
|
+
const handlerContext: HandlerContext = {
|
|
549
|
+
catalog: gatewayMethods,
|
|
550
|
+
credentials: createDaemonCredentialStore(secretsManager),
|
|
551
|
+
configManager,
|
|
552
|
+
workingDirectory,
|
|
553
|
+
homeDirectory,
|
|
554
|
+
logger: handlerLogger,
|
|
555
|
+
};
|
|
556
|
+
const daemonHandlers = registerDaemonHandlers(handlerContext, {
|
|
557
|
+
registerRouting,
|
|
558
|
+
registerInbox: (ctx, routing) =>
|
|
559
|
+
registerTriagedInbox(ctx, (inboxCtx) => registerInboxMethods(inboxCtx, routing))
|
|
560
|
+
.unregister,
|
|
561
|
+
registerDrafts: (ctx) => registerDraftMethods(ctx),
|
|
562
|
+
registerCalendar,
|
|
563
|
+
registerEmail: (ctx) => registerEmailMethods(ctx),
|
|
564
|
+
registerRemote: (ctx) => registerRemoteSurface(ctx, { manager: distributedRuntime }),
|
|
565
|
+
});
|
|
566
|
+
|
|
520
567
|
const remoteRunnerRegistry = new RemoteRunnerRegistry(agentManager);
|
|
521
568
|
const remoteSupervisor = new RemoteSupervisor(remoteRunnerRegistry);
|
|
522
569
|
const sandboxSessionRegistry = new SandboxSessionRegistry(workingDirectory);
|
|
@@ -669,6 +716,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
669
716
|
providerRegistry,
|
|
670
717
|
toolLLM,
|
|
671
718
|
distributedRuntime,
|
|
719
|
+
daemonHandlers,
|
|
672
720
|
remoteRunnerRegistry,
|
|
673
721
|
remoteSupervisor,
|
|
674
722
|
sessionMemoryStore,
|
package/src/version.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { join } from 'node:path';
|
|
|
6
6
|
// The prebuild script updates the fallback value before compilation.
|
|
7
7
|
// Uses import.meta.dir (Bun) to locate package.json relative to this file,
|
|
8
8
|
// which is correct regardless of the process working directory.
|
|
9
|
-
let _version = '0.
|
|
9
|
+
let _version = '0.26.0';
|
|
10
10
|
try {
|
|
11
11
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8'));
|
|
12
12
|
_version = pkg.version ?? _version;
|