@vellumai/assistant 0.4.48 → 0.4.49
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/ARCHITECTURE.md +2 -2
- package/README.md +2 -23
- package/docs/architecture/integrations.md +45 -41
- package/docs/architecture/keychain-broker.md +3 -3
- package/docs/runbook-trusted-contacts.md +3 -8
- package/hook-templates/debug-prompt-logger/hook.json +1 -1
- package/hook-templates/debug-prompt-logger/run.sh +1 -3
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +0 -1
- package/src/__tests__/anthropic-provider.test.ts +156 -0
- package/src/__tests__/approval-cascade.test.ts +810 -0
- package/src/__tests__/approval-primitive.test.ts +0 -1
- package/src/__tests__/approval-routes-http.test.ts +2 -0
- package/src/__tests__/assistant-attachments.test.ts +12 -34
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +76 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -1
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/channel-guardian.test.ts +0 -2
- package/src/__tests__/channel-readiness-routes.test.ts +15 -6
- package/src/__tests__/channel-readiness-service.test.ts +10 -9
- package/src/__tests__/checker.test.ts +9 -29
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-tools.test.ts +2 -19
- package/src/__tests__/config-watcher.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/context-image-dimensions.test.ts +332 -0
- package/src/__tests__/context-token-estimator.test.ts +196 -13
- package/src/__tests__/conversation-attention-store.test.ts +0 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +144 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/credential-metadata-store.test.ts +64 -73
- package/src/__tests__/credential-security-invariants.test.ts +13 -7
- package/src/__tests__/credential-vault-unit.test.ts +280 -49
- package/src/__tests__/credential-vault.test.ts +138 -16
- package/src/__tests__/credentials-cli.test.ts +71 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/ephemeral-permissions.test.ts +3 -3
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +0 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -39
- package/src/__tests__/heartbeat-service.test.ts +0 -1
- package/src/__tests__/host-cu-proxy.test.ts +629 -0
- package/src/__tests__/host-shell-tool.test.ts +27 -15
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/ingress-url-consistency.test.ts +14 -21
- package/src/__tests__/integration-status.test.ts +32 -51
- package/src/__tests__/intent-routing.test.ts +0 -1
- package/src/__tests__/invite-routes-http.test.ts +10 -9
- package/src/__tests__/keychain-broker-client.test.ts +11 -43
- package/src/__tests__/notification-routing-intent.test.ts +0 -1
- package/src/__tests__/oauth-cli.test.ts +373 -14
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -9
- package/src/__tests__/oauth-scope-policy.test.ts +4 -6
- package/src/__tests__/oauth-store.test.ts +756 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
- package/src/__tests__/provider-error-scenarios.test.ts +0 -1
- package/src/__tests__/provider-streaming.benchmark.test.ts +0 -1
- package/src/__tests__/public-ingress-urls.test.ts +15 -21
- package/src/__tests__/recording-handler.test.ts +3 -4
- package/src/__tests__/registry.test.ts +2 -2
- package/src/__tests__/runtime-events-sse.test.ts +55 -7
- package/src/__tests__/schedule-store.test.ts +0 -1
- package/src/__tests__/scheduler-recurrence.test.ts +0 -1
- package/src/__tests__/scoped-approval-grants.test.ts +0 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
- package/src/__tests__/secret-ingress-handler.test.ts +0 -1
- package/src/__tests__/send-endpoint-busy.test.ts +21 -6
- package/src/__tests__/sequence-store.test.ts +0 -1
- package/src/__tests__/session-init.benchmark.test.ts +4 -5
- package/src/__tests__/skill-include-graph.test.ts +66 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +0 -1
- package/src/__tests__/skill-load-tool.test.ts +149 -1
- package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
- package/src/__tests__/skills-uninstall.test.ts +1 -1
- package/src/__tests__/skills.test.ts +3 -3
- package/src/__tests__/slack-channel-config.test.ts +67 -3
- package/src/__tests__/slack-share-routes.test.ts +17 -19
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/telegram-invite-adapter.test.ts +18 -22
- package/src/__tests__/terminal-tools.test.ts +4 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/tool-approval-handler.test.ts +0 -1
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor-shell-integration.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
- package/src/__tests__/trust-store-pattern-matches.test.ts +29 -0
- package/src/__tests__/trust-store.test.ts +1 -22
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
- package/src/__tests__/twilio-routes.test.ts +0 -16
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
- package/src/agent/ax-tree-compaction.test.ts +235 -0
- package/src/agent/loop.ts +76 -130
- package/src/calls/call-domain.ts +1 -6
- package/src/calls/relay-server.ts +9 -13
- package/src/calls/twilio-config.ts +2 -7
- package/src/calls/twilio-routes.ts +1 -2
- package/src/calls/voice-ingress-preflight.ts +1 -1
- package/src/cli/commands/browser-relay.ts +18 -12
- package/src/cli/commands/completions.ts +0 -3
- package/src/cli/commands/credentials.ts +101 -15
- package/src/cli/commands/oauth/apps.ts +255 -0
- package/src/cli/commands/oauth/connections.ts +299 -0
- package/src/cli/commands/oauth/index.ts +52 -0
- package/src/cli/commands/oauth/providers.ts +242 -0
- package/src/cli/commands/skills.ts +4 -338
- package/src/cli/program.ts +1 -5
- package/src/cli/reference.ts +1 -3
- package/src/config/assistant-feature-flags.ts +0 -3
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +3 -6
- package/src/config/bundled-skills/computer-use/TOOLS.json +22 -4
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +21 -16
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -4
- package/src/config/bundled-skills/settings/SKILL.md +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +2 -8
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +5 -33
- package/src/config/env-registry.ts +14 -83
- package/src/config/env.ts +11 -50
- package/src/config/feature-flag-registry.json +16 -16
- package/src/config/loader.ts +0 -6
- package/src/config/schema.ts +3 -1
- package/src/config/skills.ts +21 -2
- package/src/context/image-dimensions.ts +229 -0
- package/src/context/token-estimator.ts +75 -12
- package/src/context/window-manager.ts +49 -10
- package/src/daemon/assistant-attachments.ts +1 -13
- package/src/daemon/handlers/config-ingress.ts +8 -33
- package/src/daemon/handlers/config-slack-channel.ts +49 -46
- package/src/daemon/handlers/config-telegram.ts +32 -16
- package/src/daemon/handlers/sessions.ts +10 -24
- package/src/daemon/handlers/shared.ts +0 -130
- package/src/daemon/host-cu-proxy.ts +401 -0
- package/src/daemon/lifecycle.ts +36 -68
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/computer-use.ts +2 -119
- package/src/daemon/message-types/host-cu.ts +19 -0
- package/src/daemon/message-types/messages.ts +3 -0
- package/src/daemon/server.ts +14 -21
- package/src/daemon/session-agent-loop-handlers.ts +2 -0
- package/src/daemon/session-attachments.ts +1 -2
- package/src/daemon/session-slash.ts +1 -1
- package/src/daemon/session-surfaces.ts +40 -28
- package/src/daemon/session-tool-setup.ts +2 -9
- package/src/daemon/session.ts +138 -15
- package/src/daemon/tool-side-effects.ts +2 -8
- package/src/daemon/watch-handler.ts +2 -2
- package/src/events/tool-metrics-listener.ts +2 -2
- package/src/hooks/manager.ts +1 -4
- package/src/inbound/public-ingress-urls.ts +7 -7
- package/src/logfire.ts +16 -5
- package/src/memory/conversation-key-store.ts +21 -0
- package/src/memory/db-init.ts +4 -0
- package/src/memory/migrations/149-oauth-tables.ts +60 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/oauth.ts +65 -0
- package/src/messaging/provider.ts +4 -4
- package/src/messaging/providers/gmail/client.ts +82 -2
- package/src/messaging/providers/gmail/people-client.ts +10 -10
- package/src/messaging/providers/telegram-bot/adapter.ts +17 -17
- package/src/messaging/providers/whatsapp/adapter.ts +11 -8
- package/src/messaging/registry.ts +2 -32
- package/src/notifications/copy-composer.ts +0 -5
- package/src/notifications/signal.ts +4 -5
- package/src/oauth/byo-connection.test.ts +126 -25
- package/src/oauth/byo-connection.ts +22 -6
- package/src/oauth/connect-orchestrator.ts +113 -57
- package/src/oauth/connect-types.ts +17 -23
- package/src/oauth/connection-resolver.ts +35 -11
- package/src/oauth/connection.ts +1 -1
- package/src/oauth/manual-token-connection.ts +104 -0
- package/src/oauth/oauth-store.ts +496 -0
- package/src/oauth/platform-connection.test.ts +29 -0
- package/src/oauth/platform-connection.ts +6 -5
- package/src/oauth/provider-behaviors.ts +124 -0
- package/src/oauth/scope-policy.ts +9 -2
- package/src/oauth/seed-providers.ts +161 -0
- package/src/oauth/token-persistence.ts +74 -78
- package/src/permissions/checker.ts +3 -3
- package/src/permissions/defaults.ts +0 -1
- package/src/permissions/prompter.ts +10 -1
- package/src/permissions/trust-store.ts +13 -0
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +3 -1
- package/src/prompts/system-prompt.ts +28 -40
- package/src/providers/anthropic/client.ts +133 -24
- package/src/providers/retry.ts +1 -27
- package/src/runtime/auth/route-policy.ts +0 -3
- package/src/runtime/channel-reply-delivery.ts +0 -40
- package/src/runtime/gateway-client.ts +0 -7
- package/src/runtime/http-server.ts +8 -6
- package/src/runtime/http-types.ts +2 -2
- package/src/runtime/middleware/twilio-validation.ts +1 -11
- package/src/runtime/pending-interactions.ts +14 -12
- package/src/runtime/routes/channel-delivery-routes.ts +0 -1
- package/src/runtime/routes/conversation-routes.ts +73 -19
- package/src/runtime/routes/events-routes.ts +21 -11
- package/src/runtime/routes/host-cu-routes.ts +97 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +12 -111
- package/src/runtime/routes/integrations/slack/share.ts +6 -7
- package/src/runtime/routes/log-export-routes.ts +126 -8
- package/src/runtime/routes/settings-routes.ts +55 -48
- package/src/runtime/routes/surface-action-routes.ts +1 -1
- package/src/runtime/routes/watch-routes.ts +128 -0
- package/src/schedule/integration-status.ts +10 -9
- package/src/security/credential-key.ts +0 -156
- package/src/security/keychain-broker-client.ts +5 -6
- package/src/security/oauth2.ts +1 -1
- package/src/security/token-manager.ts +119 -46
- package/src/skills/catalog-install.ts +358 -0
- package/src/skills/include-graph.ts +32 -0
- package/src/telegram/bot-username.ts +2 -3
- package/src/tools/browser/network-recorder.ts +1 -1
- package/src/tools/browser/network-recording-types.ts +1 -1
- package/src/tools/computer-use/definitions.ts +46 -11
- package/src/tools/computer-use/registry.ts +4 -5
- package/src/tools/credentials/broker.ts +1 -2
- package/src/tools/credentials/metadata-store.ts +17 -121
- package/src/tools/credentials/vault.ts +94 -167
- package/src/tools/registry.ts +2 -7
- package/src/tools/skills/load.ts +62 -3
- package/src/tools/watch/watch-state.ts +0 -12
- package/src/util/logger.ts +7 -41
- package/src/util/platform.ts +9 -28
- package/src/watcher/providers/google-calendar.ts +2 -1
- package/src/__tests__/computer-use-session-compaction.test.ts +0 -143
- package/src/__tests__/computer-use-session-lifecycle.test.ts +0 -322
- package/src/__tests__/computer-use-session-working-dir.test.ts +0 -166
- package/src/__tests__/computer-use-skill-baseline.test.ts +0 -78
- package/src/__tests__/computer-use-skill-endstate.test.ts +0 -105
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +0 -249
- package/src/__tests__/ride-shotgun-handler.test.ts +0 -452
- package/src/cli/commands/dev.ts +0 -129
- package/src/cli/commands/map.ts +0 -391
- package/src/cli/commands/oauth.ts +0 -77
- package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +0 -16
- package/src/daemon/computer-use-session.ts +0 -1026
- package/src/daemon/ride-shotgun-handler.ts +0 -569
- package/src/oauth/provider-base-urls.ts +0 -21
- package/src/oauth/provider-profiles.ts +0 -192
- package/src/prompts/computer-use-prompt.ts +0 -98
- package/src/runtime/routes/computer-use-routes.ts +0 -641
- package/src/runtime/telegram-streaming-delivery.test.ts +0 -729
- package/src/runtime/telegram-streaming-delivery.ts +0 -393
- package/src/tools/computer-use/request-computer-control.ts +0 -56
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { getConfig } from "../../config/loader.js";
|
|
2
2
|
import { orchestrateOAuthConnect } from "../../oauth/connect-orchestrator.js";
|
|
3
3
|
import {
|
|
4
|
-
|
|
4
|
+
disconnectOAuthProvider,
|
|
5
|
+
getAppByProviderAndClientId,
|
|
6
|
+
getMostRecentAppByProvider,
|
|
7
|
+
getProvider,
|
|
8
|
+
} from "../../oauth/oauth-store.js";
|
|
9
|
+
import {
|
|
10
|
+
getProviderBehavior,
|
|
5
11
|
resolveService,
|
|
6
12
|
SERVICE_ALIASES,
|
|
7
|
-
} from "../../oauth/provider-
|
|
13
|
+
} from "../../oauth/provider-behaviors.js";
|
|
8
14
|
import { RiskLevel } from "../../permissions/types.js";
|
|
9
15
|
import type { ToolDefinition } from "../../providers/types.js";
|
|
10
16
|
import { buildAssistantEvent } from "../../runtime/assistant-event.js";
|
|
11
17
|
import { assistantEventHub } from "../../runtime/assistant-event-hub.js";
|
|
12
18
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../../runtime/assistant-scope.js";
|
|
13
|
-
import { credentialKey
|
|
14
|
-
import type { TokenEndpointAuthMethod } from "../../security/oauth2.js";
|
|
19
|
+
import { credentialKey } from "../../security/credential-key.js";
|
|
15
20
|
import {
|
|
16
21
|
deleteSecureKeyAsync,
|
|
17
22
|
getSecureKey,
|
|
@@ -36,50 +41,6 @@ import { toPolicyFromInput, validatePolicyInput } from "./policy-validate.js";
|
|
|
36
41
|
|
|
37
42
|
const log = getLogger("credential-vault");
|
|
38
43
|
|
|
39
|
-
/**
|
|
40
|
-
* Look up a stored OAuth secret (e.g. client_secret) for a service from the
|
|
41
|
-
* secure store. Checks both the canonical and alias service names.
|
|
42
|
-
*/
|
|
43
|
-
function findStoredOAuthSecret(
|
|
44
|
-
service: string,
|
|
45
|
-
field: string,
|
|
46
|
-
): string | undefined {
|
|
47
|
-
const servicesToCheck = [service];
|
|
48
|
-
// Also check the alias if the input is the canonical name, or vice versa
|
|
49
|
-
for (const [alias, canonical] of Object.entries(SERVICE_ALIASES)) {
|
|
50
|
-
if (canonical === service) servicesToCheck.push(alias);
|
|
51
|
-
if (alias === service) servicesToCheck.push(canonical);
|
|
52
|
-
}
|
|
53
|
-
for (const svc of servicesToCheck) {
|
|
54
|
-
const value = getSecureKey(credentialKey(svc, field));
|
|
55
|
-
if (value) return value;
|
|
56
|
-
}
|
|
57
|
-
return undefined;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Look up the stored OAuth client_id for a service from credential metadata.
|
|
62
|
-
* Checks both the canonical and alias service names.
|
|
63
|
-
*/
|
|
64
|
-
function findStoredOAuthClientId(service: string): string | undefined {
|
|
65
|
-
const servicesToCheck = [service];
|
|
66
|
-
for (const [alias, canonical] of Object.entries(SERVICE_ALIASES)) {
|
|
67
|
-
if (canonical === service) servicesToCheck.push(alias);
|
|
68
|
-
if (alias === service) servicesToCheck.push(canonical);
|
|
69
|
-
}
|
|
70
|
-
// Check metadata first (written by oauth2_connect after successful auth)
|
|
71
|
-
for (const svc of servicesToCheck) {
|
|
72
|
-
const meta = getCredentialMetadata(svc, "access_token");
|
|
73
|
-
if (meta?.oauth2ClientId) return meta.oauth2ClientId;
|
|
74
|
-
}
|
|
75
|
-
// Fall back to secure key store (written by credential_store prompt action)
|
|
76
|
-
for (const svc of servicesToCheck) {
|
|
77
|
-
const value = getSecureKey(credentialKey(svc, "client_id"));
|
|
78
|
-
if (value) return value;
|
|
79
|
-
}
|
|
80
|
-
return undefined;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
44
|
class CredentialStoreTool implements Tool {
|
|
84
45
|
name = "credential_store";
|
|
85
46
|
description =
|
|
@@ -151,16 +112,6 @@ class CredentialStoreTool implements Tool {
|
|
|
151
112
|
description:
|
|
152
113
|
'Human-readable description of intended usage (for store/prompt actions), e.g. "GitHub login for pushing changes"',
|
|
153
114
|
},
|
|
154
|
-
auth_url: {
|
|
155
|
-
type: "string",
|
|
156
|
-
description:
|
|
157
|
-
"OAuth2 authorization endpoint (only for oauth2_connect action). Auto-filled for well-known services (gmail, slack).",
|
|
158
|
-
},
|
|
159
|
-
token_url: {
|
|
160
|
-
type: "string",
|
|
161
|
-
description:
|
|
162
|
-
"OAuth2 token endpoint (only for oauth2_connect action). Auto-filled for well-known services (gmail, slack).",
|
|
163
|
-
},
|
|
164
115
|
scopes: {
|
|
165
116
|
type: "array",
|
|
166
117
|
items: { type: "string" },
|
|
@@ -172,27 +123,11 @@ class CredentialStoreTool implements Tool {
|
|
|
172
123
|
description:
|
|
173
124
|
"OAuth2 client ID (only for oauth2_connect action). If omitted, looked up from previously stored credentials.",
|
|
174
125
|
},
|
|
175
|
-
extra_params: {
|
|
176
|
-
type: "object",
|
|
177
|
-
description:
|
|
178
|
-
"Extra query params for OAuth2 auth URL (only for oauth2_connect action)",
|
|
179
|
-
},
|
|
180
|
-
userinfo_url: {
|
|
181
|
-
type: "string",
|
|
182
|
-
description:
|
|
183
|
-
"Endpoint to fetch account info after OAuth2 auth (only for oauth2_connect action)",
|
|
184
|
-
},
|
|
185
126
|
client_secret: {
|
|
186
127
|
type: "string",
|
|
187
128
|
description:
|
|
188
129
|
"OAuth2 client secret for providers that require it (e.g. Google, Slack). If omitted, looked up from previously stored credentials; if still absent, PKCE-only is used (only for oauth2_connect action)",
|
|
189
130
|
},
|
|
190
|
-
token_endpoint_auth_method: {
|
|
191
|
-
type: "string",
|
|
192
|
-
enum: ["client_secret_basic", "client_secret_post"],
|
|
193
|
-
description:
|
|
194
|
-
'How to send client credentials at the token endpoint: "client_secret_post" (default, in POST body) or "client_secret_basic" (HTTP Basic Auth header). Only for oauth2_connect action.',
|
|
195
|
-
},
|
|
196
131
|
alias: {
|
|
197
132
|
type: "string",
|
|
198
133
|
description:
|
|
@@ -243,7 +178,6 @@ class CredentialStoreTool implements Tool {
|
|
|
243
178
|
input: Record<string, unknown>,
|
|
244
179
|
context: ToolContext,
|
|
245
180
|
): Promise<ToolExecutionResult> {
|
|
246
|
-
migrateKeys();
|
|
247
181
|
const action = input.action as string;
|
|
248
182
|
|
|
249
183
|
switch (action) {
|
|
@@ -517,6 +451,21 @@ class CredentialStoreTool implements Tool {
|
|
|
517
451
|
"metadata delete failed after removing credential",
|
|
518
452
|
);
|
|
519
453
|
}
|
|
454
|
+
// Also clean up any OAuth connection for this service (best-effort)
|
|
455
|
+
try {
|
|
456
|
+
const oauthResult = await disconnectOAuthProvider(service);
|
|
457
|
+
if (oauthResult === "error") {
|
|
458
|
+
log.warn(
|
|
459
|
+
{ service },
|
|
460
|
+
"OAuth disconnect failed after removing credential — secure key deletion error",
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
} catch (err) {
|
|
464
|
+
log.warn(
|
|
465
|
+
{ service, err },
|
|
466
|
+
"OAuth disconnect failed after removing credential",
|
|
467
|
+
);
|
|
468
|
+
}
|
|
520
469
|
return {
|
|
521
470
|
content: `Deleted credential for ${service}/${field}.`,
|
|
522
471
|
isError: false,
|
|
@@ -777,51 +726,44 @@ class CredentialStoreTool implements Tool {
|
|
|
777
726
|
// Resolve aliases (e.g. "gmail" → "integration:gmail")
|
|
778
727
|
const service = resolveService(rawService);
|
|
779
728
|
|
|
780
|
-
//
|
|
781
|
-
const
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
729
|
+
// Code-side behavioral fields (identityVerifier, setup, etc.)
|
|
730
|
+
const behavior = getProviderBehavior(service);
|
|
731
|
+
// Protocol-level config from the DB (authUrl, tokenUrl, scopes, etc.)
|
|
732
|
+
const providerRow = getProvider(service);
|
|
733
|
+
|
|
734
|
+
// Resolve client_id and client_secret.
|
|
735
|
+
// Priority:
|
|
736
|
+
// 1. Explicit input from the caller
|
|
737
|
+
// 2. oauth-store DB — when clientId is already known, look up the
|
|
738
|
+
// matching app so the secret comes from the same app. Only fall
|
|
739
|
+
// back to the most-recent-app heuristic when clientId is unknown.
|
|
740
|
+
let clientId = input.client_id as string | undefined;
|
|
741
|
+
let clientSecret = input.client_secret as string | undefined;
|
|
742
|
+
|
|
743
|
+
if (!clientId || !clientSecret) {
|
|
744
|
+
const dbApp = clientId
|
|
745
|
+
? getAppByProviderAndClientId(service, clientId)
|
|
746
|
+
: getMostRecentAppByProvider(service);
|
|
747
|
+
if (dbApp) {
|
|
748
|
+
if (!clientId) clientId = dbApp.clientId;
|
|
749
|
+
if (!clientSecret) {
|
|
750
|
+
clientSecret = getSecureKey(
|
|
751
|
+
`oauth_app/${dbApp.id}/client_secret`,
|
|
752
|
+
);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
790
756
|
|
|
791
757
|
// Early guardrails that stay in vault.ts (credential resolution is vault-specific)
|
|
792
758
|
const inputScopes = input.scopes as string[] | undefined;
|
|
793
759
|
|
|
794
|
-
if (
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
} else {
|
|
800
|
-
// Custom/unknown provider: require authUrl, tokenUrl, scopes from input
|
|
801
|
-
if (!input.auth_url)
|
|
802
|
-
return {
|
|
803
|
-
content:
|
|
804
|
-
"Error: auth_url is required for oauth2_connect action (no well-known config for this service)",
|
|
805
|
-
isError: true,
|
|
806
|
-
};
|
|
807
|
-
if (!input.token_url)
|
|
808
|
-
return {
|
|
809
|
-
content:
|
|
810
|
-
"Error: token_url is required for oauth2_connect action (no well-known config for this service)",
|
|
811
|
-
isError: true,
|
|
812
|
-
};
|
|
813
|
-
if (!inputScopes)
|
|
814
|
-
return {
|
|
815
|
-
content:
|
|
816
|
-
"Error: scopes is required for oauth2_connect action (no well-known config for this service)",
|
|
817
|
-
isError: true,
|
|
818
|
-
};
|
|
760
|
+
if (!providerRow) {
|
|
761
|
+
return {
|
|
762
|
+
content: `Error: no OAuth provider registered for "${service}". Ensure the provider is seeded in the database.`,
|
|
763
|
+
isError: true,
|
|
764
|
+
};
|
|
819
765
|
}
|
|
820
766
|
|
|
821
|
-
const authUrl =
|
|
822
|
-
(input.auth_url as string | undefined) ?? profile?.authUrl;
|
|
823
|
-
const tokenUrl =
|
|
824
|
-
(input.token_url as string | undefined) ?? profile?.tokenUrl;
|
|
825
767
|
if (!clientId)
|
|
826
768
|
return {
|
|
827
769
|
content:
|
|
@@ -833,10 +775,10 @@ class CredentialStoreTool implements Tool {
|
|
|
833
775
|
// agent to collect it from the user rather than letting it improvise
|
|
834
776
|
// browser-automation workarounds that inevitably fail.
|
|
835
777
|
const requiresSecret =
|
|
836
|
-
|
|
837
|
-
!!(
|
|
778
|
+
behavior?.setup?.requiresClientSecret ??
|
|
779
|
+
!!(providerRow.tokenEndpointAuthMethod || providerRow.extraParams);
|
|
838
780
|
if (requiresSecret && !clientSecret) {
|
|
839
|
-
const skillId =
|
|
781
|
+
const skillId = behavior?.setupSkillId;
|
|
840
782
|
const skillHint = skillId
|
|
841
783
|
? `\n\nLoad the "${skillId}" skill for provider-specific instructions on obtaining the client secret.`
|
|
842
784
|
: '\n\nUse credential_store with action "prompt" to securely collect the client_secret from the user before calling oauth2_connect again.';
|
|
@@ -846,25 +788,8 @@ class CredentialStoreTool implements Tool {
|
|
|
846
788
|
};
|
|
847
789
|
}
|
|
848
790
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
} catch {
|
|
852
|
-
return {
|
|
853
|
-
content:
|
|
854
|
-
"Error: credential metadata file has an unrecognized version; cannot store credentials",
|
|
855
|
-
isError: true,
|
|
856
|
-
};
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
const tokenEndpointAuthMethod =
|
|
860
|
-
(input.token_endpoint_auth_method as
|
|
861
|
-
| TokenEndpointAuthMethod
|
|
862
|
-
| undefined) ?? profile?.tokenEndpointAuthMethod;
|
|
863
|
-
|
|
864
|
-
// Delegate to the shared orchestrator.
|
|
865
|
-
// For profile-based providers, pass user scopes as requestedScopes so the
|
|
866
|
-
// scope policy engine (resolveScopes) is invoked. For custom providers,
|
|
867
|
-
// pass scopes directly as an explicit override.
|
|
791
|
+
// Delegate to the shared orchestrator — it resolves authUrl, tokenUrl,
|
|
792
|
+
// extraParams, userinfoUrl, and tokenEndpointAuthMethod from the DB.
|
|
868
793
|
const result = await orchestrateOAuthConnect({
|
|
869
794
|
service: rawService,
|
|
870
795
|
clientId,
|
|
@@ -872,24 +797,7 @@ class CredentialStoreTool implements Tool {
|
|
|
872
797
|
isInteractive: !!context.isInteractive,
|
|
873
798
|
sendToClient: context.sendToClient,
|
|
874
799
|
allowedTools: input.allowed_tools as string[] | undefined,
|
|
875
|
-
|
|
876
|
-
tokenUrl,
|
|
877
|
-
...(profile
|
|
878
|
-
? {
|
|
879
|
-
// Profile-based: let orchestrator resolve scopes via policy engine.
|
|
880
|
-
// Only pass requestedScopes if the user explicitly provided scopes.
|
|
881
|
-
...(inputScopes ? { requestedScopes: inputScopes } : {}),
|
|
882
|
-
}
|
|
883
|
-
: {
|
|
884
|
-
// Custom provider: explicit scopes override (bypasses policy engine)
|
|
885
|
-
scopes: inputScopes,
|
|
886
|
-
}),
|
|
887
|
-
extraParams:
|
|
888
|
-
(input.extra_params as Record<string, string> | undefined) ??
|
|
889
|
-
profile?.extraParams,
|
|
890
|
-
userinfoUrl:
|
|
891
|
-
(input.userinfo_url as string | undefined) ?? profile?.userinfoUrl,
|
|
892
|
-
tokenEndpointAuthMethod,
|
|
800
|
+
...(inputScopes ? { requestedScopes: inputScopes } : {}),
|
|
893
801
|
onDeferredComplete: (deferredResult) => {
|
|
894
802
|
// Emit oauth_connect_result to all connected SSE clients so the
|
|
895
803
|
// UI can update immediately when the deferred browser flow completes.
|
|
@@ -958,8 +866,8 @@ class CredentialStoreTool implements Tool {
|
|
|
958
866
|
};
|
|
959
867
|
}
|
|
960
868
|
const resolvedService = resolveService(rawService);
|
|
961
|
-
const
|
|
962
|
-
if (!
|
|
869
|
+
const descProviderRow = getProvider(resolvedService);
|
|
870
|
+
if (!descProviderRow) {
|
|
963
871
|
return {
|
|
964
872
|
content: `No well-known OAuth config found for "${rawService}". Available services: ${Object.keys(
|
|
965
873
|
SERVICE_ALIASES,
|
|
@@ -968,11 +876,17 @@ class CredentialStoreTool implements Tool {
|
|
|
968
876
|
};
|
|
969
877
|
}
|
|
970
878
|
|
|
879
|
+
const descBehavior = getProviderBehavior(resolvedService);
|
|
880
|
+
|
|
971
881
|
// Compute the redirect URI based on callback transport
|
|
972
882
|
let redirectUri: string;
|
|
973
|
-
const transport =
|
|
974
|
-
|
|
975
|
-
|
|
883
|
+
const transport =
|
|
884
|
+
(descProviderRow.callbackTransport as
|
|
885
|
+
| "loopback"
|
|
886
|
+
| "gateway"
|
|
887
|
+
| null) ?? "gateway";
|
|
888
|
+
if (transport === "loopback" && descProviderRow.loopbackPort) {
|
|
889
|
+
redirectUri = `http://127.0.0.1:${descProviderRow.loopbackPort}/oauth/callback`;
|
|
976
890
|
} else if (transport === "loopback") {
|
|
977
891
|
redirectUri =
|
|
978
892
|
"(automatic — no redirect URI needed, uses random localhost port)";
|
|
@@ -986,26 +900,39 @@ class CredentialStoreTool implements Tool {
|
|
|
986
900
|
redirectUri = `${baseUrl}/webhooks/oauth/callback`;
|
|
987
901
|
} catch {
|
|
988
902
|
redirectUri =
|
|
989
|
-
"(requires
|
|
903
|
+
"(requires ingress.publicBaseUrl — not currently configured)";
|
|
990
904
|
}
|
|
991
905
|
}
|
|
992
906
|
|
|
993
907
|
// Prefer explicit setup metadata, fall back to heuristic
|
|
994
908
|
const requiresClientSecret =
|
|
995
|
-
|
|
996
|
-
!!(
|
|
909
|
+
descBehavior?.setup?.requiresClientSecret ??
|
|
910
|
+
!!(
|
|
911
|
+
descProviderRow.tokenEndpointAuthMethod ||
|
|
912
|
+
descProviderRow.extraParams
|
|
913
|
+
);
|
|
914
|
+
|
|
915
|
+
const descDefaultScopes: string[] = descProviderRow.defaultScopes
|
|
916
|
+
? JSON.parse(descProviderRow.defaultScopes)
|
|
917
|
+
: [];
|
|
997
918
|
|
|
998
919
|
const info: Record<string, unknown> = {
|
|
999
920
|
service: resolvedService,
|
|
1000
|
-
authUrl:
|
|
1001
|
-
tokenUrl:
|
|
1002
|
-
scopes:
|
|
921
|
+
authUrl: descProviderRow.authUrl,
|
|
922
|
+
tokenUrl: descProviderRow.tokenUrl,
|
|
923
|
+
scopes: descDefaultScopes,
|
|
1003
924
|
callbackTransport: transport,
|
|
1004
925
|
redirectUri,
|
|
1005
926
|
requiresClientSecret,
|
|
1006
927
|
};
|
|
1007
|
-
if (
|
|
1008
|
-
if (
|
|
928
|
+
if (descBehavior?.setup) info.setup = descBehavior.setup;
|
|
929
|
+
if (descProviderRow.extraParams) {
|
|
930
|
+
try {
|
|
931
|
+
info.extraParams = JSON.parse(descProviderRow.extraParams);
|
|
932
|
+
} catch {
|
|
933
|
+
// Non-fatal
|
|
934
|
+
}
|
|
935
|
+
}
|
|
1009
936
|
|
|
1010
937
|
return { content: JSON.stringify(info, null, 2), isError: false };
|
|
1011
938
|
}
|
package/src/tools/registry.ts
CHANGED
|
@@ -4,7 +4,6 @@ import { getLogger } from "../util/logger.js";
|
|
|
4
4
|
import { coreAppProxyTools } from "./apps/definitions.js";
|
|
5
5
|
import { registerAppTools } from "./apps/registry.js";
|
|
6
6
|
import { allComputerUseTools } from "./computer-use/definitions.js";
|
|
7
|
-
import { requestComputerControlTool } from "./computer-use/request-computer-control.js";
|
|
8
7
|
import { hostFileEditTool } from "./host-filesystem/edit.js";
|
|
9
8
|
import { hostFileReadTool } from "./host-filesystem/read.js";
|
|
10
9
|
import { hostFileWriteTool } from "./host-filesystem/write.js";
|
|
@@ -300,8 +299,8 @@ export function getSkillRefCount(skillId: string): number {
|
|
|
300
299
|
}
|
|
301
300
|
|
|
302
301
|
export function getAllToolDefinitions(): ToolDefinition[] {
|
|
303
|
-
// Exclude proxy tools (e.g. computer_use_* tools) — they are
|
|
304
|
-
// by
|
|
302
|
+
// Exclude proxy tools (e.g. computer_use_* tools) — they are projected
|
|
303
|
+
// into sessions by the skill system, not via the global tool list.
|
|
305
304
|
// Exclude skill-origin tools — they are managed by the session-level
|
|
306
305
|
// skill projection system (projectSkillTools) and must not leak into
|
|
307
306
|
// the base tool list, which is shared across sessions via the global
|
|
@@ -341,9 +340,6 @@ export async function initializeTools(): Promise<void> {
|
|
|
341
340
|
registerTool(tool);
|
|
342
341
|
}
|
|
343
342
|
|
|
344
|
-
// The escalation tool is registered in core so text_qa sessions can execute it.
|
|
345
|
-
// The 12 action tools are provided by the bundled computer-use skill.
|
|
346
|
-
registerTool(requestComputerControlTool);
|
|
347
343
|
registerUiSurfaceTools();
|
|
348
344
|
registerAppTools();
|
|
349
345
|
|
|
@@ -367,7 +363,6 @@ export async function initializeTools(): Promise<void> {
|
|
|
367
363
|
...lazyTools.map((t: LazyToolDescriptor) => t.name),
|
|
368
364
|
...hostTools.map((t: Tool) => t.name),
|
|
369
365
|
...allComputerUseTools.map((t: Tool) => t.name),
|
|
370
|
-
requestComputerControlTool.name,
|
|
371
366
|
...allUiSurfaceTools.map((t: Tool) => t.name),
|
|
372
367
|
...coreAppProxyTools.map((t: Tool) => t.name),
|
|
373
368
|
]);
|
package/src/tools/skills/load.ts
CHANGED
|
@@ -8,7 +8,9 @@ import type { SkillSummary, SkillToolManifest } from "../../config/skills.js";
|
|
|
8
8
|
import { loadSkillBySelector, loadSkillCatalog } from "../../config/skills.js";
|
|
9
9
|
import { RiskLevel } from "../../permissions/types.js";
|
|
10
10
|
import type { ToolDefinition } from "../../providers/types.js";
|
|
11
|
+
import { autoInstallFromCatalog } from "../../skills/catalog-install.js";
|
|
11
12
|
import {
|
|
13
|
+
collectAllMissing,
|
|
12
14
|
indexCatalogById,
|
|
13
15
|
validateIncludes,
|
|
14
16
|
} from "../../skills/include-graph.js";
|
|
@@ -137,7 +139,32 @@ export class SkillLoadTool implements Tool {
|
|
|
137
139
|
};
|
|
138
140
|
}
|
|
139
141
|
|
|
140
|
-
|
|
142
|
+
let loaded = loadSkillBySelector(selector);
|
|
143
|
+
|
|
144
|
+
// Auto-install from catalog if the skill isn't found locally
|
|
145
|
+
if (
|
|
146
|
+
!loaded.skill &&
|
|
147
|
+
(loaded.errorCode === "not_found" || loaded.errorCode === "empty_catalog")
|
|
148
|
+
) {
|
|
149
|
+
try {
|
|
150
|
+
const installed = await autoInstallFromCatalog(selector);
|
|
151
|
+
if (installed) {
|
|
152
|
+
log.info({ skillId: selector }, "Auto-installed skill from catalog");
|
|
153
|
+
loaded = loadSkillBySelector(selector);
|
|
154
|
+
}
|
|
155
|
+
} catch (err) {
|
|
156
|
+
const installError = err instanceof Error ? err.message : String(err);
|
|
157
|
+
log.warn(
|
|
158
|
+
{ err, skillId: selector },
|
|
159
|
+
"Auto-install from catalog failed",
|
|
160
|
+
);
|
|
161
|
+
return {
|
|
162
|
+
content: `Error: skill "${selector}" was found in the catalog but installation failed: ${installError}`,
|
|
163
|
+
isError: true,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
141
168
|
if (!loaded.skill) {
|
|
142
169
|
return {
|
|
143
170
|
content: `Error: ${loaded.error ?? "Failed to load skill"}`,
|
|
@@ -160,10 +187,42 @@ export class SkillLoadTool implements Tool {
|
|
|
160
187
|
// Load catalog for include validation and child metadata output
|
|
161
188
|
let catalogIndex: Map<string, SkillSummary> | undefined;
|
|
162
189
|
if (skill.includes && skill.includes.length > 0) {
|
|
163
|
-
|
|
190
|
+
let catalog = loadSkillCatalog();
|
|
164
191
|
catalogIndex = indexCatalogById(catalog);
|
|
165
192
|
|
|
166
|
-
//
|
|
193
|
+
// Auto-install missing includes before validation (max 5 rounds for transitive deps)
|
|
194
|
+
const MAX_INSTALL_ROUNDS = 5;
|
|
195
|
+
for (let round = 0; round < MAX_INSTALL_ROUNDS; round++) {
|
|
196
|
+
const missing = collectAllMissing(skill.id, catalogIndex);
|
|
197
|
+
if (missing.size === 0) break;
|
|
198
|
+
|
|
199
|
+
let installedAny = false;
|
|
200
|
+
for (const missingId of missing) {
|
|
201
|
+
try {
|
|
202
|
+
const installed = await autoInstallFromCatalog(missingId);
|
|
203
|
+
if (installed) {
|
|
204
|
+
log.info(
|
|
205
|
+
{ skillId: missingId, parentSkillId: skill.id },
|
|
206
|
+
"Auto-installed missing include",
|
|
207
|
+
);
|
|
208
|
+
installedAny = true;
|
|
209
|
+
}
|
|
210
|
+
} catch (err) {
|
|
211
|
+
log.warn(
|
|
212
|
+
{ err, skillId: missingId },
|
|
213
|
+
"Failed to auto-install missing include",
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (!installedAny) break; // Nothing could be installed, stop trying
|
|
219
|
+
|
|
220
|
+
// Reload catalog to pick up newly installed skills
|
|
221
|
+
catalog = loadSkillCatalog();
|
|
222
|
+
catalogIndex = indexCatalogById(catalog);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Validate (fail-closed — catches genuinely missing deps + cycles)
|
|
167
226
|
const validation = validateIncludes(skill.id, catalogIndex);
|
|
168
227
|
if (!validation.ok) {
|
|
169
228
|
if (validation.error === "missing") {
|
|
@@ -24,18 +24,6 @@ export interface WatchSession {
|
|
|
24
24
|
timeoutHandle?: ReturnType<typeof setTimeout>;
|
|
25
25
|
/** Guards against concurrent generateSummary calls */
|
|
26
26
|
summaryInFlight?: boolean;
|
|
27
|
-
/** Whether this session was started via ride shotgun (no live commentary) */
|
|
28
|
-
isRideShotgun?: boolean;
|
|
29
|
-
/** Learn mode records network traffic alongside screen observations */
|
|
30
|
-
isLearnMode?: boolean;
|
|
31
|
-
/** Domain filter for network recording in learn mode */
|
|
32
|
-
targetDomain?: string;
|
|
33
|
-
/** Recording ID for learn mode sessions */
|
|
34
|
-
recordingId?: string;
|
|
35
|
-
/** Path where the learn recording was successfully saved (undefined if save failed) */
|
|
36
|
-
savedRecordingPath?: string;
|
|
37
|
-
/** Reason the learn-mode bootstrap failed (CDP launch vs recorder attach) */
|
|
38
|
-
bootstrapFailureReason?: string;
|
|
39
27
|
}
|
|
40
28
|
|
|
41
29
|
/** Module-level map of watch sessions keyed by watchId. */
|
package/src/util/logger.ts
CHANGED
|
@@ -12,11 +12,7 @@ import pino from "pino";
|
|
|
12
12
|
import type { PrettyOptions } from "pino-pretty";
|
|
13
13
|
import pinoPretty from "pino-pretty";
|
|
14
14
|
|
|
15
|
-
import {
|
|
16
|
-
getDebugMode,
|
|
17
|
-
getDebugStdoutLogs,
|
|
18
|
-
getLogStderr,
|
|
19
|
-
} from "../config/env-registry.js";
|
|
15
|
+
import { getDebugStdoutLogs } from "../config/env-registry.js";
|
|
20
16
|
import { logSerializers } from "./log-redact.js";
|
|
21
17
|
import { getLogPath } from "./platform.js";
|
|
22
18
|
|
|
@@ -110,31 +106,18 @@ function buildRotatingLogger(config: LogFileConfig): pino.Logger {
|
|
|
110
106
|
activeLogDate = today;
|
|
111
107
|
activeLogFileConfig = config;
|
|
112
108
|
|
|
113
|
-
const level = getDebugMode() ? "debug" : "info";
|
|
114
|
-
|
|
115
|
-
if (getDebugMode()) {
|
|
116
|
-
const prettyStream = pinoPretty(prettyOpts({ destination: 2 }));
|
|
117
|
-
return pino(
|
|
118
|
-
{ name: "assistant", level, serializers: logSerializers },
|
|
119
|
-
pino.multistream([
|
|
120
|
-
{ stream: fileStream, level: "info" as const },
|
|
121
|
-
{ stream: prettyStream, level: "debug" as const },
|
|
122
|
-
]),
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
109
|
// When stdout is not a TTY (e.g. desktop app redirects to a hatch log file),
|
|
127
110
|
// write to the rotating file only — the hatch log already captured early
|
|
128
111
|
// startup output and echoing pino output there is unnecessary duplication.
|
|
129
112
|
if (!process.stdout.isTTY) {
|
|
130
113
|
return pino(
|
|
131
|
-
{ name: "assistant", level, serializers: logSerializers },
|
|
114
|
+
{ name: "assistant", level: "info", serializers: logSerializers },
|
|
132
115
|
fileStream,
|
|
133
116
|
);
|
|
134
117
|
}
|
|
135
118
|
|
|
136
119
|
return pino(
|
|
137
|
-
{ name: "assistant", level, serializers: logSerializers },
|
|
120
|
+
{ name: "assistant", level: "info", serializers: logSerializers },
|
|
138
121
|
pino.multistream([
|
|
139
122
|
{ stream: fileStream, level: "info" as const },
|
|
140
123
|
{
|
|
@@ -173,13 +156,11 @@ function getRootLogger(): pino.Logger {
|
|
|
173
156
|
}
|
|
174
157
|
if (!rootLogger) {
|
|
175
158
|
const forceStderr =
|
|
176
|
-
process.env.BUN_TEST === "1" ||
|
|
177
|
-
process.env.NODE_ENV === "test" ||
|
|
178
|
-
getLogStderr();
|
|
159
|
+
process.env.BUN_TEST === "1" || process.env.NODE_ENV === "test";
|
|
179
160
|
if (forceStderr) {
|
|
180
161
|
rootLogger = pino(
|
|
181
162
|
{
|
|
182
|
-
level:
|
|
163
|
+
level: "info",
|
|
183
164
|
serializers: logSerializers,
|
|
184
165
|
},
|
|
185
166
|
pino.destination(2),
|
|
@@ -208,17 +189,7 @@ function getRootLogger(): pino.Logger {
|
|
|
208
189
|
prettyOpts({ destination: fileDest, colorize: false }),
|
|
209
190
|
);
|
|
210
191
|
|
|
211
|
-
if (
|
|
212
|
-
const prettyStream = pinoPretty(prettyOpts({ destination: 2 }));
|
|
213
|
-
const multi = pino.multistream([
|
|
214
|
-
{ stream: fileStream, level: "info" as const },
|
|
215
|
-
{ stream: prettyStream, level: "debug" as const },
|
|
216
|
-
]);
|
|
217
|
-
rootLogger = pino(
|
|
218
|
-
{ level: "debug", serializers: logSerializers },
|
|
219
|
-
multi,
|
|
220
|
-
);
|
|
221
|
-
} else if (getDebugStdoutLogs()) {
|
|
192
|
+
if (getDebugStdoutLogs()) {
|
|
222
193
|
rootLogger = pino(
|
|
223
194
|
{ level: "info", serializers: logSerializers },
|
|
224
195
|
pino.multistream([
|
|
@@ -238,7 +209,7 @@ function getRootLogger(): pino.Logger {
|
|
|
238
209
|
} catch {
|
|
239
210
|
rootLogger = pino(
|
|
240
211
|
{
|
|
241
|
-
level:
|
|
212
|
+
level: "info",
|
|
242
213
|
serializers: logSerializers,
|
|
243
214
|
},
|
|
244
215
|
pinoPretty(prettyOpts({ destination: 2 })),
|
|
@@ -248,11 +219,6 @@ function getRootLogger(): pino.Logger {
|
|
|
248
219
|
return rootLogger;
|
|
249
220
|
}
|
|
250
221
|
|
|
251
|
-
/** Returns true when VELLUM_DEBUG=1 is set. */
|
|
252
|
-
export function isDebug(): boolean {
|
|
253
|
-
return getDebugMode();
|
|
254
|
-
}
|
|
255
|
-
|
|
256
222
|
/**
|
|
257
223
|
* Truncate a string for debug logging. Returns the original if under maxLen,
|
|
258
224
|
* otherwise returns the first maxLen chars with a suffix indicating how much was cut.
|