@pellux/goodvibes-tui 0.25.0 → 0.27.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 +22 -3
- package/README.md +12 -7
- package/docs/foundation-artifacts/operator-contract.json +2422 -1040
- package/package.json +2 -2
- package/src/cli/bundle-command.ts +2 -1
- package/src/cli/service-posture.ts +2 -1
- package/src/core/conversation-rendering.ts +2 -2
- package/src/core/conversation.ts +49 -2
- package/src/core/session-recovery.ts +24 -18
- package/src/core/system-message-router.ts +42 -26
- package/src/core/turn-event-wiring.ts +12 -16
- package/src/daemon/{calendar → handlers/calendar}/caldav-client.ts +29 -24
- 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/{channels → handlers}/drafts/draft-store.ts +114 -50
- 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/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/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/{channels → handlers}/inbox/cursor-store.ts +58 -66
- package/src/daemon/handlers/inbox/index.ts +211 -0
- package/src/daemon/{channels → handlers}/inbox/mapping.ts +8 -6
- package/src/daemon/{channels → handlers}/inbox/poller.ts +6 -5
- package/src/daemon/{channels → handlers}/inbox/provider-adapter.ts +14 -10
- package/src/daemon/{channels → handlers}/inbox/providers/discord.ts +10 -11
- package/src/daemon/{channels → handlers}/inbox/providers/email.ts +2 -1
- package/src/daemon/{channels → handlers}/inbox/providers/imap-client.ts +1 -1
- package/src/daemon/{channels → handlers}/inbox/providers/route-util.ts +4 -3
- package/src/daemon/{channels → handlers}/inbox/providers/slack.ts +11 -12
- package/src/daemon/handlers/index.ts +107 -0
- package/src/daemon/handlers/register.ts +161 -0
- package/src/daemon/{remote → handlers/remote}/backends/cloud-terminal.ts +8 -3
- package/src/daemon/{remote → handlers/remote}/backends/docker.ts +2 -3
- package/src/daemon/handlers/remote/backends/index.ts +40 -0
- package/src/daemon/{remote → handlers/remote}/backends/process-runner.ts +16 -40
- package/src/daemon/{remote → handlers/remote}/backends/ssh.ts +8 -3
- package/src/daemon/{remote → handlers/remote}/backends/types.ts +29 -3
- package/src/daemon/{remote → handlers/remote}/dispatcher.ts +27 -6
- package/src/daemon/handlers/remote/index.ts +119 -0
- package/src/daemon/{remote → handlers/remote}/peer-registry.ts +47 -11
- package/src/daemon/handlers/remote/service.ts +191 -0
- package/src/daemon/{channels → handlers}/routing/inbox-bridge.ts +33 -20
- package/src/daemon/handlers/routing/index.ts +261 -0
- package/src/daemon/{channels → handlers}/routing/route-store.ts +57 -16
- package/src/daemon/{channels → handlers}/routing/routing-resolver.ts +1 -1
- package/src/daemon/{operator → handlers}/sqlite-store.ts +5 -5
- package/src/daemon/handlers/triage/index.ts +57 -0
- package/src/daemon/handlers/triage/integration.ts +213 -0
- package/src/daemon/{triage → handlers/triage}/pipeline.ts +60 -71
- package/src/daemon/{triage → handlers/triage}/scorer.ts +21 -21
- package/src/daemon/handlers/triage/tagger/discord.ts +187 -0
- package/src/daemon/handlers/triage/tagger/imap.ts +384 -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/export/gist-uploader.ts +3 -1
- package/src/input/command-registry.ts +1 -0
- package/src/input/commands/cloudflare-runtime.ts +2 -1
- package/src/input/commands/guidance-runtime.ts +2 -4
- package/src/input/commands/health-runtime.ts +13 -7
- package/src/input/commands/knowledge.ts +2 -1
- package/src/input/commands/runtime-services.ts +40 -10
- package/src/input/handler-command-route.ts +1 -1
- package/src/input/handler-interactions.ts +2 -1
- package/src/input/handler-modal-routes.ts +2 -1
- package/src/input/handler-onboarding-cloudflare.ts +2 -1
- package/src/input/handler-onboarding.ts +8 -8
- package/src/input/handler-ui-state.ts +1 -1
- package/src/input/tts-settings-actions.ts +2 -1
- package/src/main.ts +52 -59
- package/src/panels/agent-inspector-panel.ts +72 -2
- package/src/panels/agent-logs-panel.ts +127 -19
- package/src/panels/base-panel.ts +2 -1
- package/src/panels/builtin/agent.ts +3 -1
- package/src/panels/builtin/development.ts +1 -0
- package/src/panels/builtin/session.ts +1 -1
- package/src/panels/context-visualizer-panel.ts +24 -14
- package/src/panels/cost-tracker-panel.ts +7 -13
- package/src/panels/debug-panel.ts +11 -22
- package/src/panels/docs-panel.ts +14 -24
- package/src/panels/file-explorer-panel.ts +2 -1
- package/src/panels/file-preview-panel.ts +2 -1
- package/src/panels/git-panel.ts +10 -17
- package/src/panels/marketplace-panel.ts +2 -1
- package/src/panels/memory-panel.ts +2 -1
- package/src/panels/project-planning-panel.ts +5 -4
- package/src/panels/provider-health-panel.ts +56 -67
- package/src/panels/schedule-panel.ts +4 -7
- package/src/panels/session-browser-panel.ts +13 -21
- package/src/panels/skills-panel.ts +2 -1
- package/src/panels/tasks-panel.ts +2 -7
- package/src/panels/thinking-panel.ts +6 -11
- package/src/panels/token-budget-panel.ts +31 -15
- package/src/panels/tool-inspector-panel.ts +10 -18
- package/src/panels/work-plan-panel.ts +2 -1
- package/src/panels/wrfc-panel.ts +37 -35
- package/src/renderer/agent-detail-modal.ts +2 -2
- package/src/renderer/modal-utils.ts +0 -10
- package/src/renderer/process-modal.ts +2 -2
- package/src/runtime/bootstrap-command-context.ts +3 -0
- package/src/runtime/bootstrap-command-parts.ts +3 -1
- package/src/runtime/bootstrap-core.ts +31 -31
- package/src/runtime/bootstrap-shell.ts +1 -0
- package/src/runtime/onboarding/apply.ts +4 -3
- package/src/runtime/onboarding/snapshot.ts +4 -3
- package/src/runtime/process-lifecycle.ts +195 -0
- package/src/runtime/services.ts +52 -36
- package/src/runtime/wrfc-persistence.ts +20 -5
- package/src/shell/ui-openers.ts +3 -2
- package/src/verification/live-verifier.ts +4 -3
- package/src/version.ts +1 -1
- package/src/core/context-auto-compact.ts +0 -110
- package/src/daemon/calendar/index.ts +0 -52
- package/src/daemon/calendar/register.ts +0 -527
- package/src/daemon/channels/drafts/index.ts +0 -22
- package/src/daemon/channels/drafts/register.ts +0 -449
- package/src/daemon/channels/inbox/index.ts +0 -58
- package/src/daemon/channels/inbox/register.ts +0 -247
- package/src/daemon/channels/routing/index.ts +0 -39
- package/src/daemon/channels/routing/register.ts +0 -296
- package/src/daemon/email/index.ts +0 -68
- package/src/daemon/email/register.ts +0 -715
- package/src/daemon/operator/index.ts +0 -43
- package/src/daemon/operator/register-helper.ts +0 -150
- package/src/daemon/operator/surfaces.ts +0 -137
- package/src/daemon/operator/types.ts +0 -207
- package/src/daemon/remote/backends/index.ts +0 -34
- package/src/daemon/remote/index.ts +0 -74
- package/src/daemon/remote/register.ts +0 -411
- package/src/daemon/triage/index.ts +0 -59
- package/src/daemon/triage/integration.ts +0 -179
- package/src/daemon/triage/register.ts +0 -231
- package/src/daemon/triage/tagger.ts +0 -777
- /package/src/daemon/{calendar → handlers/calendar}/ics.ts +0 -0
- /package/src/daemon/{operator/credential-store.ts → handlers/credentials.ts} +0 -0
- /package/src/daemon/{email → handlers/email}/imap-connector.ts +0 -0
- /package/src/daemon/{email → handlers/email}/imap-parsing.ts +0 -0
- /package/src/daemon/{email → handlers/email}/smtp-connector.ts +0 -0
- /package/src/daemon/{remote → handlers/remote}/backends/local-process.ts +0 -0
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
// Foundation barrel for the daemon operator-method scaffolding.
|
|
2
|
-
// Surfaces import only from here, from src/config/*, and from the SDK.
|
|
3
|
-
|
|
4
|
-
export type {
|
|
5
|
-
OperatorAccess,
|
|
6
|
-
OperatorTransport,
|
|
7
|
-
OperatorEffect,
|
|
8
|
-
OperatorMethodDescriptor,
|
|
9
|
-
CatalogMethodDescriptor,
|
|
10
|
-
OperatorInvocation,
|
|
11
|
-
OperatorHandler,
|
|
12
|
-
OperatorLogger,
|
|
13
|
-
OperatorContext,
|
|
14
|
-
Unregister,
|
|
15
|
-
SurfaceRegister,
|
|
16
|
-
InboundChannelItem,
|
|
17
|
-
ChannelRoute,
|
|
18
|
-
DraftRecord,
|
|
19
|
-
CalendarEventSummary,
|
|
20
|
-
} from './types.ts';
|
|
21
|
-
export { OperatorError, REQUIRE_CONFIRM, sha256First, redactWebhook } from './types.ts';
|
|
22
|
-
|
|
23
|
-
export {
|
|
24
|
-
declareOperatorMethod,
|
|
25
|
-
declareOperatorMethods,
|
|
26
|
-
assertConfirmed,
|
|
27
|
-
} from './register-helper.ts';
|
|
28
|
-
|
|
29
|
-
export { OperatorSqliteStore } from './sqlite-store.ts';
|
|
30
|
-
export type { OperatorSqliteOptions } from './sqlite-store.ts';
|
|
31
|
-
|
|
32
|
-
export {
|
|
33
|
-
createDaemonCredentialStore,
|
|
34
|
-
createAtRestCipher,
|
|
35
|
-
} from './credential-store.ts';
|
|
36
|
-
export type { DaemonCredentialStore, AtRestCipher } from './credential-store.ts';
|
|
37
|
-
|
|
38
|
-
// NOTE: `registerDaemonOperatorSurfaces` / `DaemonOperatorSurfaces` are NOT
|
|
39
|
-
// re-exported here. `surfaces.ts` is the composition root that imports every
|
|
40
|
-
// surface register module; re-exporting it from this foundation barrel would
|
|
41
|
-
// make any leaf module that imports the barrel transitively pull in the whole
|
|
42
|
-
// surface graph, forming an import cycle. The composition root (services.ts)
|
|
43
|
-
// imports them directly from './surfaces.ts'.
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
GatewayMethodAccess,
|
|
3
|
-
GatewayMethodDescriptor,
|
|
4
|
-
GatewayMethodInvocation,
|
|
5
|
-
GatewayMethodSource,
|
|
6
|
-
GatewayMethodTransport,
|
|
7
|
-
} from '@pellux/goodvibes-sdk/platform/control-plane';
|
|
8
|
-
import type {
|
|
9
|
-
CatalogMethodDescriptor,
|
|
10
|
-
OperatorAccess,
|
|
11
|
-
OperatorContext,
|
|
12
|
-
OperatorHandler,
|
|
13
|
-
OperatorInvocation,
|
|
14
|
-
OperatorMethodDescriptor,
|
|
15
|
-
OperatorTransport,
|
|
16
|
-
Unregister,
|
|
17
|
-
} from './types.ts';
|
|
18
|
-
import { OperatorError, REQUIRE_CONFIRM } from './types.ts';
|
|
19
|
-
|
|
20
|
-
const CATALOG_TRANSPORTS = new Set<GatewayMethodTransport>(['http', 'ws', 'internal']);
|
|
21
|
-
|
|
22
|
-
function mapAccess(access: OperatorAccess): GatewayMethodAccess {
|
|
23
|
-
// The SDK has no 'operator' access tier; map it to 'admin'.
|
|
24
|
-
return access === 'operator' ? 'admin' : access;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function mapSource(source: string | undefined, pluginId: string | undefined): GatewayMethodSource {
|
|
28
|
-
// The SDK accepts only 'builtin' | 'plugin'. Daemon-owned methods register as
|
|
29
|
-
// 'builtin' unless they carry a pluginId.
|
|
30
|
-
if (source === 'plugin' || pluginId !== undefined) return 'plugin';
|
|
31
|
-
return 'builtin';
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function mapTransport(transport: OperatorTransport[] | undefined): GatewayMethodTransport[] {
|
|
35
|
-
const candidates = transport ?? ['ws', 'internal'];
|
|
36
|
-
return candidates.filter((t): t is GatewayMethodTransport => CATALOG_TRANSPORTS.has(t as GatewayMethodTransport));
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function toCatalogDescriptor(descriptor: OperatorMethodDescriptor): CatalogMethodDescriptor {
|
|
40
|
-
// Strip non-catalog fields (effect, confirm). Only the SDK-recognized fields
|
|
41
|
-
// are forwarded to catalog.register().
|
|
42
|
-
return {
|
|
43
|
-
id: descriptor.id,
|
|
44
|
-
title: descriptor.title,
|
|
45
|
-
description: descriptor.description,
|
|
46
|
-
category: descriptor.category,
|
|
47
|
-
source: mapSource(descriptor.source, descriptor.pluginId),
|
|
48
|
-
access: mapAccess(descriptor.access),
|
|
49
|
-
transport: mapTransport(descriptor.transport),
|
|
50
|
-
scopes: descriptor.scopes,
|
|
51
|
-
...(descriptor.pluginId !== undefined ? { pluginId: descriptor.pluginId } : {}),
|
|
52
|
-
...(descriptor.inputSchema !== undefined ? { inputSchema: descriptor.inputSchema } : {}),
|
|
53
|
-
...(descriptor.outputSchema !== undefined ? { outputSchema: descriptor.outputSchema } : {}),
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function hasConfirmFlag(body: unknown): boolean {
|
|
58
|
-
return (
|
|
59
|
-
typeof body === 'object'
|
|
60
|
-
&& body !== null
|
|
61
|
-
&& (body as { confirm?: unknown }).confirm === true
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function explicitUserRequestFlag(metadata: Record<string, unknown> | undefined): boolean {
|
|
66
|
-
return metadata?.explicitUserRequest === true;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Assert that an invocation carries an explicit, confirmed user request.
|
|
71
|
-
* Throws OperatorError(REQUIRE_CONFIRM, 403) when not confirmed.
|
|
72
|
-
*/
|
|
73
|
-
export function assertConfirmed(input: {
|
|
74
|
-
body: unknown;
|
|
75
|
-
context: { explicitUserRequest?: boolean };
|
|
76
|
-
}): void {
|
|
77
|
-
if (!hasConfirmFlag(input.body) || input.context.explicitUserRequest !== true) {
|
|
78
|
-
throw new OperatorError(
|
|
79
|
-
'This operation requires explicit user confirmation.',
|
|
80
|
-
REQUIRE_CONFIRM,
|
|
81
|
-
403,
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Declare one operator method: applies defaults, wraps the handler with a
|
|
88
|
-
* confirm-guard + error mapping, and registers it against the real catalog.
|
|
89
|
-
* Returns the catalog's unregister function.
|
|
90
|
-
*/
|
|
91
|
-
export function declareOperatorMethod<TBody, TResult>(
|
|
92
|
-
ctx: OperatorContext,
|
|
93
|
-
descriptor: OperatorMethodDescriptor,
|
|
94
|
-
handler: OperatorHandler<TBody, TResult>,
|
|
95
|
-
): Unregister {
|
|
96
|
-
const catalogDescriptor = toCatalogDescriptor(descriptor);
|
|
97
|
-
const requiresConfirm = descriptor.confirm === true;
|
|
98
|
-
|
|
99
|
-
const wrappedHandler = async (input: GatewayMethodInvocation): Promise<unknown> => {
|
|
100
|
-
// Normalize the SDK invocation context into the operator-facing shape.
|
|
101
|
-
const explicitUserRequest = explicitUserRequestFlag(input.context.metadata);
|
|
102
|
-
const operatorContext = {
|
|
103
|
-
principalId: input.context.principalId ?? '',
|
|
104
|
-
explicitUserRequest,
|
|
105
|
-
};
|
|
106
|
-
try {
|
|
107
|
-
if (requiresConfirm) {
|
|
108
|
-
assertConfirmed({ body: input.body, context: operatorContext });
|
|
109
|
-
}
|
|
110
|
-
const invocation: OperatorInvocation<TBody> = {
|
|
111
|
-
body: input.body as TBody,
|
|
112
|
-
context: operatorContext,
|
|
113
|
-
};
|
|
114
|
-
return await handler(invocation);
|
|
115
|
-
} catch (error) {
|
|
116
|
-
if (error instanceof OperatorError) throw error;
|
|
117
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
118
|
-
throw new OperatorError(message, 'OPERATOR_HANDLER_FAILED', 500);
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
// CatalogMethodDescriptor is structurally a GatewayMethodDescriptor.
|
|
123
|
-
return ctx.catalog.register(catalogDescriptor as GatewayMethodDescriptor, wrappedHandler);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Register many methods at once. Returns a single Unregister that tears them all
|
|
128
|
-
* down (invoking each individual unregister fn in reverse registration order).
|
|
129
|
-
*/
|
|
130
|
-
export function declareOperatorMethods(
|
|
131
|
-
ctx: OperatorContext,
|
|
132
|
-
entries: Array<{
|
|
133
|
-
descriptor: OperatorMethodDescriptor;
|
|
134
|
-
handler: OperatorHandler<unknown, unknown>;
|
|
135
|
-
}>,
|
|
136
|
-
): Unregister {
|
|
137
|
-
const unregisters: Unregister[] = [];
|
|
138
|
-
for (const entry of entries) {
|
|
139
|
-
unregisters.push(declareOperatorMethod(ctx, entry.descriptor, entry.handler));
|
|
140
|
-
}
|
|
141
|
-
return () => {
|
|
142
|
-
for (let i = unregisters.length - 1; i >= 0; i -= 1) {
|
|
143
|
-
try {
|
|
144
|
-
unregisters[i]?.();
|
|
145
|
-
} catch {
|
|
146
|
-
// Best-effort teardown: continue unregistering the rest.
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
}
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// Daemon operator-surface integration root.
|
|
3
|
-
//
|
|
4
|
-
// `registerDaemonOperatorSurfaces(ctx)` is the single call the runtime services
|
|
5
|
-
// layer (src/runtime/services.ts) makes to publish every daemon operator
|
|
6
|
-
// surface against the shared GatewayMethodCatalog. Each surface module owns its
|
|
7
|
-
// own method declarations; this module only composes their register entry
|
|
8
|
-
// points and aggregates teardown.
|
|
9
|
-
//
|
|
10
|
-
// Surfaces wired here:
|
|
11
|
-
// - channels.routing.* (routing/register.ts)
|
|
12
|
-
// - channels.inbox.list + (triage/integration.ts -> registerTriagedInbox,
|
|
13
|
-
// inbox.triage.* which registers the inbox surface through a
|
|
14
|
-
// catalog proxy that overlays triage scores, plus
|
|
15
|
-
// the inbox.triage.list / .tag methods)
|
|
16
|
-
// - channels.drafts.* (channels/drafts/register.ts)
|
|
17
|
-
// - calendar.* (CalDAV) (calendar/register.ts)
|
|
18
|
-
// - email.* (email/register.ts)
|
|
19
|
-
// - remote.peers.register + (remote/register.ts) — the register method is
|
|
20
|
-
// remote dispatch adapter published on the catalog and the dispatch
|
|
21
|
-
// adapter for the existing remote.peers.invoke
|
|
22
|
-
// route is exposed on the returned handle.
|
|
23
|
-
//
|
|
24
|
-
// Every surface initializes its stores lazily (on first method invocation), so
|
|
25
|
-
// this composition is synchronous and never blocks daemon bootstrap on disk I/O.
|
|
26
|
-
// The remote peer-registry store is the one async initializer; it is kicked off
|
|
27
|
-
// in the background and the dispatch adapter awaits it implicitly on first use.
|
|
28
|
-
// ---------------------------------------------------------------------------
|
|
29
|
-
|
|
30
|
-
import type { OperatorContext, Unregister } from './types.ts';
|
|
31
|
-
import { registerRoutingMethods, type RoutingRegistration } from '../channels/routing/register.ts';
|
|
32
|
-
import { createInboxRouteResolver } from '../channels/routing/inbox-bridge.ts';
|
|
33
|
-
import { registerTriagedInbox } from '../triage/integration.ts';
|
|
34
|
-
import { registerDraftsMethods } from '../channels/drafts/register.ts';
|
|
35
|
-
import { registerCalendarMethods } from '../calendar/register.ts';
|
|
36
|
-
import { registerEmailMethods } from '../email/register.ts';
|
|
37
|
-
import {
|
|
38
|
-
createRemoteSurface,
|
|
39
|
-
type RemoteSurface,
|
|
40
|
-
type RemoteInvokeAdapter,
|
|
41
|
-
} from '../remote/register.ts';
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Handles returned to the integrator. `unregister()` tears every surface down in
|
|
45
|
-
* reverse registration order. `remoteDispatch` is the invoke adapter the daemon
|
|
46
|
-
* server attaches to the existing `remote.peers.invoke` route; `remoteSurface`
|
|
47
|
-
* exposes the underlying peer registry / dispatcher for advanced wiring.
|
|
48
|
-
*/
|
|
49
|
-
export interface DaemonOperatorSurfaces {
|
|
50
|
-
/** Tear down every registered operator surface (reverse order). */
|
|
51
|
-
readonly unregister: Unregister;
|
|
52
|
-
/** Routing registration handle (store + resolver reuse). */
|
|
53
|
-
readonly routing: RoutingRegistration;
|
|
54
|
-
/** Remote execution surface (peer registry + dispatcher). */
|
|
55
|
-
readonly remoteSurface: RemoteSurface;
|
|
56
|
-
/** Dispatch adapter for the existing remote.peers.invoke route. */
|
|
57
|
-
readonly remoteDispatch: RemoteInvokeAdapter;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Register every daemon operator surface against the catalog in `ctx`.
|
|
62
|
-
*
|
|
63
|
-
* Synchronous: surfaces defer their disk I/O until first invocation. The only
|
|
64
|
-
* async initializer (the remote peer registry) is started in the background and
|
|
65
|
-
* its failure is logged rather than thrown so daemon bootstrap is never blocked.
|
|
66
|
-
*/
|
|
67
|
-
export function registerDaemonOperatorSurfaces(ctx: OperatorContext): DaemonOperatorSurfaces {
|
|
68
|
-
const teardowns: Unregister[] = [];
|
|
69
|
-
const pushTeardown = (fn: Unregister): void => {
|
|
70
|
-
teardowns.push(fn);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
// Aggregate teardown invoked in reverse registration order; best-effort so one
|
|
74
|
-
// failing teardown never strands the rest.
|
|
75
|
-
const unregister: Unregister = () => {
|
|
76
|
-
for (let i = teardowns.length - 1; i >= 0; i -= 1) {
|
|
77
|
-
try {
|
|
78
|
-
teardowns[i]?.();
|
|
79
|
-
} catch (error) {
|
|
80
|
-
ctx.logger.warn('operator surface teardown failed', {
|
|
81
|
-
message: error instanceof Error ? error.message : String(error),
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
// 1. Routing control plane (channels.routing.list/assign/delete).
|
|
89
|
-
const routing = registerRoutingMethods(ctx);
|
|
90
|
-
pushTeardown(routing);
|
|
91
|
-
|
|
92
|
-
// 2. Triaged inbox: channels.inbox.list (triage-enriched) + inbox.triage.*.
|
|
93
|
-
// Bridge routing's resolver into the inbox so inbound items resolve their
|
|
94
|
-
// routeId via the channel<->profile bindings (exact > surface-only >
|
|
95
|
-
// wildcard). The resolver is best-effort: a null lookup leaves the item
|
|
96
|
-
// unrouted (offline/default fallback) and never throws.
|
|
97
|
-
pushTeardown(
|
|
98
|
-
registerTriagedInbox(ctx, {
|
|
99
|
-
inbox: { resolveRouteId: createInboxRouteResolver(routing.resolver) },
|
|
100
|
-
}),
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
// 3. Channel drafts mirror (channels.drafts.list/get/save/delete).
|
|
104
|
-
pushTeardown(registerDraftsMethods(ctx));
|
|
105
|
-
|
|
106
|
-
// 4. Calendar (CalDAV) operator methods.
|
|
107
|
-
pushTeardown(registerCalendarMethods(ctx));
|
|
108
|
-
|
|
109
|
-
// 5. Email operator surface (read/list/draft/send).
|
|
110
|
-
pushTeardown(registerEmailMethods(ctx));
|
|
111
|
-
|
|
112
|
-
// 6. Remote execution surface: publish remote.peers.register and build the
|
|
113
|
-
// dispatch adapter for the existing remote.peers.invoke route.
|
|
114
|
-
const remoteSurface = createRemoteSurface(ctx);
|
|
115
|
-
const unregisterRemoteMethod = remoteSurface.register();
|
|
116
|
-
const remoteDispatch = remoteSurface.registerDispatch();
|
|
117
|
-
pushTeardown(() => {
|
|
118
|
-
try {
|
|
119
|
-
unregisterRemoteMethod();
|
|
120
|
-
} finally {
|
|
121
|
-
remoteSurface.close();
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
// Background-init the peer registry store; never block bootstrap on it.
|
|
125
|
-
void remoteSurface.init().catch((error: unknown) => {
|
|
126
|
-
ctx.logger.error('remote surface peer-registry init failed', {
|
|
127
|
-
message: error instanceof Error ? error.message : String(error),
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
return { unregister, routing, remoteSurface, remoteDispatch };
|
|
132
|
-
} catch (error) {
|
|
133
|
-
// Roll back any surfaces registered before the failure.
|
|
134
|
-
unregister();
|
|
135
|
-
throw error;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
|
-
import type {
|
|
3
|
-
GatewayMethodCatalog,
|
|
4
|
-
GatewayMethodAccess,
|
|
5
|
-
GatewayMethodSource,
|
|
6
|
-
GatewayMethodTransport,
|
|
7
|
-
} from '@pellux/goodvibes-sdk/platform/control-plane';
|
|
8
|
-
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
9
|
-
import type { SecretsManager } from '../../config/secrets.ts';
|
|
10
|
-
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
|
-
// Access / transport / effect vocabularies
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
|
|
15
|
-
export type OperatorAccess = 'public' | 'authenticated' | 'operator';
|
|
16
|
-
export type OperatorTransport = 'ws' | 'internal' | 'http';
|
|
17
|
-
export type OperatorEffect =
|
|
18
|
-
| 'read-only'
|
|
19
|
-
| 'read-only-network'
|
|
20
|
-
| 'confirmed-effect'
|
|
21
|
-
| 'confirmed-connected-host-state'
|
|
22
|
-
| 'local-state-mutation';
|
|
23
|
-
|
|
24
|
-
// ---------------------------------------------------------------------------
|
|
25
|
-
// Method descriptor
|
|
26
|
-
//
|
|
27
|
-
// Matches catalog.register() descriptor (services.ts survey). The SDK catalog
|
|
28
|
-
// has NO confirmationRequired / effect fields — confirmation is application-level
|
|
29
|
-
// via request body `confirm:true`. The `effect` and `confirm` fields below are
|
|
30
|
-
// metadata-only here; enforcement happens in the handler against body.confirm.
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
|
|
33
|
-
export interface OperatorMethodDescriptor {
|
|
34
|
-
id: string;
|
|
35
|
-
title: string;
|
|
36
|
-
description: string;
|
|
37
|
-
category: string;
|
|
38
|
-
source?: string; // default 'daemon'
|
|
39
|
-
access: OperatorAccess;
|
|
40
|
-
transport?: OperatorTransport[]; // default ['ws','internal']
|
|
41
|
-
scopes: string[];
|
|
42
|
-
pluginId?: string;
|
|
43
|
-
inputSchema?: Record<string, unknown>; // JSON Schema
|
|
44
|
-
outputSchema?: Record<string, unknown>; // JSON Schema
|
|
45
|
-
effect?: OperatorEffect; // app-level metadata, not sent to catalog
|
|
46
|
-
confirm?: boolean; // when true, handler MUST require body.confirm === true
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// The exact descriptor shape the SDK catalog.register() accepts
|
|
50
|
-
// (GatewayMethodDescriptor). `source`/`access`/`transport` use the SDK's narrow
|
|
51
|
-
// unions, so the app-level OperatorAccess 'operator' is mapped to 'admin' and the
|
|
52
|
-
// app-level source 'daemon' is mapped to 'builtin' before registration.
|
|
53
|
-
export interface CatalogMethodDescriptor {
|
|
54
|
-
readonly id: string;
|
|
55
|
-
readonly title: string;
|
|
56
|
-
readonly description: string;
|
|
57
|
-
readonly category: string;
|
|
58
|
-
readonly source: GatewayMethodSource;
|
|
59
|
-
readonly access: GatewayMethodAccess;
|
|
60
|
-
readonly transport: readonly GatewayMethodTransport[];
|
|
61
|
-
readonly scopes: readonly string[];
|
|
62
|
-
readonly pluginId?: string;
|
|
63
|
-
readonly inputSchema?: Record<string, unknown>;
|
|
64
|
-
readonly outputSchema?: Record<string, unknown>;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// ---------------------------------------------------------------------------
|
|
68
|
-
// Handler / invocation
|
|
69
|
-
//
|
|
70
|
-
// Matches catalog handler input: async ({ body, context }) => unknown
|
|
71
|
-
// ---------------------------------------------------------------------------
|
|
72
|
-
|
|
73
|
-
export interface OperatorInvocation<TBody = unknown> {
|
|
74
|
-
body: TBody;
|
|
75
|
-
context: { principalId: string; explicitUserRequest?: boolean };
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export type OperatorHandler<TBody = unknown, TResult = unknown> = (
|
|
79
|
-
input: OperatorInvocation<TBody>,
|
|
80
|
-
) => Promise<TResult>;
|
|
81
|
-
|
|
82
|
-
// ---------------------------------------------------------------------------
|
|
83
|
-
// Logger
|
|
84
|
-
// ---------------------------------------------------------------------------
|
|
85
|
-
|
|
86
|
-
export interface OperatorLogger {
|
|
87
|
-
info(msg: string, meta?: unknown): void;
|
|
88
|
-
warn(msg: string, meta?: unknown): void;
|
|
89
|
-
error(msg: string, meta?: unknown): void;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// ---------------------------------------------------------------------------
|
|
93
|
-
// OperatorContext
|
|
94
|
-
//
|
|
95
|
-
// Context injected into every surface register() by services.ts (the ONE
|
|
96
|
-
// allowed edit there).
|
|
97
|
-
// ---------------------------------------------------------------------------
|
|
98
|
-
|
|
99
|
-
export interface OperatorContext {
|
|
100
|
-
readonly catalog: GatewayMethodCatalog;
|
|
101
|
-
readonly secrets: SecretsManager;
|
|
102
|
-
// Narrow to the read surface actually used by surfaces (get / getCategory).
|
|
103
|
-
readonly configManager: Pick<ConfigManager, 'get' | 'getCategory'>;
|
|
104
|
-
readonly workingDirectory: string;
|
|
105
|
-
readonly homeDirectory: string;
|
|
106
|
-
readonly logger: OperatorLogger;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export type Unregister = () => void;
|
|
110
|
-
|
|
111
|
-
// Every surface module's default/contract: register(ctx) => Unregister
|
|
112
|
-
// (call to remove all its methods).
|
|
113
|
-
export type SurfaceRegister = (ctx: OperatorContext) => Unregister;
|
|
114
|
-
|
|
115
|
-
// ---------------------------------------------------------------------------
|
|
116
|
-
// Errors
|
|
117
|
-
// ---------------------------------------------------------------------------
|
|
118
|
-
|
|
119
|
-
export class OperatorError extends Error {
|
|
120
|
-
readonly code: string;
|
|
121
|
-
readonly status: number;
|
|
122
|
-
|
|
123
|
-
constructor(message: string, code: string, status = 400) {
|
|
124
|
-
super(message);
|
|
125
|
-
this.name = 'OperatorError';
|
|
126
|
-
this.code = code;
|
|
127
|
-
this.status = status;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export const REQUIRE_CONFIRM = 'OPERATOR_CONFIRMATION_REQUIRED';
|
|
132
|
-
|
|
133
|
-
// ---------------------------------------------------------------------------
|
|
134
|
-
// Handoff domain types (shared across surfaces)
|
|
135
|
-
// ---------------------------------------------------------------------------
|
|
136
|
-
|
|
137
|
-
export interface InboundChannelItem {
|
|
138
|
-
id: string;
|
|
139
|
-
surface: string;
|
|
140
|
-
accountId?: string;
|
|
141
|
-
conversationId?: string;
|
|
142
|
-
conversationKind?: 'direct' | 'group' | 'channel' | 'thread' | string;
|
|
143
|
-
fromDigest: string; // sha256First(fromAddress, 16)
|
|
144
|
-
messageDigest: string; // sha256First(messageBody, 12)
|
|
145
|
-
subject?: string;
|
|
146
|
-
snippet?: string;
|
|
147
|
-
receivedAt: string; // ISO-8601
|
|
148
|
-
unread: boolean;
|
|
149
|
-
metadata?: Record<string, unknown>;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export interface ChannelRoute {
|
|
153
|
-
id: string;
|
|
154
|
-
surface: string;
|
|
155
|
-
accountId?: string;
|
|
156
|
-
matchKind: 'sender' | 'conversation' | 'keyword' | 'default' | string;
|
|
157
|
-
matchValue: string;
|
|
158
|
-
targetSurface: string;
|
|
159
|
-
targetConversationId?: string;
|
|
160
|
-
priority: number;
|
|
161
|
-
enabled: boolean;
|
|
162
|
-
webhook?: string; // redacted on read via redactWebhook()
|
|
163
|
-
createdAt: string; // ISO-8601
|
|
164
|
-
updatedAt: string; // ISO-8601
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
export interface DraftRecord {
|
|
168
|
-
id: string;
|
|
169
|
-
surface: string;
|
|
170
|
-
accountId?: string;
|
|
171
|
-
conversationId?: string;
|
|
172
|
-
to?: string;
|
|
173
|
-
subject?: string;
|
|
174
|
-
bodyCiphertext: string; // AES-256-GCM, base64(iv|tag|ct) — never plaintext at rest
|
|
175
|
-
status: 'draft' | 'queued' | 'sent' | 'failed' | string;
|
|
176
|
-
createdAt: string; // ISO-8601
|
|
177
|
-
updatedAt: string; // ISO-8601
|
|
178
|
-
metadata?: Record<string, unknown>;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export interface CalendarEventSummary {
|
|
182
|
-
id: string;
|
|
183
|
-
calendarId?: string;
|
|
184
|
-
title: string;
|
|
185
|
-
start: string; // ISO-8601
|
|
186
|
-
end: string; // ISO-8601
|
|
187
|
-
allDay?: boolean;
|
|
188
|
-
location?: string;
|
|
189
|
-
organizerDigest?: string; // sha256First(organizer, 16)
|
|
190
|
-
status?: 'confirmed' | 'tentative' | 'cancelled' | string;
|
|
191
|
-
metadata?: Record<string, unknown>;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// ---------------------------------------------------------------------------
|
|
195
|
-
// Digest / redaction conventions (shared pure helpers)
|
|
196
|
-
// ---------------------------------------------------------------------------
|
|
197
|
-
|
|
198
|
-
/** SHA-256 of input, truncated to the first `hexChars` hex characters. */
|
|
199
|
-
export function sha256First(input: string, hexChars: number): string {
|
|
200
|
-
const digest = createHash('sha256').update(input, 'utf-8').digest('hex');
|
|
201
|
-
return digest.slice(0, Math.max(0, hexChars));
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/** Returns '[redacted]' when a value is present, otherwise undefined. */
|
|
205
|
-
export function redactWebhook(value?: string): string | undefined {
|
|
206
|
-
return value === undefined || value === null || value === '' ? undefined : '[redacted]';
|
|
207
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { BackendKind } from '../peer-registry.ts';
|
|
2
|
-
import { type Backend, type BackendContext } from './types.ts';
|
|
3
|
-
import { createLocalProcessBackend } from './local-process.ts';
|
|
4
|
-
import { createDockerBackend } from './docker.ts';
|
|
5
|
-
import { createSshBackend } from './ssh.ts';
|
|
6
|
-
import { createCloudTerminalBackend } from './cloud-terminal.ts';
|
|
7
|
-
|
|
8
|
-
export type { Backend, BackendContext, BackendDispatchResult, DispatchPayload } from './types.ts';
|
|
9
|
-
export { BackendDispatchError, DEFAULT_SYNC_TIMEOUT_MS, MAX_SYNC_TIMEOUT_MS, resolveTimeout } from './types.ts';
|
|
10
|
-
export { createLocalProcessBackend } from './local-process.ts';
|
|
11
|
-
export { createDockerBackend } from './docker.ts';
|
|
12
|
-
export { createSshBackend } from './ssh.ts';
|
|
13
|
-
export { createCloudTerminalBackend } from './cloud-terminal.ts';
|
|
14
|
-
export { tokenizeCommand } from './local-process.ts';
|
|
15
|
-
export { runProcess } from './process-runner.ts';
|
|
16
|
-
export type { RunOptions, RunResult } from './process-runner.ts';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Build the full backend registry keyed by backendKind. The dispatcher selects
|
|
20
|
-
* a backend by the peer's backendKind.
|
|
21
|
-
*/
|
|
22
|
-
export function createBackends(ctx: BackendContext): Map<BackendKind, Backend> {
|
|
23
|
-
const backends: Backend[] = [
|
|
24
|
-
createLocalProcessBackend(ctx),
|
|
25
|
-
createDockerBackend(ctx),
|
|
26
|
-
createSshBackend(ctx),
|
|
27
|
-
createCloudTerminalBackend(ctx),
|
|
28
|
-
];
|
|
29
|
-
const registry = new Map<BackendKind, Backend>();
|
|
30
|
-
for (const backend of backends) {
|
|
31
|
-
registry.set(backend.kind, backend);
|
|
32
|
-
}
|
|
33
|
-
return registry;
|
|
34
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
// Remote Execution Backends surface (Docker / SSH / Cloud Terminal / local).
|
|
2
|
-
//
|
|
3
|
-
// Publishes the daemon-internal `remote.peers.register` operator method and a
|
|
4
|
-
// dispatch adapter for the already-published `remote.peers.invoke` route. The
|
|
5
|
-
// integrator attaches the dispatch adapter to the existing invoke router and
|
|
6
|
-
// (optionally) wires the work enqueuer to the distributed runtime work queue.
|
|
7
|
-
|
|
8
|
-
export {
|
|
9
|
-
PeerRegistry,
|
|
10
|
-
PeerRegistryValidationError,
|
|
11
|
-
normalizeBackendConfig,
|
|
12
|
-
} from './peer-registry.ts';
|
|
13
|
-
export type {
|
|
14
|
-
BackendKind,
|
|
15
|
-
CloudProvider,
|
|
16
|
-
BackendConfig,
|
|
17
|
-
DockerBackendConfig,
|
|
18
|
-
SshBackendConfig,
|
|
19
|
-
CloudTerminalBackendConfig,
|
|
20
|
-
LocalProcessBackendConfig,
|
|
21
|
-
PeerRecord,
|
|
22
|
-
PeerRegistrationInput,
|
|
23
|
-
} from './peer-registry.ts';
|
|
24
|
-
|
|
25
|
-
export {
|
|
26
|
-
createBackends,
|
|
27
|
-
createLocalProcessBackend,
|
|
28
|
-
createDockerBackend,
|
|
29
|
-
createSshBackend,
|
|
30
|
-
createCloudTerminalBackend,
|
|
31
|
-
tokenizeCommand,
|
|
32
|
-
runProcess,
|
|
33
|
-
BackendDispatchError,
|
|
34
|
-
resolveTimeout,
|
|
35
|
-
DEFAULT_SYNC_TIMEOUT_MS,
|
|
36
|
-
MAX_SYNC_TIMEOUT_MS,
|
|
37
|
-
} from './backends/index.ts';
|
|
38
|
-
export type {
|
|
39
|
-
Backend,
|
|
40
|
-
BackendContext,
|
|
41
|
-
BackendDispatchResult,
|
|
42
|
-
DispatchPayload,
|
|
43
|
-
RunOptions,
|
|
44
|
-
RunResult,
|
|
45
|
-
} from './backends/index.ts';
|
|
46
|
-
|
|
47
|
-
export {
|
|
48
|
-
RemoteDispatcher,
|
|
49
|
-
STDOUT_PREVIEW_LIMIT,
|
|
50
|
-
} from './dispatcher.ts';
|
|
51
|
-
export type {
|
|
52
|
-
RemoteDispatcherOptions,
|
|
53
|
-
RemoteInvokeResult,
|
|
54
|
-
RemoteWorkEnqueuer,
|
|
55
|
-
RemoteWorkItemInput,
|
|
56
|
-
DispatchRequest,
|
|
57
|
-
} from './dispatcher.ts';
|
|
58
|
-
|
|
59
|
-
export {
|
|
60
|
-
createRemoteSurface,
|
|
61
|
-
registerRemoteMethods,
|
|
62
|
-
registerRemoteDispatch,
|
|
63
|
-
attachRemoteInvokeRoute,
|
|
64
|
-
REMOTE_PEERS_REGISTER,
|
|
65
|
-
REMOTE_PEERS_INVOKE,
|
|
66
|
-
REMOTE_PEERS_INVOKE_DESCRIPTOR,
|
|
67
|
-
} from './register.ts';
|
|
68
|
-
export type {
|
|
69
|
-
RemoteSurface,
|
|
70
|
-
RemoteSurfaceOptions,
|
|
71
|
-
RegisteredRemoteMethods,
|
|
72
|
-
RemoteInvokeAdapter,
|
|
73
|
-
RegisterPeerResult,
|
|
74
|
-
} from './register.ts';
|