@murphai/murph 0.1.1
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 +2009 -0
- package/LICENSE +674 -0
- package/README.md +97 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/assistant/automation/run-loop.d.ts +21 -0
- package/dist/assistant/automation/run-loop.d.ts.map +1 -0
- package/dist/assistant/automation/run-loop.js +31 -0
- package/dist/assistant/automation/run-loop.js.map +1 -0
- package/dist/assistant/automation.d.ts +10 -0
- package/dist/assistant/automation.d.ts.map +1 -0
- package/dist/assistant/automation.js +5 -0
- package/dist/assistant/automation.js.map +1 -0
- package/dist/assistant/cron.d.ts +19 -0
- package/dist/assistant/cron.d.ts.map +1 -0
- package/dist/assistant/cron.js +59 -0
- package/dist/assistant/cron.js.map +1 -0
- package/dist/assistant/doctor-security.d.ts +15 -0
- package/dist/assistant/doctor-security.d.ts.map +1 -0
- package/dist/assistant/doctor-security.js +172 -0
- package/dist/assistant/doctor-security.js.map +1 -0
- package/dist/assistant/doctor.d.ts +5 -0
- package/dist/assistant/doctor.d.ts.map +1 -0
- package/dist/assistant/doctor.js +527 -0
- package/dist/assistant/doctor.js.map +1 -0
- package/dist/assistant/outbox.d.ts +19 -0
- package/dist/assistant/outbox.d.ts.map +1 -0
- package/dist/assistant/outbox.js +28 -0
- package/dist/assistant/outbox.js.map +1 -0
- package/dist/assistant/provider-catalog.d.ts +61 -0
- package/dist/assistant/provider-catalog.d.ts.map +1 -0
- package/dist/assistant/provider-catalog.js +205 -0
- package/dist/assistant/provider-catalog.js.map +1 -0
- package/dist/assistant/service.d.ts +85 -0
- package/dist/assistant/service.d.ts.map +1 -0
- package/dist/assistant/service.js +26 -0
- package/dist/assistant/service.js.map +1 -0
- package/dist/assistant/status.d.ts +9 -0
- package/dist/assistant/status.d.ts.map +1 -0
- package/dist/assistant/status.js +16 -0
- package/dist/assistant/status.js.map +1 -0
- package/dist/assistant/stop.d.ts +20 -0
- package/dist/assistant/stop.d.ts.map +1 -0
- package/dist/assistant/stop.js +142 -0
- package/dist/assistant/stop.js.map +1 -0
- package/dist/assistant/store.d.ts +6 -0
- package/dist/assistant/store.d.ts.map +1 -0
- package/dist/assistant/store.js +21 -0
- package/dist/assistant/store.js.map +1 -0
- package/dist/assistant/ui/ink.d.ts +247 -0
- package/dist/assistant/ui/ink.d.ts.map +1 -0
- package/dist/assistant/ui/ink.js +2417 -0
- package/dist/assistant/ui/ink.js.map +1 -0
- package/dist/assistant/ui/theme.d.ts +64 -0
- package/dist/assistant/ui/theme.d.ts.map +1 -0
- package/dist/assistant/ui/theme.js +180 -0
- package/dist/assistant/ui/theme.js.map +1 -0
- package/dist/assistant/ui/view-model.d.ts +89 -0
- package/dist/assistant/ui/view-model.d.ts.map +1 -0
- package/dist/assistant/ui/view-model.js +298 -0
- package/dist/assistant/ui/view-model.js.map +1 -0
- package/dist/assistant-chat-ink.d.ts +2 -0
- package/dist/assistant-chat-ink.d.ts.map +1 -0
- package/dist/assistant-chat-ink.js +2 -0
- package/dist/assistant-chat-ink.js.map +1 -0
- package/dist/assistant-daemon-client.d.ts +81 -0
- package/dist/assistant-daemon-client.d.ts.map +1 -0
- package/dist/assistant-daemon-client.js +473 -0
- package/dist/assistant-daemon-client.js.map +1 -0
- package/dist/assistant-runtime.d.ts +25 -0
- package/dist/assistant-runtime.d.ts.map +1 -0
- package/dist/assistant-runtime.js +17 -0
- package/dist/assistant-runtime.js.map +1 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +7 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli-entry.d.ts +10 -0
- package/dist/cli-entry.d.ts.map +1 -0
- package/dist/cli-entry.js +127 -0
- package/dist/cli-entry.js.map +1 -0
- package/dist/commands/assistant.d.ts +5 -0
- package/dist/commands/assistant.d.ts.map +1 -0
- package/dist/commands/assistant.js +1663 -0
- package/dist/commands/assistant.js.map +1 -0
- package/dist/commands/audit-command-helpers.d.ts +15 -0
- package/dist/commands/audit-command-helpers.d.ts.map +1 -0
- package/dist/commands/audit-command-helpers.js +24 -0
- package/dist/commands/audit-command-helpers.js.map +1 -0
- package/dist/commands/audit.d.ts +4 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +107 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/device.d.ts +4 -0
- package/dist/commands/device.d.ts.map +1 -0
- package/dist/commands/device.js +177 -0
- package/dist/commands/device.js.map +1 -0
- package/dist/commands/document.d.ts +4 -0
- package/dist/commands/document.d.ts.map +1 -0
- package/dist/commands/document.js +117 -0
- package/dist/commands/document.js.map +1 -0
- package/dist/commands/event.d.ts +4 -0
- package/dist/commands/event.d.ts.map +1 -0
- package/dist/commands/event.js +136 -0
- package/dist/commands/event.js.map +1 -0
- package/dist/commands/experiment.d.ts +4 -0
- package/dist/commands/experiment.d.ts.map +1 -0
- package/dist/commands/experiment.js +140 -0
- package/dist/commands/experiment.js.map +1 -0
- package/dist/commands/export-intake-read-helpers.d.ts +150 -0
- package/dist/commands/export-intake-read-helpers.d.ts.map +1 -0
- package/dist/commands/export-intake-read-helpers.js +328 -0
- package/dist/commands/export-intake-read-helpers.js.map +1 -0
- package/dist/commands/export.d.ts +4 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +179 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/food.d.ts +4 -0
- package/dist/commands/food.d.ts.map +1 -0
- package/dist/commands/food.js +190 -0
- package/dist/commands/food.js.map +1 -0
- package/dist/commands/health-command-factory.d.ts +230 -0
- package/dist/commands/health-command-factory.d.ts.map +1 -0
- package/dist/commands/health-command-factory.js +551 -0
- package/dist/commands/health-command-factory.js.map +1 -0
- package/dist/commands/health-entity-command-registry.d.ts +27 -0
- package/dist/commands/health-entity-command-registry.d.ts.map +1 -0
- package/dist/commands/health-entity-command-registry.js +84 -0
- package/dist/commands/health-entity-command-registry.js.map +1 -0
- package/dist/commands/inbox.d.ts +5 -0
- package/dist/commands/inbox.d.ts.map +1 -0
- package/dist/commands/inbox.js +841 -0
- package/dist/commands/inbox.js.map +1 -0
- package/dist/commands/intake.d.ts +4 -0
- package/dist/commands/intake.d.ts.map +1 -0
- package/dist/commands/intake.js +175 -0
- package/dist/commands/intake.js.map +1 -0
- package/dist/commands/intervention.d.ts +4 -0
- package/dist/commands/intervention.d.ts.map +1 -0
- package/dist/commands/intervention.js +122 -0
- package/dist/commands/intervention.js.map +1 -0
- package/dist/commands/journal.d.ts +12 -0
- package/dist/commands/journal.d.ts.map +1 -0
- package/dist/commands/journal.js +186 -0
- package/dist/commands/journal.js.map +1 -0
- package/dist/commands/meal.d.ts +4 -0
- package/dist/commands/meal.d.ts.map +1 -0
- package/dist/commands/meal.js +123 -0
- package/dist/commands/meal.js.map +1 -0
- package/dist/commands/profile.d.ts +4 -0
- package/dist/commands/profile.d.ts.map +1 -0
- package/dist/commands/profile.js +62 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/commands/protocol.d.ts +4 -0
- package/dist/commands/protocol.d.ts.map +1 -0
- package/dist/commands/protocol.js +79 -0
- package/dist/commands/protocol.js.map +1 -0
- package/dist/commands/provider.d.ts +4 -0
- package/dist/commands/provider.d.ts.map +1 -0
- package/dist/commands/provider.js +115 -0
- package/dist/commands/provider.js.map +1 -0
- package/dist/commands/read.d.ts +4 -0
- package/dist/commands/read.d.ts.map +1 -0
- package/dist/commands/read.js +55 -0
- package/dist/commands/read.js.map +1 -0
- package/dist/commands/recipe.d.ts +4 -0
- package/dist/commands/recipe.d.ts.map +1 -0
- package/dist/commands/recipe.js +116 -0
- package/dist/commands/recipe.js.map +1 -0
- package/dist/commands/record-mutation-command-helpers.d.ts +196 -0
- package/dist/commands/record-mutation-command-helpers.d.ts.map +1 -0
- package/dist/commands/record-mutation-command-helpers.js +150 -0
- package/dist/commands/record-mutation-command-helpers.js.map +1 -0
- package/dist/commands/research.d.ts +3 -0
- package/dist/commands/research.d.ts.map +1 -0
- package/dist/commands/research.js +104 -0
- package/dist/commands/research.js.map +1 -0
- package/dist/commands/sample-batch-command-helpers.d.ts +24 -0
- package/dist/commands/sample-batch-command-helpers.d.ts.map +1 -0
- package/dist/commands/sample-batch-command-helpers.js +99 -0
- package/dist/commands/sample-batch-command-helpers.js.map +1 -0
- package/dist/commands/sample-import-command-helpers.d.ts +24 -0
- package/dist/commands/sample-import-command-helpers.d.ts.map +1 -0
- package/dist/commands/sample-import-command-helpers.js +49 -0
- package/dist/commands/sample-import-command-helpers.js.map +1 -0
- package/dist/commands/sample-query-command-helpers.d.ts +11 -0
- package/dist/commands/sample-query-command-helpers.d.ts.map +1 -0
- package/dist/commands/sample-query-command-helpers.js +26 -0
- package/dist/commands/sample-query-command-helpers.js.map +1 -0
- package/dist/commands/samples.d.ts +4 -0
- package/dist/commands/samples.d.ts.map +1 -0
- package/dist/commands/samples.js +261 -0
- package/dist/commands/samples.js.map +1 -0
- package/dist/commands/search.d.ts +4 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +295 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/supplement.d.ts +4 -0
- package/dist/commands/supplement.d.ts.map +1 -0
- package/dist/commands/supplement.js +338 -0
- package/dist/commands/supplement.js.map +1 -0
- package/dist/commands/vault.d.ts +4 -0
- package/dist/commands/vault.d.ts.map +1 -0
- package/dist/commands/vault.js +164 -0
- package/dist/commands/vault.js.map +1 -0
- package/dist/commands/workout.d.ts +4 -0
- package/dist/commands/workout.d.ts.map +1 -0
- package/dist/commands/workout.js +284 -0
- package/dist/commands/workout.js.map +1 -0
- package/dist/incur.generated.d.ts +2164 -0
- package/dist/incur.generated.d.ts.map +1 -0
- package/dist/incur.generated.js +2 -0
- package/dist/incur.generated.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/research-cli-contracts.d.ts +22 -0
- package/dist/research-cli-contracts.d.ts.map +1 -0
- package/dist/research-cli-contracts.js +18 -0
- package/dist/research-cli-contracts.js.map +1 -0
- package/dist/research-runtime.d.ts +79 -0
- package/dist/research-runtime.d.ts.map +1 -0
- package/dist/research-runtime.js +351 -0
- package/dist/research-runtime.js.map +1 -0
- package/dist/run-terminal-logging.d.ts +12 -0
- package/dist/run-terminal-logging.d.ts.map +1 -0
- package/dist/run-terminal-logging.js +323 -0
- package/dist/run-terminal-logging.js.map +1 -0
- package/dist/setup-agentmail.d.ts +30 -0
- package/dist/setup-agentmail.d.ts.map +1 -0
- package/dist/setup-agentmail.js +136 -0
- package/dist/setup-agentmail.js.map +1 -0
- package/dist/setup-assistant-account.d.ts +29 -0
- package/dist/setup-assistant-account.d.ts.map +1 -0
- package/dist/setup-assistant-account.js +443 -0
- package/dist/setup-assistant-account.js.map +1 -0
- package/dist/setup-assistant.d.ts +34 -0
- package/dist/setup-assistant.d.ts.map +1 -0
- package/dist/setup-assistant.js +355 -0
- package/dist/setup-assistant.js.map +1 -0
- package/dist/setup-cli.d.ts +72 -0
- package/dist/setup-cli.d.ts.map +1 -0
- package/dist/setup-cli.js +387 -0
- package/dist/setup-cli.js.map +1 -0
- package/dist/setup-services/channels.d.ts +19 -0
- package/dist/setup-services/channels.d.ts.map +1 -0
- package/dist/setup-services/channels.js +721 -0
- package/dist/setup-services/channels.js.map +1 -0
- package/dist/setup-services/process.d.ts +18 -0
- package/dist/setup-services/process.d.ts.map +1 -0
- package/dist/setup-services/process.js +98 -0
- package/dist/setup-services/process.js.map +1 -0
- package/dist/setup-services/scheduled-updates.d.ts +9 -0
- package/dist/setup-services/scheduled-updates.d.ts.map +1 -0
- package/dist/setup-services/scheduled-updates.js +64 -0
- package/dist/setup-services/scheduled-updates.js.map +1 -0
- package/dist/setup-services/shell.d.ts +18 -0
- package/dist/setup-services/shell.d.ts.map +1 -0
- package/dist/setup-services/shell.js +447 -0
- package/dist/setup-services/shell.js.map +1 -0
- package/dist/setup-services/steps.d.ts +39 -0
- package/dist/setup-services/steps.d.ts.map +1 -0
- package/dist/setup-services/steps.js +86 -0
- package/dist/setup-services/steps.js.map +1 -0
- package/dist/setup-services/toolchain.d.ts +46 -0
- package/dist/setup-services/toolchain.d.ts.map +1 -0
- package/dist/setup-services/toolchain.js +232 -0
- package/dist/setup-services/toolchain.js.map +1 -0
- package/dist/setup-services.d.ts +44 -0
- package/dist/setup-services.d.ts.map +1 -0
- package/dist/setup-services.js +739 -0
- package/dist/setup-services.js.map +1 -0
- package/dist/setup-wizard.d.ts +101 -0
- package/dist/setup-wizard.d.ts.map +1 -0
- package/dist/setup-wizard.js +1458 -0
- package/dist/setup-wizard.js.map +1 -0
- package/dist/usecases/intervention.d.ts +63 -0
- package/dist/usecases/intervention.d.ts.map +1 -0
- package/dist/usecases/intervention.js +205 -0
- package/dist/usecases/intervention.js.map +1 -0
- package/dist/usecases/text-duration.d.ts +4 -0
- package/dist/usecases/text-duration.d.ts.map +1 -0
- package/dist/usecases/text-duration.js +63 -0
- package/dist/usecases/text-duration.js.map +1 -0
- package/dist/usecases/workout-format.d.ts +139 -0
- package/dist/usecases/workout-format.d.ts.map +1 -0
- package/dist/usecases/workout-format.js +445 -0
- package/dist/usecases/workout-format.js.map +1 -0
- package/dist/usecases/workout.d.ts +94 -0
- package/dist/usecases/workout.d.ts.map +1 -0
- package/dist/usecases/workout.js +411 -0
- package/dist/usecases/workout.js.map +1 -0
- package/dist/vault-cli-command-manifest.d.ts +562 -0
- package/dist/vault-cli-command-manifest.d.ts.map +1 -0
- package/dist/vault-cli-command-manifest.js +759 -0
- package/dist/vault-cli-command-manifest.js.map +1 -0
- package/dist/vault-cli.d.ts +6 -0
- package/dist/vault-cli.d.ts.map +1 -0
- package/dist/vault-cli.js +38 -0
- package/dist/vault-cli.js.map +1 -0
- package/package.json +85 -0
|
@@ -0,0 +1,721 @@
|
|
|
1
|
+
import { readAssistantAutomationState, saveAssistantAutomationState, } from '@murphai/assistant-core/assistant-state';
|
|
2
|
+
import { resolveAgentmailApiKey } from '@murphai/assistant-core/agentmail-runtime';
|
|
3
|
+
import { getAssistantChannelAdapter } from '@murphai/assistant-core/assistant-runtime';
|
|
4
|
+
import { describeLinqConnectorEndpoint as describeLinqEndpoint } from '@murphai/assistant-core/inbox-app/linq-endpoint';
|
|
5
|
+
import { resolveSetupChannelMissingEnv, SETUP_RUNTIME_ENV_NOTICE, } from '@murphai/assistant-core/setup-runtime-env';
|
|
6
|
+
import { setupChannelValues, } from '@murphai/assistant-core/setup-cli-contracts';
|
|
7
|
+
import { resolveTelegramBotToken } from '@murphai/assistant-core/telegram-runtime';
|
|
8
|
+
import { VaultCliError } from '@murphai/assistant-core/vault-cli-errors';
|
|
9
|
+
import { createStep } from './steps.js';
|
|
10
|
+
const IMESSAGE_SETUP_CONNECTOR_ID = 'imessage:self';
|
|
11
|
+
const IMESSAGE_SETUP_ACCOUNT_ID = 'self';
|
|
12
|
+
const TELEGRAM_SETUP_CONNECTOR_ID = 'telegram:bot';
|
|
13
|
+
const TELEGRAM_SETUP_ACCOUNT_ID = 'bot';
|
|
14
|
+
const LINQ_SETUP_CONNECTOR_ID = 'linq:default';
|
|
15
|
+
const LINQ_SETUP_ACCOUNT_ID = 'default';
|
|
16
|
+
const EMAIL_SETUP_CONNECTOR_ID = 'email:agentmail';
|
|
17
|
+
const EMAIL_SETUP_DISPLAY_NAME = 'Murph';
|
|
18
|
+
const SETUP_CHANNEL_ORDER = [
|
|
19
|
+
'imessage',
|
|
20
|
+
'telegram',
|
|
21
|
+
'linq',
|
|
22
|
+
'email',
|
|
23
|
+
];
|
|
24
|
+
function isSetupChannelSupportedOnPlatform(channel, platform) {
|
|
25
|
+
return channel !== 'imessage' || platform === 'darwin';
|
|
26
|
+
}
|
|
27
|
+
function isSetupChannel(value) {
|
|
28
|
+
return setupChannelValues.includes(value);
|
|
29
|
+
}
|
|
30
|
+
export function normalizeSetupChannels(value) {
|
|
31
|
+
return [...new Set(value ?? [])];
|
|
32
|
+
}
|
|
33
|
+
function isIMessageSetupConnector(connector) {
|
|
34
|
+
return (connector.id === IMESSAGE_SETUP_CONNECTOR_ID ||
|
|
35
|
+
(connector.source === 'imessage' && connector.accountId === IMESSAGE_SETUP_ACCOUNT_ID));
|
|
36
|
+
}
|
|
37
|
+
function isTelegramSetupConnector(connector) {
|
|
38
|
+
return (connector.id === TELEGRAM_SETUP_CONNECTOR_ID ||
|
|
39
|
+
(connector.source === 'telegram' &&
|
|
40
|
+
connector.accountId === TELEGRAM_SETUP_ACCOUNT_ID));
|
|
41
|
+
}
|
|
42
|
+
function isLinqSetupConnector(connector) {
|
|
43
|
+
return (connector.id === LINQ_SETUP_CONNECTOR_ID ||
|
|
44
|
+
(connector.source === 'linq' && connector.accountId === LINQ_SETUP_ACCOUNT_ID));
|
|
45
|
+
}
|
|
46
|
+
function findReusableLinqSetupConnector(connectors) {
|
|
47
|
+
return (connectors.find((connector) => connector.id === LINQ_SETUP_CONNECTOR_ID) ??
|
|
48
|
+
connectors.find((connector) => connector.source === 'linq' && connector.accountId === LINQ_SETUP_ACCOUNT_ID) ??
|
|
49
|
+
connectors.find((connector) => connector.source === 'linq') ??
|
|
50
|
+
null);
|
|
51
|
+
}
|
|
52
|
+
function isEmailSetupConnector(connector) {
|
|
53
|
+
return connector.id === EMAIL_SETUP_CONNECTOR_ID || connector.source === 'email';
|
|
54
|
+
}
|
|
55
|
+
function isSetupAddedEmailConnectorResult(value) {
|
|
56
|
+
return 'selectedInbox' in value;
|
|
57
|
+
}
|
|
58
|
+
function describeLinqConnectorEndpoint(input) {
|
|
59
|
+
const endpoint = describeLinqEndpoint({
|
|
60
|
+
options: {
|
|
61
|
+
linqWebhookHost: input.options.linqWebhookHost,
|
|
62
|
+
linqWebhookPath: input.options.linqWebhookPath,
|
|
63
|
+
linqWebhookPort: input.options.linqWebhookPort ?? undefined,
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
return `${endpoint.host}:${endpoint.port}${endpoint.path}`;
|
|
67
|
+
}
|
|
68
|
+
function describeConfiguredEmailAction(input) {
|
|
69
|
+
if (input.added.provisionedMailbox) {
|
|
70
|
+
return 'Provisioned';
|
|
71
|
+
}
|
|
72
|
+
if (input.added.reusedMailbox || input.selectedInbox) {
|
|
73
|
+
return 'Reused';
|
|
74
|
+
}
|
|
75
|
+
return 'Provisioned';
|
|
76
|
+
}
|
|
77
|
+
const CHANNEL_SPECS = {
|
|
78
|
+
imessage: {
|
|
79
|
+
channel: 'imessage',
|
|
80
|
+
title: 'iMessage channel',
|
|
81
|
+
stepId: 'channel-imessage',
|
|
82
|
+
runtimeUnavailableMessage: 'Murph setup cannot configure iMessage because the inbox source management services are unavailable in this build.',
|
|
83
|
+
readiness: {
|
|
84
|
+
kind: 'always-ready',
|
|
85
|
+
},
|
|
86
|
+
plan(context) {
|
|
87
|
+
if (context.platform !== 'darwin') {
|
|
88
|
+
return {
|
|
89
|
+
supported: false,
|
|
90
|
+
connectorId: null,
|
|
91
|
+
detail: 'Skipped iMessage because it requires macOS. Use Telegram, Linq, or email on Linux, or run iMessage from a Mac host.',
|
|
92
|
+
missingEnv: [],
|
|
93
|
+
stepDetail: 'Skipped iMessage because it requires Messages.app and the local Messages database on macOS.',
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
supported: true,
|
|
98
|
+
connectorId: IMESSAGE_SETUP_CONNECTOR_ID,
|
|
99
|
+
dryRunDetail: 'Would configure the local iMessage inbox connector and enable assistant auto-reply for new conversations.',
|
|
100
|
+
dryRunStepDetail: 'Would add the imessage:self inbox connector and enable assistant auto-reply for new iMessage conversations.',
|
|
101
|
+
missingEnv: [],
|
|
102
|
+
readyForSetup: true,
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
findExistingConnector(connectors) {
|
|
106
|
+
return connectors.find(isIMessageSetupConnector) ?? null;
|
|
107
|
+
},
|
|
108
|
+
async addConnector(context, sourceAdd) {
|
|
109
|
+
return sourceAdd({
|
|
110
|
+
account: IMESSAGE_SETUP_ACCOUNT_ID,
|
|
111
|
+
id: IMESSAGE_SETUP_CONNECTOR_ID,
|
|
112
|
+
includeOwn: true,
|
|
113
|
+
requestId: context.requestId,
|
|
114
|
+
source: 'imessage',
|
|
115
|
+
vault: context.vault,
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
describeReused({ connector }) {
|
|
119
|
+
return {
|
|
120
|
+
stepDetail: `Reusing the iMessage inbox connector "${connector.id}" and enabling assistant auto-reply for new iMessage conversations.`,
|
|
121
|
+
detail: `Reused the iMessage connector "${connector.id}" and enabled assistant auto-reply for new iMessage conversations.`,
|
|
122
|
+
};
|
|
123
|
+
},
|
|
124
|
+
describeAdded({ added }) {
|
|
125
|
+
return {
|
|
126
|
+
stepDetail: `Added the iMessage inbox connector "${added.connector.id}" and enabled assistant auto-reply for new iMessage conversations.`,
|
|
127
|
+
detail: `Configured the iMessage connector "${added.connector.id}" and enabled assistant auto-reply for new iMessage conversations.`,
|
|
128
|
+
};
|
|
129
|
+
},
|
|
130
|
+
matchesConfiguredConnector: isIMessageSetupConnector,
|
|
131
|
+
},
|
|
132
|
+
telegram: {
|
|
133
|
+
channel: 'telegram',
|
|
134
|
+
title: 'Telegram channel',
|
|
135
|
+
stepId: 'channel-telegram',
|
|
136
|
+
runtimeUnavailableMessage: 'Murph setup cannot configure Telegram because the inbox source management services are unavailable in this build.',
|
|
137
|
+
readiness: {
|
|
138
|
+
fallbackReason: 'Telegram readiness probe failed',
|
|
139
|
+
kind: 'doctor-probe',
|
|
140
|
+
},
|
|
141
|
+
plan(context) {
|
|
142
|
+
const token = resolveTelegramBotToken(context.env);
|
|
143
|
+
const readyForSetup = getAssistantChannelAdapter('telegram')?.isReadyForSetup(context.env) ??
|
|
144
|
+
Boolean(token);
|
|
145
|
+
const missingEnv = resolveSetupChannelMissingEnv('telegram', context.env);
|
|
146
|
+
return {
|
|
147
|
+
supported: true,
|
|
148
|
+
connectorId: TELEGRAM_SETUP_CONNECTOR_ID,
|
|
149
|
+
dryRunDetail: token
|
|
150
|
+
? 'Would configure the Telegram bot connector and enable assistant auto-reply for Telegram direct chats.'
|
|
151
|
+
: `Telegram needs TELEGRAM_BOT_TOKEN in the current environment before setup can enable the channel. ${SETUP_RUNTIME_ENV_NOTICE}`,
|
|
152
|
+
dryRunStepDetail: token
|
|
153
|
+
? 'Would verify the Telegram bot token, add or reuse the telegram:bot inbox connector, and enable assistant auto-reply for Telegram direct chats.'
|
|
154
|
+
: 'Would configure Telegram once TELEGRAM_BOT_TOKEN is available in the shell or local `.env`.',
|
|
155
|
+
missingEnv,
|
|
156
|
+
readyForSetup,
|
|
157
|
+
};
|
|
158
|
+
},
|
|
159
|
+
findExistingConnector(connectors) {
|
|
160
|
+
return connectors.find(isTelegramSetupConnector) ?? null;
|
|
161
|
+
},
|
|
162
|
+
async addConnector(context, sourceAdd) {
|
|
163
|
+
return sourceAdd({
|
|
164
|
+
account: TELEGRAM_SETUP_ACCOUNT_ID,
|
|
165
|
+
id: TELEGRAM_SETUP_CONNECTOR_ID,
|
|
166
|
+
requestId: context.requestId,
|
|
167
|
+
source: 'telegram',
|
|
168
|
+
vault: context.vault,
|
|
169
|
+
});
|
|
170
|
+
},
|
|
171
|
+
describeMissingEnv({ existingConnector }) {
|
|
172
|
+
return {
|
|
173
|
+
stepDetail: existingConnector
|
|
174
|
+
? `Reused the Telegram inbox connector "${existingConnector.id}", but did not enable assistant auto-reply because TELEGRAM_BOT_TOKEN was not available in the shell or local \`.env\`.`
|
|
175
|
+
: 'Telegram was selected, but setup did not add the connector because TELEGRAM_BOT_TOKEN was not available in the shell or local `.env`.',
|
|
176
|
+
detail: existingConnector
|
|
177
|
+
? `Reused the Telegram connector "${existingConnector.id}", but skipped assistant auto-reply until a bot token is available in the current environment. ${SETUP_RUNTIME_ENV_NOTICE}`
|
|
178
|
+
: `Telegram needs TELEGRAM_BOT_TOKEN in the current environment before setup can add the connector and enable assistant auto-reply. ${SETUP_RUNTIME_ENV_NOTICE}`,
|
|
179
|
+
};
|
|
180
|
+
},
|
|
181
|
+
describeReused({ connector, readiness }) {
|
|
182
|
+
return {
|
|
183
|
+
stepDetail: readiness.ready
|
|
184
|
+
? `Reusing the Telegram inbox connector "${connector.id}" and enabling assistant auto-reply for Telegram direct chats.`
|
|
185
|
+
: `Reused the Telegram inbox connector "${connector.id}", but did not enable assistant auto-reply because the bot token could not authenticate${readiness.reason ? ` (${readiness.reason})` : ''}.`,
|
|
186
|
+
detail: readiness.ready
|
|
187
|
+
? `Reused the Telegram connector "${connector.id}" and enabled assistant auto-reply for Telegram direct chats.`
|
|
188
|
+
: `Reused the Telegram connector "${connector.id}", but skipped assistant auto-reply until the bot token authenticates successfully with Telegram${readiness.reason ? ` (${readiness.reason})` : ''}.`,
|
|
189
|
+
};
|
|
190
|
+
},
|
|
191
|
+
describeAdded({ added, readiness }) {
|
|
192
|
+
return {
|
|
193
|
+
stepDetail: readiness.ready
|
|
194
|
+
? `Added the Telegram inbox connector "${added.connector.id}" and enabled assistant auto-reply for Telegram direct chats.`
|
|
195
|
+
: `Added the Telegram inbox connector "${added.connector.id}", but did not enable assistant auto-reply because the bot token could not authenticate${readiness.reason ? ` (${readiness.reason})` : ''}.`,
|
|
196
|
+
detail: readiness.ready
|
|
197
|
+
? `Configured the Telegram connector "${added.connector.id}" and enabled assistant auto-reply for Telegram direct chats.`
|
|
198
|
+
: `Configured the Telegram connector "${added.connector.id}", but skipped assistant auto-reply until the bot token authenticates successfully with Telegram${readiness.reason ? ` (${readiness.reason})` : ''}.`,
|
|
199
|
+
};
|
|
200
|
+
},
|
|
201
|
+
matchesConfiguredConnector: isTelegramSetupConnector,
|
|
202
|
+
},
|
|
203
|
+
linq: {
|
|
204
|
+
channel: 'linq',
|
|
205
|
+
title: 'Linq channel',
|
|
206
|
+
stepId: 'channel-linq',
|
|
207
|
+
runtimeUnavailableMessage: 'Murph setup cannot configure Linq because the inbox source management services are unavailable in this build.',
|
|
208
|
+
readiness: {
|
|
209
|
+
fallbackReason: 'Linq readiness probe failed',
|
|
210
|
+
kind: 'doctor-probe',
|
|
211
|
+
},
|
|
212
|
+
plan(context) {
|
|
213
|
+
const readyForSetup = getAssistantChannelAdapter('linq')?.isReadyForSetup(context.env) ?? false;
|
|
214
|
+
const missingEnv = resolveSetupChannelMissingEnv('linq', context.env);
|
|
215
|
+
return {
|
|
216
|
+
supported: true,
|
|
217
|
+
connectorId: LINQ_SETUP_CONNECTOR_ID,
|
|
218
|
+
dryRunDetail: readyForSetup
|
|
219
|
+
? 'Would configure the Linq webhook connector and enable assistant auto-reply for Linq direct chats.'
|
|
220
|
+
: `Linq needs both LINQ_API_TOKEN and LINQ_WEBHOOK_SECRET in the current environment before setup can enable the channel. ${SETUP_RUNTIME_ENV_NOTICE}`,
|
|
221
|
+
dryRunStepDetail: readyForSetup
|
|
222
|
+
? 'Would verify the Linq API token, add or reuse the linq:default inbox connector, and enable assistant auto-reply for Linq direct chats.'
|
|
223
|
+
: 'Would configure Linq once LINQ_API_TOKEN and LINQ_WEBHOOK_SECRET are available in the shell or local `.env`.',
|
|
224
|
+
missingEnv,
|
|
225
|
+
readyForSetup,
|
|
226
|
+
};
|
|
227
|
+
},
|
|
228
|
+
findExistingConnector(connectors) {
|
|
229
|
+
return findReusableLinqSetupConnector(connectors);
|
|
230
|
+
},
|
|
231
|
+
async addConnector(context, sourceAdd) {
|
|
232
|
+
return sourceAdd({
|
|
233
|
+
account: LINQ_SETUP_ACCOUNT_ID,
|
|
234
|
+
id: LINQ_SETUP_CONNECTOR_ID,
|
|
235
|
+
requestId: context.requestId,
|
|
236
|
+
source: 'linq',
|
|
237
|
+
vault: context.vault,
|
|
238
|
+
});
|
|
239
|
+
},
|
|
240
|
+
describeMissingEnv({ existingConnector }) {
|
|
241
|
+
return {
|
|
242
|
+
stepDetail: existingConnector
|
|
243
|
+
? `Reused the Linq inbox connector "${existingConnector.id}", but did not enable assistant auto-reply because LINQ_API_TOKEN and LINQ_WEBHOOK_SECRET were not both available in the shell or local \`.env\`.`
|
|
244
|
+
: 'Linq was selected, but setup did not add the connector because LINQ_API_TOKEN and LINQ_WEBHOOK_SECRET were not both available in the shell or local `.env`.',
|
|
245
|
+
detail: existingConnector
|
|
246
|
+
? `Reused the Linq connector "${existingConnector.id}", but skipped assistant auto-reply until both a Linq API token and webhook secret are available in the current environment. ${SETUP_RUNTIME_ENV_NOTICE}`
|
|
247
|
+
: `Linq needs LINQ_API_TOKEN and LINQ_WEBHOOK_SECRET in the current environment before setup can add the connector and enable assistant auto-reply. ${SETUP_RUNTIME_ENV_NOTICE}`,
|
|
248
|
+
};
|
|
249
|
+
},
|
|
250
|
+
describeReused({ connector, readiness }) {
|
|
251
|
+
const endpoint = describeLinqConnectorEndpoint(connector);
|
|
252
|
+
return {
|
|
253
|
+
stepDetail: readiness.ready
|
|
254
|
+
? `Reusing the Linq inbox connector "${connector.id}" at ${endpoint} and enabling assistant auto-reply for Linq direct chats.`
|
|
255
|
+
: `Reused the Linq inbox connector "${connector.id}" at ${endpoint}, but did not enable assistant auto-reply because the API token could not authenticate${readiness.reason ? ` (${readiness.reason})` : ''}.`,
|
|
256
|
+
detail: readiness.ready
|
|
257
|
+
? `Reused the Linq connector "${connector.id}" at ${endpoint} and enabled assistant auto-reply for Linq direct chats.`
|
|
258
|
+
: `Reused the Linq connector "${connector.id}" at ${endpoint}, but skipped assistant auto-reply until the Linq API token authenticates successfully${readiness.reason ? ` (${readiness.reason})` : ''}.`,
|
|
259
|
+
};
|
|
260
|
+
},
|
|
261
|
+
describeAdded({ added, readiness }) {
|
|
262
|
+
const endpoint = describeLinqConnectorEndpoint(added.connector);
|
|
263
|
+
return {
|
|
264
|
+
stepDetail: readiness.ready
|
|
265
|
+
? `Added the Linq inbox connector "${added.connector.id}" at ${endpoint} and enabled assistant auto-reply for Linq direct chats.`
|
|
266
|
+
: `Added the Linq inbox connector "${added.connector.id}" at ${endpoint}, but did not enable assistant auto-reply because the API token could not authenticate${readiness.reason ? ` (${readiness.reason})` : ''}.`,
|
|
267
|
+
detail: readiness.ready
|
|
268
|
+
? `Configured the Linq connector "${added.connector.id}" at ${endpoint} and enabled assistant auto-reply for Linq direct chats.`
|
|
269
|
+
: `Configured the Linq connector "${added.connector.id}" at ${endpoint}, but skipped assistant auto-reply until the Linq API token authenticates successfully${readiness.reason ? ` (${readiness.reason})` : ''}.`,
|
|
270
|
+
};
|
|
271
|
+
},
|
|
272
|
+
matchesConfiguredConnector: isLinqSetupConnector,
|
|
273
|
+
},
|
|
274
|
+
email: {
|
|
275
|
+
channel: 'email',
|
|
276
|
+
title: 'Email channel',
|
|
277
|
+
stepId: 'channel-email',
|
|
278
|
+
runtimeUnavailableMessage: 'Murph setup cannot configure email because the inbox source management services are unavailable in this build.',
|
|
279
|
+
readiness: {
|
|
280
|
+
fallbackReason: 'Email readiness probe failed',
|
|
281
|
+
kind: 'doctor-probe',
|
|
282
|
+
treatProbeWarnAsReady: true,
|
|
283
|
+
},
|
|
284
|
+
plan(context) {
|
|
285
|
+
const apiKey = resolveAgentmailApiKey(context.env);
|
|
286
|
+
const missingEnv = resolveSetupChannelMissingEnv('email', context.env);
|
|
287
|
+
return {
|
|
288
|
+
supported: true,
|
|
289
|
+
connectorId: EMAIL_SETUP_CONNECTOR_ID,
|
|
290
|
+
dryRunDetail: apiKey
|
|
291
|
+
? 'Would reuse an existing AgentMail inbox when possible, or provision a new inbox connector and enable assistant auto-reply for direct email threads.'
|
|
292
|
+
: `Email needs AGENTMAIL_API_KEY in the current environment before setup can enable the channel. ${SETUP_RUNTIME_ENV_NOTICE}`,
|
|
293
|
+
dryRunStepDetail: apiKey
|
|
294
|
+
? 'Would provision or reuse an AgentMail inbox, verify email polling, and enable assistant auto-reply for direct email threads.'
|
|
295
|
+
: 'Would configure email once AGENTMAIL_API_KEY is available in the shell or local `.env`.',
|
|
296
|
+
missingEnv,
|
|
297
|
+
readyForSetup: Boolean(apiKey),
|
|
298
|
+
};
|
|
299
|
+
},
|
|
300
|
+
findExistingConnector(connectors) {
|
|
301
|
+
return connectors.find(isEmailSetupConnector) ?? null;
|
|
302
|
+
},
|
|
303
|
+
async addConnector(context, sourceAdd) {
|
|
304
|
+
const apiKey = resolveAgentmailApiKey(context.env);
|
|
305
|
+
const selectedInbox = context.resolveAgentmailInboxSelection && apiKey
|
|
306
|
+
? await context.resolveAgentmailInboxSelection({
|
|
307
|
+
allowPrompt: context.allowPrompt,
|
|
308
|
+
env: context.env,
|
|
309
|
+
})
|
|
310
|
+
: null;
|
|
311
|
+
const added = await sourceAdd({
|
|
312
|
+
account: selectedInbox?.accountId,
|
|
313
|
+
address: selectedInbox?.emailAddress ?? undefined,
|
|
314
|
+
id: EMAIL_SETUP_CONNECTOR_ID,
|
|
315
|
+
provision: selectedInbox === null,
|
|
316
|
+
emailDisplayName: EMAIL_SETUP_DISPLAY_NAME,
|
|
317
|
+
requestId: context.requestId,
|
|
318
|
+
source: 'email',
|
|
319
|
+
vault: context.vault,
|
|
320
|
+
});
|
|
321
|
+
return { ...added, selectedInbox };
|
|
322
|
+
},
|
|
323
|
+
describeMissingEnv({ existingConnector }) {
|
|
324
|
+
return {
|
|
325
|
+
stepDetail: existingConnector
|
|
326
|
+
? `Reused the email inbox connector "${existingConnector.id}", but did not enable assistant auto-reply because AGENTMAIL_API_KEY was not available in the shell or local \`.env\`.`
|
|
327
|
+
: 'Email was selected, but setup did not add the connector because AGENTMAIL_API_KEY was not available in the shell or local `.env`.',
|
|
328
|
+
detail: existingConnector
|
|
329
|
+
? `Reused the email connector "${existingConnector.id}", but skipped assistant auto-reply until an AgentMail API key is available in the current environment. ${SETUP_RUNTIME_ENV_NOTICE}`
|
|
330
|
+
: `Email needs AGENTMAIL_API_KEY in the current environment before setup can reuse or provision the connector and enable assistant auto-reply. ${SETUP_RUNTIME_ENV_NOTICE}`,
|
|
331
|
+
};
|
|
332
|
+
},
|
|
333
|
+
describeReused({ connector, readiness }) {
|
|
334
|
+
return {
|
|
335
|
+
stepDetail: readiness.ready
|
|
336
|
+
? `Reusing the email inbox connector "${connector.id}" and enabling assistant auto-reply for direct email threads.`
|
|
337
|
+
: `Reused the email inbox connector "${connector.id}", but did not enable assistant auto-reply because AgentMail readiness checks failed${readiness.reason ? ` (${readiness.reason})` : ''}.`,
|
|
338
|
+
detail: readiness.ready
|
|
339
|
+
? `Reused the email connector "${connector.id}" and enabled assistant auto-reply for direct email threads.`
|
|
340
|
+
: `Reused the email connector "${connector.id}", but skipped assistant auto-reply until AgentMail readiness checks succeed${readiness.reason ? ` (${readiness.reason})` : ''}.`,
|
|
341
|
+
};
|
|
342
|
+
},
|
|
343
|
+
describeAdded({ added, readiness }) {
|
|
344
|
+
const selectedInbox = isSetupAddedEmailConnectorResult(added)
|
|
345
|
+
? added.selectedInbox ?? null
|
|
346
|
+
: null;
|
|
347
|
+
const configuredAddress = added.provisionedMailbox?.emailAddress ??
|
|
348
|
+
added.reusedMailbox?.emailAddress ??
|
|
349
|
+
selectedInbox?.emailAddress ??
|
|
350
|
+
added.connector.options.emailAddress ??
|
|
351
|
+
null;
|
|
352
|
+
const actionVerb = describeConfiguredEmailAction({
|
|
353
|
+
added,
|
|
354
|
+
selectedInbox,
|
|
355
|
+
});
|
|
356
|
+
return {
|
|
357
|
+
stepDetail: readiness.ready
|
|
358
|
+
? `${actionVerb} the AgentMail inbox connector "${added.connector.id}"${configuredAddress ? ` at ${configuredAddress}` : ''} and enabled assistant auto-reply for direct email threads.`
|
|
359
|
+
: `${actionVerb} the AgentMail inbox connector "${added.connector.id}"${configuredAddress ? ` at ${configuredAddress}` : ''}, but did not enable assistant auto-reply because AgentMail readiness checks failed${readiness.reason ? ` (${readiness.reason})` : ''}.`,
|
|
360
|
+
detail: readiness.ready
|
|
361
|
+
? `Configured the email connector "${added.connector.id}"${configuredAddress ? ` at ${configuredAddress}` : ''} and enabled assistant auto-reply for direct email threads.`
|
|
362
|
+
: `Configured the email connector "${added.connector.id}"${configuredAddress ? ` at ${configuredAddress}` : ''}, but skipped assistant auto-reply until AgentMail readiness checks succeed${readiness.reason ? ` (${readiness.reason})` : ''}.`,
|
|
363
|
+
};
|
|
364
|
+
},
|
|
365
|
+
matchesConfiguredConnector: isEmailSetupConnector,
|
|
366
|
+
},
|
|
367
|
+
};
|
|
368
|
+
const CHANNEL_CONFIGURERS = {
|
|
369
|
+
imessage: configureIMessageChannel,
|
|
370
|
+
telegram: configureTelegramChannel,
|
|
371
|
+
linq: configureLinqChannel,
|
|
372
|
+
email: configureEmailChannel,
|
|
373
|
+
};
|
|
374
|
+
export async function configureSetupChannels(input) {
|
|
375
|
+
const configured = [];
|
|
376
|
+
const platform = input.platform ?? process.platform;
|
|
377
|
+
const context = {
|
|
378
|
+
allowPrompt: input.allowPrompt ?? false,
|
|
379
|
+
dryRun: input.dryRun,
|
|
380
|
+
env: input.env,
|
|
381
|
+
inboxServices: input.inboxServices,
|
|
382
|
+
platform,
|
|
383
|
+
requestId: input.requestId,
|
|
384
|
+
resolveAgentmailInboxSelection: input.resolveAgentmailInboxSelection,
|
|
385
|
+
steps: input.steps,
|
|
386
|
+
vault: input.vault,
|
|
387
|
+
};
|
|
388
|
+
const selectedChannels = new Set(normalizeSetupChannels(input.channels));
|
|
389
|
+
for (const channel of SETUP_CHANNEL_ORDER) {
|
|
390
|
+
if (!selectedChannels.has(channel)) {
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
configured.push(await CHANNEL_CONFIGURERS[channel](context));
|
|
394
|
+
}
|
|
395
|
+
if (!input.dryRun) {
|
|
396
|
+
await reconcileDeselectedSetupChannels({
|
|
397
|
+
channels: input.channels,
|
|
398
|
+
inboxServices: input.inboxServices,
|
|
399
|
+
platform,
|
|
400
|
+
requestId: input.requestId,
|
|
401
|
+
vault: input.vault,
|
|
402
|
+
});
|
|
403
|
+
await updateAssistantChannelState({
|
|
404
|
+
autoReplyChannels: configured
|
|
405
|
+
.filter((channel) => channel.autoReply)
|
|
406
|
+
.map((channel) => channel.channel),
|
|
407
|
+
platform,
|
|
408
|
+
preferredChannels: filterPersistedSetupChannels(input.channels, platform),
|
|
409
|
+
vault: input.vault,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
return configured;
|
|
413
|
+
}
|
|
414
|
+
function filterPersistedSetupChannels(channels, platform) {
|
|
415
|
+
return normalizeSetupChannels(channels).filter((channel) => isSetupChannelSupportedOnPlatform(channel, platform));
|
|
416
|
+
}
|
|
417
|
+
async function configureIMessageChannel(context) {
|
|
418
|
+
return configureSetupChannel(CHANNEL_SPECS.imessage, context);
|
|
419
|
+
}
|
|
420
|
+
async function configureTelegramChannel(context) {
|
|
421
|
+
return configureSetupChannel(CHANNEL_SPECS.telegram, context);
|
|
422
|
+
}
|
|
423
|
+
async function configureLinqChannel(context) {
|
|
424
|
+
return configureSetupChannel(CHANNEL_SPECS.linq, context);
|
|
425
|
+
}
|
|
426
|
+
async function configureEmailChannel(context) {
|
|
427
|
+
return configureSetupChannel(CHANNEL_SPECS.email, context);
|
|
428
|
+
}
|
|
429
|
+
async function configureSetupChannel(spec, context) {
|
|
430
|
+
const plan = spec.plan(context);
|
|
431
|
+
if (isUnsupportedSetupChannelPlan(plan)) {
|
|
432
|
+
return recordSetupChannelResult(spec, context, {
|
|
433
|
+
autoReplyReady: false,
|
|
434
|
+
connectorEnabled: false,
|
|
435
|
+
connectorId: plan.connectorId,
|
|
436
|
+
connectorPresent: false,
|
|
437
|
+
detail: plan.detail,
|
|
438
|
+
missingEnv: plan.missingEnv,
|
|
439
|
+
outcome: 'unsupported',
|
|
440
|
+
stepDetail: plan.stepDetail,
|
|
441
|
+
stepStatus: 'skipped',
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
if (context.dryRun) {
|
|
445
|
+
return recordSetupChannelResult(spec, context, {
|
|
446
|
+
autoReplyReady: plan.readyForSetup,
|
|
447
|
+
connectorEnabled: plan.readyForSetup,
|
|
448
|
+
connectorId: plan.connectorId,
|
|
449
|
+
connectorPresent: false,
|
|
450
|
+
detail: plan.dryRunDetail,
|
|
451
|
+
missingEnv: plan.missingEnv,
|
|
452
|
+
outcome: 'dry-run',
|
|
453
|
+
stepDetail: plan.dryRunStepDetail,
|
|
454
|
+
stepStatus: 'planned',
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
const doctor = context.inboxServices.doctor;
|
|
458
|
+
const sourceList = context.inboxServices.sourceList;
|
|
459
|
+
const sourceAdd = context.inboxServices.sourceAdd;
|
|
460
|
+
const sourceSetEnabled = context.inboxServices.sourceSetEnabled;
|
|
461
|
+
if (!sourceList || !sourceAdd) {
|
|
462
|
+
throw new VaultCliError('runtime_unavailable', spec.runtimeUnavailableMessage);
|
|
463
|
+
}
|
|
464
|
+
const listed = await sourceList({
|
|
465
|
+
vault: context.vault,
|
|
466
|
+
requestId: context.requestId,
|
|
467
|
+
});
|
|
468
|
+
const existingConnector = spec.findExistingConnector(listed.connectors);
|
|
469
|
+
if (!plan.readyForSetup) {
|
|
470
|
+
if (!spec.describeMissingEnv) {
|
|
471
|
+
throw new Error(`Missing environment message handler is required for ${spec.channel}.`);
|
|
472
|
+
}
|
|
473
|
+
const messages = spec.describeMissingEnv({
|
|
474
|
+
existingConnector,
|
|
475
|
+
});
|
|
476
|
+
const connectorPresent = existingConnector !== null;
|
|
477
|
+
const connectorEnabled = existingConnector?.enabled ?? false;
|
|
478
|
+
return recordSetupChannelResult(spec, context, {
|
|
479
|
+
autoReplyReady: false,
|
|
480
|
+
connectorEnabled,
|
|
481
|
+
connectorId: existingConnector?.id ?? null,
|
|
482
|
+
connectorPresent,
|
|
483
|
+
detail: messages.detail,
|
|
484
|
+
missingEnv: plan.missingEnv,
|
|
485
|
+
outcome: 'missing-env',
|
|
486
|
+
stepDetail: messages.stepDetail,
|
|
487
|
+
stepStatus: existingConnector ? 'reused' : 'skipped',
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
if (existingConnector) {
|
|
491
|
+
const connectorEnabled = await ensureSetupConnectorEnabled({
|
|
492
|
+
connectorId: existingConnector.id,
|
|
493
|
+
enabled: existingConnector.enabled,
|
|
494
|
+
requestId: context.requestId,
|
|
495
|
+
sourceSetEnabled,
|
|
496
|
+
vault: context.vault,
|
|
497
|
+
});
|
|
498
|
+
const readiness = await resolveSetupChannelReadiness({
|
|
499
|
+
connectorId: existingConnector.id,
|
|
500
|
+
doctor,
|
|
501
|
+
requestId: context.requestId,
|
|
502
|
+
readiness: spec.readiness,
|
|
503
|
+
vault: context.vault,
|
|
504
|
+
});
|
|
505
|
+
const autoReplyReady = readiness.ready;
|
|
506
|
+
const messages = spec.describeReused({
|
|
507
|
+
connector: existingConnector,
|
|
508
|
+
readiness,
|
|
509
|
+
});
|
|
510
|
+
return recordSetupChannelResult(spec, context, {
|
|
511
|
+
autoReplyReady,
|
|
512
|
+
connectorEnabled,
|
|
513
|
+
connectorId: existingConnector.id,
|
|
514
|
+
connectorPresent: true,
|
|
515
|
+
detail: messages.detail,
|
|
516
|
+
missingEnv: [],
|
|
517
|
+
outcome: 'reused',
|
|
518
|
+
stepDetail: messages.stepDetail,
|
|
519
|
+
stepStatus: 'reused',
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
const added = await spec.addConnector(context, sourceAdd);
|
|
523
|
+
const autoReplyReadiness = await resolveSetupChannelReadiness({
|
|
524
|
+
connectorId: added.connector.id,
|
|
525
|
+
doctor,
|
|
526
|
+
requestId: context.requestId,
|
|
527
|
+
readiness: spec.readiness,
|
|
528
|
+
vault: context.vault,
|
|
529
|
+
});
|
|
530
|
+
const autoReplyReady = autoReplyReadiness.ready;
|
|
531
|
+
const messages = spec.describeAdded({
|
|
532
|
+
added,
|
|
533
|
+
readiness: autoReplyReadiness,
|
|
534
|
+
});
|
|
535
|
+
return recordSetupChannelResult(spec, context, {
|
|
536
|
+
autoReplyReady,
|
|
537
|
+
connectorEnabled: added.connector.enabled,
|
|
538
|
+
connectorId: added.connector.id,
|
|
539
|
+
connectorPresent: true,
|
|
540
|
+
detail: messages.detail,
|
|
541
|
+
missingEnv: [],
|
|
542
|
+
outcome: 'added',
|
|
543
|
+
stepDetail: messages.stepDetail,
|
|
544
|
+
stepStatus: 'completed',
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
function isUnsupportedSetupChannelPlan(plan) {
|
|
548
|
+
return plan.supported === false;
|
|
549
|
+
}
|
|
550
|
+
function recordSetupChannelResult(spec, context, resolution) {
|
|
551
|
+
context.steps.push(createStep({
|
|
552
|
+
detail: resolution.stepDetail,
|
|
553
|
+
id: spec.stepId,
|
|
554
|
+
kind: 'configure',
|
|
555
|
+
status: resolution.stepStatus,
|
|
556
|
+
title: spec.title,
|
|
557
|
+
}));
|
|
558
|
+
return {
|
|
559
|
+
autoReply: resolution.autoReplyReady,
|
|
560
|
+
channel: spec.channel,
|
|
561
|
+
configured: mapConfiguredSetupChannelResolution(resolution),
|
|
562
|
+
connectorId: resolution.connectorId,
|
|
563
|
+
detail: resolution.detail,
|
|
564
|
+
// Preserve the historical setup result contract at the boundary while the
|
|
565
|
+
// orchestration tracks connector presence/readiness separately.
|
|
566
|
+
enabled: true,
|
|
567
|
+
missingEnv: resolution.missingEnv,
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
function mapConfiguredSetupChannelResolution(resolution) {
|
|
571
|
+
switch (resolution.outcome) {
|
|
572
|
+
case 'missing-env':
|
|
573
|
+
return resolution.connectorPresent;
|
|
574
|
+
case 'reused':
|
|
575
|
+
case 'added':
|
|
576
|
+
return resolution.autoReplyReady;
|
|
577
|
+
case 'unsupported':
|
|
578
|
+
case 'dry-run':
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
async function resolveSetupChannelReadiness(input) {
|
|
583
|
+
if (input.readiness.kind === 'always-ready') {
|
|
584
|
+
return {
|
|
585
|
+
ready: true,
|
|
586
|
+
reason: null,
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
return probeSetupReadiness({
|
|
590
|
+
connectorId: input.connectorId,
|
|
591
|
+
doctor: input.doctor,
|
|
592
|
+
fallbackReason: input.readiness.fallbackReason,
|
|
593
|
+
requestId: input.requestId,
|
|
594
|
+
treatProbeWarnAsReady: input.readiness.treatProbeWarnAsReady,
|
|
595
|
+
vault: input.vault,
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
async function probeSetupReadiness(input) {
|
|
599
|
+
if (!input.doctor) {
|
|
600
|
+
return {
|
|
601
|
+
ready: true,
|
|
602
|
+
reason: null,
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
const result = await input.doctor({
|
|
606
|
+
requestId: input.requestId,
|
|
607
|
+
sourceId: input.connectorId,
|
|
608
|
+
vault: input.vault,
|
|
609
|
+
});
|
|
610
|
+
const probeCheck = result.checks.find((check) => check.name === 'probe') ?? null;
|
|
611
|
+
const driverImportCheck = result.checks.find((check) => check.name === 'driver-import') ?? null;
|
|
612
|
+
const ready = Boolean((probeCheck?.status === 'pass' ||
|
|
613
|
+
(input.treatProbeWarnAsReady === true && probeCheck?.status === 'warn')) &&
|
|
614
|
+
(driverImportCheck === null || driverImportCheck.status === 'pass'));
|
|
615
|
+
return {
|
|
616
|
+
ready,
|
|
617
|
+
reason: ready
|
|
618
|
+
? null
|
|
619
|
+
: probeCheck?.message ?? driverImportCheck?.message ?? input.fallbackReason,
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
async function updateAssistantChannelState(input) {
|
|
623
|
+
const state = await readAssistantAutomationState(input.vault);
|
|
624
|
+
const preservedAutoReplyChannels = state.autoReplyChannels.filter((channel) => isSetupChannel(channel) &&
|
|
625
|
+
!isSetupChannelSupportedOnPlatform(channel, input.platform));
|
|
626
|
+
const preservedPreferredChannels = state.preferredChannels.filter((channel) => isSetupChannel(channel) &&
|
|
627
|
+
!isSetupChannelSupportedOnPlatform(channel, input.platform));
|
|
628
|
+
const autoReplyChannels = normalizeSetupChannels([
|
|
629
|
+
...input.autoReplyChannels,
|
|
630
|
+
...preservedAutoReplyChannels,
|
|
631
|
+
]);
|
|
632
|
+
const preferredChannels = normalizeSetupChannels([
|
|
633
|
+
...input.preferredChannels,
|
|
634
|
+
...preservedPreferredChannels,
|
|
635
|
+
]);
|
|
636
|
+
const nextBacklogChannels = normalizeSetupChannels(state.autoReplyBacklogChannels.filter((channel) => channel === 'email' && autoReplyChannels.includes(channel)));
|
|
637
|
+
if (autoReplyChannels.includes('email') && !state.autoReplyChannels.includes('email')) {
|
|
638
|
+
nextBacklogChannels.push('email');
|
|
639
|
+
}
|
|
640
|
+
const autoReplyChanged = autoReplyChannels.length !== state.autoReplyChannels.length ||
|
|
641
|
+
autoReplyChannels.some((channel, index) => state.autoReplyChannels[index] !== channel);
|
|
642
|
+
const preferredChanged = preferredChannels.length !== state.preferredChannels.length ||
|
|
643
|
+
preferredChannels.some((channel, index) => state.preferredChannels[index] !== channel);
|
|
644
|
+
const backlogChanged = nextBacklogChannels.length !== state.autoReplyBacklogChannels.length ||
|
|
645
|
+
nextBacklogChannels.some((channel, index) => state.autoReplyBacklogChannels[index] !== channel);
|
|
646
|
+
if (!autoReplyChanged && !preferredChanged && !backlogChanged) {
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
await saveAssistantAutomationState(input.vault, {
|
|
650
|
+
version: 2,
|
|
651
|
+
inboxScanCursor: state.inboxScanCursor,
|
|
652
|
+
autoReplyScanCursor: autoReplyChannels.length === 0
|
|
653
|
+
? null
|
|
654
|
+
: autoReplyChanged
|
|
655
|
+
? null
|
|
656
|
+
: state.autoReplyScanCursor,
|
|
657
|
+
autoReplyChannels,
|
|
658
|
+
preferredChannels,
|
|
659
|
+
autoReplyBacklogChannels: nextBacklogChannels,
|
|
660
|
+
autoReplyPrimed: autoReplyChannels.length === 0
|
|
661
|
+
? true
|
|
662
|
+
: autoReplyChanged
|
|
663
|
+
? false
|
|
664
|
+
: state.autoReplyPrimed,
|
|
665
|
+
preferredScheduledUpdates: state.preferredScheduledUpdates,
|
|
666
|
+
updatedAt: new Date().toISOString(),
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
async function reconcileDeselectedSetupChannels(input) {
|
|
670
|
+
const sourceList = input.inboxServices.sourceList;
|
|
671
|
+
const sourceSetEnabled = input.inboxServices.sourceSetEnabled;
|
|
672
|
+
if (!sourceList || !sourceSetEnabled) {
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
const selectedChannels = new Set(normalizeSetupChannels(input.channels));
|
|
676
|
+
const listed = await sourceList({
|
|
677
|
+
vault: input.vault,
|
|
678
|
+
requestId: input.requestId,
|
|
679
|
+
});
|
|
680
|
+
for (const connector of listed.connectors) {
|
|
681
|
+
if (!connector.enabled) {
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
684
|
+
const setupChannel = resolveSetupChannelForConnector(connector);
|
|
685
|
+
if (!setupChannel ||
|
|
686
|
+
!isSetupChannelSupportedOnPlatform(setupChannel, input.platform) ||
|
|
687
|
+
selectedChannels.has(setupChannel)) {
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
await sourceSetEnabled({
|
|
691
|
+
connectorId: connector.id,
|
|
692
|
+
enabled: false,
|
|
693
|
+
requestId: input.requestId,
|
|
694
|
+
vault: input.vault,
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
async function ensureSetupConnectorEnabled(input) {
|
|
699
|
+
if (input.enabled) {
|
|
700
|
+
return true;
|
|
701
|
+
}
|
|
702
|
+
if (!input.sourceSetEnabled) {
|
|
703
|
+
return false;
|
|
704
|
+
}
|
|
705
|
+
await input.sourceSetEnabled({
|
|
706
|
+
connectorId: input.connectorId,
|
|
707
|
+
enabled: true,
|
|
708
|
+
requestId: input.requestId,
|
|
709
|
+
vault: input.vault,
|
|
710
|
+
});
|
|
711
|
+
return true;
|
|
712
|
+
}
|
|
713
|
+
function resolveSetupChannelForConnector(connector) {
|
|
714
|
+
for (const channel of SETUP_CHANNEL_ORDER) {
|
|
715
|
+
if (CHANNEL_SPECS[channel].matchesConfiguredConnector(connector)) {
|
|
716
|
+
return channel;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return null;
|
|
720
|
+
}
|
|
721
|
+
//# sourceMappingURL=channels.js.map
|