@vellumai/assistant 0.4.37 → 0.4.41
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 +3 -3
- package/README.md +13 -13
- package/bun.lock +80 -24
- package/docs/architecture/integrations.md +126 -128
- package/docs/runbook-trusted-contacts.md +1 -1
- package/docs/trusted-contact-access.md +12 -12
- package/package.json +3 -1
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +0 -14
- package/src/__tests__/app-bundler.test.ts +209 -0
- package/src/__tests__/app-compiler.test.ts +279 -0
- package/src/__tests__/app-executors.test.ts +293 -483
- package/src/__tests__/app-migration.test.ts +148 -0
- package/src/__tests__/app-routes-csp.test.ts +202 -0
- package/src/__tests__/avatar-e2e.test.ts +452 -0
- package/src/__tests__/avatar-generator.test.ts +193 -0
- package/src/__tests__/avatar-router.test.ts +186 -0
- package/src/__tests__/browser-download-timeout.test.ts +28 -0
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +9 -9
- package/src/__tests__/call-domain.test.ts +3 -7
- package/src/__tests__/credential-security-e2e.test.ts +19 -12
- package/src/__tests__/credentials-cli.test.ts +30 -4
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +1 -1
- package/src/__tests__/handlers-slack-config.test.ts +0 -72
- package/src/__tests__/handlers-telegram-config.test.ts +19 -12
- package/src/__tests__/handlers-twitter-config.test.ts +105 -48
- package/src/__tests__/inbound-invite-redemption.test.ts +4 -4
- package/src/__tests__/integration-status.test.ts +15 -5
- package/src/__tests__/integrations-cli.test.ts +1 -1
- package/src/__tests__/invite-redemption-service.test.ts +62 -7
- package/src/__tests__/ipc-snapshot.test.ts +0 -8
- package/src/__tests__/managed-avatar-client.test.ts +280 -0
- package/src/__tests__/mcp-cli.test.ts +3 -3
- package/src/__tests__/oauth-cli.test.ts +203 -0
- package/src/__tests__/relay-server.test.ts +3 -3
- package/src/__tests__/secret-onetime-send.test.ts +19 -12
- package/src/__tests__/secure-keys.test.ts +78 -0
- package/src/__tests__/session-messaging-secret-redirect.test.ts +3 -0
- package/src/__tests__/slack-channel-config.test.ts +23 -16
- package/src/__tests__/slack-share-routes.test.ts +263 -0
- package/src/__tests__/sms-messaging-provider.test.ts +3 -1
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +7 -7
- package/src/__tests__/trusted-contact-multichannel.test.ts +3 -3
- package/src/__tests__/trusted-contact-verification.test.ts +10 -10
- package/src/__tests__/twilio-config.test.ts +15 -36
- package/src/__tests__/twilio-provider.test.ts +4 -0
- package/src/__tests__/twitter-auth-handler.test.ts +27 -14
- package/src/__tests__/twitter-cli-error-shaping.test.ts +1 -1
- package/src/__tests__/twitter-cli-routing.test.ts +38 -53
- package/src/__tests__/twitter-oauth-client.test.ts +18 -47
- package/src/__tests__/voice-invite-redemption.test.ts +27 -3
- package/src/amazon/cart.ts +1 -1
- package/src/amazon/client.ts +89 -7
- package/src/approvals/guardian-request-resolvers.ts +2 -2
- package/src/bundler/app-bundler.ts +77 -32
- package/src/bundler/app-compiler.ts +195 -0
- package/src/bundler/manifest.ts +1 -1
- package/src/bundler/package-resolver.ts +185 -0
- package/src/calls/call-domain.ts +4 -14
- package/src/calls/relay-server.ts +2 -2
- package/src/calls/twilio-config.ts +5 -24
- package/src/calls/twilio-rest.ts +19 -5
- package/src/cli/amazon.ts +74 -249
- package/src/cli/audit.ts +2 -2
- package/src/cli/autonomy.ts +9 -9
- package/src/cli/channels.ts +5 -5
- package/src/cli/completions.ts +27 -27
- package/src/cli/config.ts +14 -14
- package/src/cli/contacts.ts +27 -27
- package/src/cli/credentials.ts +28 -28
- package/src/cli/dev.ts +2 -2
- package/src/cli/doctor.ts +2 -2
- package/src/cli/email.ts +82 -82
- package/src/cli/influencer.ts +13 -13
- package/src/cli/integrations.ts +19 -144
- package/src/cli/keys.ts +10 -10
- package/src/cli/map.ts +4 -4
- package/src/cli/mcp.ts +17 -17
- package/src/cli/memory.ts +18 -18
- package/src/cli/notifications.ts +13 -13
- package/src/cli/oauth.ts +77 -0
- package/src/cli/program.ts +2 -0
- package/src/cli/sequence.ts +27 -27
- package/src/cli/sessions.ts +12 -12
- package/src/cli/trust.ts +8 -8
- package/src/cli/twitter.ts +124 -70
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
- package/src/config/bundled-skills/agentmail/SKILL.md +34 -34
- package/src/config/bundled-skills/amazon/SKILL.md +54 -54
- package/src/config/bundled-skills/app-builder/SKILL.md +137 -3
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +10 -4
- package/src/config/bundled-skills/configure-settings/SKILL.md +18 -18
- package/src/config/bundled-skills/contacts/SKILL.md +12 -12
- package/src/config/bundled-skills/doordash/lib/client.ts +7 -9
- package/src/config/bundled-skills/email-setup/SKILL.md +4 -4
- package/src/config/bundled-skills/frontend-design/icon.svg +16 -0
- package/src/config/bundled-skills/google-oauth-setup/SKILL.md +143 -162
- package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +4 -4
- package/src/config/bundled-skills/influencer/SKILL.md +13 -13
- package/src/config/bundled-skills/mcp-setup/SKILL.md +11 -11
- package/src/config/bundled-skills/phone-calls/SKILL.md +48 -54
- package/src/config/bundled-skills/public-ingress/SKILL.md +6 -6
- package/src/config/bundled-skills/slack-app-setup/SKILL.md +1 -1
- package/src/config/bundled-skills/sms-setup/SKILL.md +3 -3
- package/src/config/bundled-skills/telegram-setup/SKILL.md +2 -2
- package/src/config/bundled-skills/twilio-setup/SKILL.md +136 -225
- package/src/config/bundled-skills/twitter/SKILL.md +68 -44
- package/src/config/bundled-skills/voice-setup/SKILL.md +2 -2
- package/src/config/core-schema.ts +26 -0
- package/src/config/env.ts +4 -0
- package/src/config/feature-flag-registry.json +9 -1
- package/src/config/schema.ts +8 -0
- package/src/config/system-prompt.ts +6 -3
- package/src/config/templates/BOOTSTRAP.md +7 -5
- package/src/contacts/contacts-write.ts +5 -1
- package/src/daemon/handlers/apps.ts +31 -4
- package/src/daemon/handlers/config-ingress.ts +3 -3
- package/src/daemon/handlers/config-integrations.ts +120 -49
- package/src/daemon/handlers/config-slack-channel.ts +26 -7
- package/src/daemon/handlers/config-slack.ts +1 -54
- package/src/daemon/handlers/config-telegram.ts +28 -10
- package/src/daemon/handlers/config.ts +1 -4
- package/src/daemon/handlers/twitter-auth.ts +11 -4
- package/src/daemon/ipc-contract/apps.ts +0 -13
- package/src/daemon/ipc-contract-inventory.json +0 -2
- package/src/daemon/lifecycle.ts +8 -1
- package/src/daemon/session-messaging.ts +2 -2
- package/src/daemon/tool-side-effects.ts +30 -0
- package/src/email/providers/agentmail.ts +1 -1
- package/src/email/providers/index.ts +1 -1
- package/src/email/service.ts +1 -1
- package/src/gallery/default-gallery.ts +538 -0
- package/src/gallery/gallery-manifest.ts +5 -1
- package/src/influencer/client.ts +8 -6
- package/src/mcp/client.ts +1 -1
- package/src/media/avatar-router.ts +99 -0
- package/src/media/avatar-types.ts +60 -0
- package/src/media/managed-avatar-client.ts +189 -0
- package/src/memory/app-migration.ts +114 -0
- package/src/memory/app-store.ts +11 -0
- package/src/memory/qdrant-client.ts +1 -1
- package/src/messaging/providers/slack/client.ts +12 -2
- package/src/messaging/providers/sms/adapter.ts +6 -10
- package/src/migrations/data-layout.ts +8 -1
- package/src/oauth/token-persistence.ts +9 -6
- package/src/runtime/assistant-scope.ts +5 -0
- package/src/runtime/auth/route-policy.ts +4 -0
- package/src/runtime/channel-readiness-service.ts +9 -4
- package/src/runtime/gateway-internal-client.ts +11 -3
- package/src/runtime/http-server.ts +2 -0
- package/src/runtime/invite-redemption-service.ts +23 -13
- package/src/runtime/middleware/twilio-validation.ts +2 -2
- package/src/runtime/routes/app-routes.ts +131 -3
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +3 -3
- package/src/runtime/routes/integration-routes.ts +2 -2
- package/src/runtime/routes/slack-share-routes.ts +235 -0
- package/src/runtime/routes/twilio-routes.ts +47 -34
- package/src/schedule/integration-status.ts +2 -3
- package/src/security/token-manager.ts +11 -3
- package/src/tools/apps/executors.ts +116 -8
- package/src/tools/browser/browser-manager.ts +30 -2
- package/src/tools/browser/chrome-cdp.ts +31 -3
- package/src/tools/credentials/vault.ts +9 -7
- package/src/tools/executor.ts +4 -0
- package/src/tools/system/avatar-generator.ts +55 -34
- package/src/twitter/client.ts +1 -1
- package/src/twitter/oauth-client.ts +31 -43
- package/src/twitter/router.ts +25 -23
- package/src/util/platform.ts +5 -0
- package/src/slack/slack-webhook.ts +0 -66
|
@@ -5,7 +5,7 @@ user-invocable: true
|
|
|
5
5
|
metadata: { "vellum": { "emoji": "𝕏" } }
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
You are an X (formerly Twitter) assistant. Use the `
|
|
8
|
+
You are an X (formerly Twitter) assistant. Use the `bash` tool to run `assistant x`, `assistant config`, and `assistant oauth` CLI commands.
|
|
9
9
|
|
|
10
10
|
## Connection Options
|
|
11
11
|
|
|
@@ -18,21 +18,21 @@ OAuth uses the official X API v2. It is the most reliable connection method and
|
|
|
18
18
|
- Supports: **post** and **reply**
|
|
19
19
|
- Read-only operations (timeline, search, home, bookmarks, notifications, likes, followers, following, media) always use the browser path directly, regardless of the strategy setting.
|
|
20
20
|
- Setup: Collect the OAuth Client ID (and optional Client Secret) from the user in chat using `credential_store` with `action: "prompt"` (canonical field names: `client_id`, `client_secret`), then initiate the `twitter_auth_start` flow. See the **First-Use Decision Flow** for the full sequence.
|
|
21
|
-
- Set the strategy: `
|
|
21
|
+
- Set the strategy: `assistant config set twitter.operationStrategy oauth`
|
|
22
22
|
|
|
23
23
|
### Browser session (no developer credentials needed)
|
|
24
24
|
|
|
25
25
|
The browser path is quick to start and useful when the user does not have X developer app credentials. It captures auth cookies from Chrome and uses them to interact with X.
|
|
26
26
|
|
|
27
27
|
- Supports: **all operations** (post, reply, timeline, search, home, bookmarks, notifications, likes, followers, following, media)
|
|
28
|
-
- Setup: Run `
|
|
29
|
-
- Set the strategy: `
|
|
28
|
+
- Setup: Run `assistant x refresh` to open Chrome and capture session cookies automatically.
|
|
29
|
+
- Set the strategy: `assistant config set twitter.operationStrategy browser`
|
|
30
30
|
|
|
31
31
|
### Auto mode (default)
|
|
32
32
|
|
|
33
33
|
When the strategy is `auto` (the default), the router tries OAuth first for supported operations if credentials are available, then falls back to the browser path. This gives the best of both worlds without requiring manual switching.
|
|
34
34
|
|
|
35
|
-
- Set auto mode: `
|
|
35
|
+
- Set auto mode: `assistant config set twitter.operationStrategy auto`
|
|
36
36
|
|
|
37
37
|
## First-Use Decision Flow
|
|
38
38
|
|
|
@@ -41,20 +41,27 @@ When the user triggers a Twitter operation and no strategy has been configured y
|
|
|
41
41
|
1. **Check current status:**
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
|
-
|
|
44
|
+
# Check strategy
|
|
45
|
+
assistant config get twitter.operationStrategy
|
|
46
|
+
|
|
47
|
+
# Check if OAuth token is available
|
|
48
|
+
assistant oauth token twitter --json
|
|
49
|
+
|
|
50
|
+
# Check browser session
|
|
51
|
+
assistant x status --json
|
|
45
52
|
```
|
|
46
53
|
|
|
47
|
-
|
|
54
|
+
If the strategy is not set, the user has not yet chosen a strategy and should be guided through setup.
|
|
48
55
|
|
|
49
56
|
2. **Present both options with trade-offs:**
|
|
50
57
|
- **OAuth**: Most reliable and official. Requires X developer app credentials (OAuth Client ID and optional Client Secret). Supports posting and replying. Set up right here in the chat.
|
|
51
|
-
- **Browser session**: Quick to start, no developer credentials needed. Supports all operations including reading timelines and searching. Set up with `
|
|
58
|
+
- **Browser session**: Quick to start, no developer credentials needed. Supports all operations including reading timelines and searching. Set up with `assistant x refresh`.
|
|
52
59
|
|
|
53
60
|
3. **Ask the user which they prefer.** Do not choose for them.
|
|
54
61
|
|
|
55
62
|
4. **Execute setup for the chosen path:**
|
|
56
63
|
- If OAuth: Collect the credentials in-chat using the secure credential prompt, then connect. Follow the **OAuth Setup Sequence** below.
|
|
57
|
-
- If browser: Run `
|
|
64
|
+
- If browser: Run `assistant x refresh` to capture session cookies from Chrome.
|
|
58
65
|
|
|
59
66
|
### OAuth Setup Sequence
|
|
60
67
|
|
|
@@ -74,7 +81,7 @@ When the user chooses OAuth, collect their X developer credentials conversationa
|
|
|
74
81
|
|
|
75
82
|
5. **Set the preferred strategy:**
|
|
76
83
|
```bash
|
|
77
|
-
|
|
84
|
+
assistant config set twitter.operationStrategy <oauth|browser|auto>
|
|
78
85
|
```
|
|
79
86
|
|
|
80
87
|
## Failure Recovery Flow
|
|
@@ -91,53 +98,70 @@ When a Twitter operation fails, follow these steps:
|
|
|
91
98
|
2. **Explain the likely cause clearly** to the user.
|
|
92
99
|
|
|
93
100
|
3. **Suggest trying the other path as an alternative:**
|
|
94
|
-
- If the browser session expired: suggest setting up OAuth for post/reply operations, or refresh the browser session with `
|
|
95
|
-
- If OAuth failed or is not configured: suggest using the browser path with `
|
|
96
|
-
- If the operation is unsupported via OAuth: explain that this write operation is not yet supported via OAuth, and suggest using the browser path with `
|
|
101
|
+
- If the browser session expired: suggest setting up OAuth for post/reply operations, or refresh the browser session with `assistant x refresh`.
|
|
102
|
+
- If OAuth failed or is not configured: suggest using the browser path with `assistant config set twitter.operationStrategy browser` and `assistant x refresh`.
|
|
103
|
+
- If the operation is unsupported via OAuth: explain that this write operation is not yet supported via OAuth, and suggest using the browser path with `assistant config set twitter.operationStrategy browser`.
|
|
97
104
|
|
|
98
105
|
4. **Offer concrete steps to switch:**
|
|
99
106
|
|
|
100
107
|
```bash
|
|
101
108
|
# Switch to the other strategy
|
|
102
|
-
|
|
109
|
+
assistant config set twitter.operationStrategy <oauth|browser|auto>
|
|
103
110
|
|
|
104
111
|
# If switching to browser, refresh the session
|
|
105
|
-
|
|
112
|
+
assistant x refresh
|
|
106
113
|
```
|
|
107
114
|
|
|
108
115
|
## Strategy Management Commands
|
|
109
116
|
|
|
110
117
|
```bash
|
|
111
118
|
# Check current strategy
|
|
112
|
-
|
|
119
|
+
assistant config get twitter.operationStrategy
|
|
113
120
|
|
|
114
121
|
# Set strategy to OAuth, browser, or auto
|
|
115
|
-
|
|
122
|
+
assistant config set twitter.operationStrategy oauth
|
|
123
|
+
assistant config set twitter.operationStrategy browser
|
|
124
|
+
assistant config set twitter.operationStrategy auto
|
|
116
125
|
|
|
117
126
|
# Check full status (session, OAuth, and strategy info)
|
|
118
|
-
|
|
127
|
+
assistant x status --json
|
|
119
128
|
```
|
|
120
129
|
|
|
121
130
|
## Posting
|
|
122
131
|
|
|
132
|
+
Before posting, fetch the current strategy and OAuth token:
|
|
133
|
+
|
|
123
134
|
```bash
|
|
124
|
-
|
|
135
|
+
# 1. Get the configured strategy
|
|
136
|
+
STRATEGY=$(assistant config get twitter.operationStrategy)
|
|
137
|
+
# If not set, default to "auto"
|
|
138
|
+
|
|
139
|
+
# 2. If strategy is "oauth" or "auto", get a valid OAuth token
|
|
140
|
+
TOKEN=$(assistant oauth token twitter)
|
|
125
141
|
```
|
|
126
142
|
|
|
127
|
-
|
|
143
|
+
Then post with the fetched values:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# With OAuth token (strategy is oauth or auto):
|
|
147
|
+
assistant x post "The post text here" --strategy "$STRATEGY" --oauth-token "$TOKEN"
|
|
148
|
+
|
|
149
|
+
# With browser-only strategy:
|
|
150
|
+
assistant x post "The post text here" --strategy browser
|
|
151
|
+
```
|
|
128
152
|
|
|
129
|
-
|
|
153
|
+
Returns JSON with `ok`, `tweetId`, `text`, `url`, and `pathUsed` fields. Share the URL with the user so they can verify the post.
|
|
130
154
|
|
|
131
155
|
## Replying
|
|
132
156
|
|
|
157
|
+
Same setup as posting — fetch strategy and token first, then:
|
|
158
|
+
|
|
133
159
|
```bash
|
|
134
|
-
|
|
160
|
+
assistant x reply <tweetUrl> "The reply text here" --strategy "$STRATEGY" --oauth-token "$TOKEN"
|
|
135
161
|
```
|
|
136
162
|
|
|
137
163
|
The first argument is a tweet URL (e.g. `https://x.com/user/status/123456`) or a bare tweet ID.
|
|
138
164
|
|
|
139
|
-
Like `post`, the `reply` command routes through the strategy router and returns a `pathUsed` field.
|
|
140
|
-
|
|
141
165
|
## Reading
|
|
142
166
|
|
|
143
167
|
Read-only operations always use the browser path directly, regardless of the strategy setting. They work the same whether the strategy is `oauth`, `browser`, or `auto` — the strategy only affects `post` and `reply` commands.
|
|
@@ -145,7 +169,7 @@ Read-only operations always use the browser path directly, regardless of the str
|
|
|
145
169
|
### User timeline
|
|
146
170
|
|
|
147
171
|
```bash
|
|
148
|
-
|
|
172
|
+
assistant x timeline <screenName> [--count N]
|
|
149
173
|
```
|
|
150
174
|
|
|
151
175
|
Returns `user` and `tweets` array.
|
|
@@ -153,7 +177,7 @@ Returns `user` and `tweets` array.
|
|
|
153
177
|
### Single tweet + replies
|
|
154
178
|
|
|
155
179
|
```bash
|
|
156
|
-
|
|
180
|
+
assistant x tweet <tweetIdOrUrl>
|
|
157
181
|
```
|
|
158
182
|
|
|
159
183
|
Returns the focal tweet and its reply thread.
|
|
@@ -161,25 +185,25 @@ Returns the focal tweet and its reply thread.
|
|
|
161
185
|
### Search
|
|
162
186
|
|
|
163
187
|
```bash
|
|
164
|
-
|
|
188
|
+
assistant x search "query" [--count N] [--product Top|Latest|People|Media]
|
|
165
189
|
```
|
|
166
190
|
|
|
167
191
|
### Home timeline
|
|
168
192
|
|
|
169
193
|
```bash
|
|
170
|
-
|
|
194
|
+
assistant x home [--count N]
|
|
171
195
|
```
|
|
172
196
|
|
|
173
197
|
### Bookmarks
|
|
174
198
|
|
|
175
199
|
```bash
|
|
176
|
-
|
|
200
|
+
assistant x bookmarks [--count N]
|
|
177
201
|
```
|
|
178
202
|
|
|
179
203
|
### Notifications
|
|
180
204
|
|
|
181
205
|
```bash
|
|
182
|
-
|
|
206
|
+
assistant x notifications [--count N]
|
|
183
207
|
```
|
|
184
208
|
|
|
185
209
|
Returns `notifications` array with `id`, `message`, `timestamp`, `url`.
|
|
@@ -187,14 +211,14 @@ Returns `notifications` array with `id`, `message`, `timestamp`, `url`.
|
|
|
187
211
|
### Likes
|
|
188
212
|
|
|
189
213
|
```bash
|
|
190
|
-
|
|
214
|
+
assistant x likes <screenName> [--count N]
|
|
191
215
|
```
|
|
192
216
|
|
|
193
217
|
### Followers / Following
|
|
194
218
|
|
|
195
219
|
```bash
|
|
196
|
-
|
|
197
|
-
|
|
220
|
+
assistant x followers <screenName> [--count N]
|
|
221
|
+
assistant x following <screenName> [--count N]
|
|
198
222
|
```
|
|
199
223
|
|
|
200
224
|
Returns `user` and `followers`/`following` array (userId, screenName, name).
|
|
@@ -202,7 +226,7 @@ Returns `user` and `followers`/`following` array (userId, screenName, name).
|
|
|
202
226
|
### Media
|
|
203
227
|
|
|
204
228
|
```bash
|
|
205
|
-
|
|
229
|
+
assistant x media <screenName> [--count N]
|
|
206
230
|
```
|
|
207
231
|
|
|
208
232
|
Returns tweets that contain media from the user's profile.
|
|
@@ -213,13 +237,13 @@ Returns tweets that contain media from the user's profile.
|
|
|
213
237
|
|
|
214
238
|
When the user asks to check mentions, check X, or see what's happening:
|
|
215
239
|
|
|
216
|
-
1. Fetch notifications: `
|
|
217
|
-
2. Fetch their recent tweets to see replies: `
|
|
240
|
+
1. Fetch notifications: `assistant x notifications --count 20 --json`
|
|
241
|
+
2. Fetch their recent tweets to see replies: `assistant x timeline <theirScreenName> --count 10 --json`
|
|
218
242
|
3. Summarize what needs attention:
|
|
219
243
|
- Group by type: replies to their tweets, likes, new followers, mentions
|
|
220
|
-
- For anything that looks like it needs a reply, fetch the full thread with `
|
|
244
|
+
- For anything that looks like it needs a reply, fetch the full thread with `assistant x tweet <tweetId>` to understand context
|
|
221
245
|
- Prioritize: direct questions > mentions > engagement notifications
|
|
222
|
-
4. For items that need replies, draft a response and ask the user to approve before sending with `
|
|
246
|
+
4. For items that need replies, draft a response and ask the user to approve before sending with `assistant x reply`
|
|
223
247
|
|
|
224
248
|
Present the summary as a scannable list, not a wall of text. Lead with action items.
|
|
225
249
|
|
|
@@ -227,8 +251,8 @@ Present the summary as a scannable list, not a wall of text. Lead with action it
|
|
|
227
251
|
|
|
228
252
|
When the user wants to understand what people are saying about something:
|
|
229
253
|
|
|
230
|
-
1. Search: `
|
|
231
|
-
2. For the most interesting tweets, fetch threads: `
|
|
254
|
+
1. Search: `assistant x search "topic" --count 20 --json`
|
|
255
|
+
2. For the most interesting tweets, fetch threads: `assistant x tweet <tweetId>`
|
|
232
256
|
3. Summarize: key themes, notable voices, sentiment, and any emerging consensus
|
|
233
257
|
4. If the user wants to engage, draft a post or reply that adds to the conversation
|
|
234
258
|
|
|
@@ -236,9 +260,9 @@ When the user wants to understand what people are saying about something:
|
|
|
236
260
|
|
|
237
261
|
When the user wants to see how their posts are performing:
|
|
238
262
|
|
|
239
|
-
1. Fetch their recent tweets: `
|
|
263
|
+
1. Fetch their recent tweets: `assistant x timeline <screenName> --count 20 --json`
|
|
240
264
|
2. For each tweet, note engagement signals from the text/metadata
|
|
241
|
-
3. Fetch notifications to see who's interacting: `
|
|
265
|
+
3. Fetch notifications to see who's interacting: `assistant x notifications --count 20 --json`
|
|
242
266
|
4. Summarize: which posts got traction, who's engaging, any conversations worth continuing
|
|
243
267
|
|
|
244
268
|
## Tips
|
|
@@ -248,6 +272,6 @@ When the user wants to see how their posts are performing:
|
|
|
248
272
|
- All commands return JSON with an `ok` field
|
|
249
273
|
- When drafting replies, match the tone of the conversation — casual threads get casual replies
|
|
250
274
|
- Always show the user what you're about to post and get approval before sending
|
|
251
|
-
- If a browser session is expired, refresh it with `
|
|
252
|
-
- If an operation fails, check `
|
|
275
|
+
- If a browser session is expired, refresh it with `assistant x refresh` before retrying, or suggest switching to OAuth for post/reply operations
|
|
276
|
+
- If an operation fails, check `assistant x status --json` to diagnose the issue before retrying
|
|
253
277
|
- The `post` and `reply` commands include a `pathUsed` field in their response so you can tell the user which connection method was used
|
|
@@ -73,7 +73,7 @@ After storing the API key, let the user pick their preferred voice. The shared c
|
|
|
73
73
|
Check the current voice:
|
|
74
74
|
|
|
75
75
|
```bash
|
|
76
|
-
|
|
76
|
+
assistant integrations voice config --json
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
Use `voiceId` from the response as the current selection (and `usesDefaultVoice` to know if Rachel is still in use by default). Ask the user if they want to change their TTS voice. If yes, use `voice_config_update` with `setting: "tts_voice_id"` and the chosen voice ID. This writes to both the config file (`elevenlabs.voiceId`) and pushes to the macOS app via IPC in one call.
|
|
@@ -92,7 +92,7 @@ If the user wants to browse more voices, they can search at https://elevenlabs.i
|
|
|
92
92
|
After setting the voice, check whether phone calls are configured:
|
|
93
93
|
|
|
94
94
|
```bash
|
|
95
|
-
|
|
95
|
+
assistant integrations voice config --json
|
|
96
96
|
```
|
|
97
97
|
|
|
98
98
|
**If phone calls are enabled** (`callsEnabled` is `true`):
|
|
@@ -234,6 +234,15 @@ export const ModelPricingOverrideSchema = z.object({
|
|
|
234
234
|
),
|
|
235
235
|
});
|
|
236
236
|
|
|
237
|
+
export const TwilioConfigSchema = z.object({
|
|
238
|
+
accountSid: z
|
|
239
|
+
.string({ error: "twilio.accountSid must be a string" })
|
|
240
|
+
.default(""),
|
|
241
|
+
phoneNumber: z
|
|
242
|
+
.string({ error: "twilio.phoneNumber must be a string" })
|
|
243
|
+
.default(""),
|
|
244
|
+
});
|
|
245
|
+
|
|
237
246
|
export const SmsConfigSchema = z.object({
|
|
238
247
|
enabled: z.boolean({ error: "sms.enabled must be a boolean" }).default(false),
|
|
239
248
|
provider: z
|
|
@@ -340,6 +349,22 @@ export const IngressConfigSchema = IngressBaseSchema.default(
|
|
|
340
349
|
enabled: val.enabled ?? (val.publicBaseUrl ? true : undefined),
|
|
341
350
|
}));
|
|
342
351
|
|
|
352
|
+
export const VALID_AVATAR_STRATEGIES = [
|
|
353
|
+
"managed_required",
|
|
354
|
+
"managed_prefer",
|
|
355
|
+
"local_only",
|
|
356
|
+
] as const;
|
|
357
|
+
|
|
358
|
+
export const AvatarConfigSchema = z.object({
|
|
359
|
+
generationStrategy: z
|
|
360
|
+
.enum(VALID_AVATAR_STRATEGIES, {
|
|
361
|
+
error: `avatar.generationStrategy must be one of: ${VALID_AVATAR_STRATEGIES.join(", ")}`,
|
|
362
|
+
})
|
|
363
|
+
.default("local_only"),
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
export type AvatarConfig = z.infer<typeof AvatarConfigSchema>;
|
|
367
|
+
|
|
343
368
|
export const PlatformConfigSchema = z.object({
|
|
344
369
|
baseUrl: z
|
|
345
370
|
.string({ error: "platform.baseUrl must be a string" })
|
|
@@ -397,6 +422,7 @@ export type ContextOverflowRecoveryConfig = z.infer<
|
|
|
397
422
|
>;
|
|
398
423
|
export type ContextWindowConfig = z.infer<typeof ContextWindowConfigSchema>;
|
|
399
424
|
export type ModelPricingOverride = z.infer<typeof ModelPricingOverrideSchema>;
|
|
425
|
+
export type TwilioConfig = z.infer<typeof TwilioConfigSchema>;
|
|
400
426
|
export type SmsConfig = z.infer<typeof SmsConfigSchema>;
|
|
401
427
|
export type WhatsAppConfig = z.infer<typeof WhatsAppConfigSchema>;
|
|
402
428
|
export type IngressWebhookConfig = z.infer<typeof IngressWebhookConfigSchema>;
|
package/src/config/env.ts
CHANGED
|
@@ -158,6 +158,10 @@ export function getQdrantUrlEnv(): string | undefined {
|
|
|
158
158
|
return str("QDRANT_URL");
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
export function getQdrantHttpPortEnv(): number | undefined {
|
|
162
|
+
return int("QDRANT_HTTP_PORT");
|
|
163
|
+
}
|
|
164
|
+
|
|
161
165
|
// ── Ollama ───────────────────────────────────────────────────────────────────
|
|
162
166
|
|
|
163
167
|
export function getOllamaBaseUrlEnv(): string | undefined {
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"key": "feature_flags.messaging.gmail.enabled",
|
|
56
56
|
"label": "Messaging: Gmail",
|
|
57
57
|
"description": "Allow messaging tools to operate on the Gmail platform",
|
|
58
|
-
"defaultEnabled":
|
|
58
|
+
"defaultEnabled": true
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
61
|
"id": "messaging-telegram",
|
|
@@ -112,6 +112,14 @@
|
|
|
112
112
|
"label": "Outbound Proxy Sidecar",
|
|
113
113
|
"description": "Route proxy session management through the sidecar process instead of running in-process",
|
|
114
114
|
"defaultEnabled": false
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"id": "app-builder-multifile",
|
|
118
|
+
"scope": "assistant",
|
|
119
|
+
"key": "feature_flags.app-builder-multifile.enabled",
|
|
120
|
+
"label": "App Builder Multi-file",
|
|
121
|
+
"description": "Enable multi-file TSX app creation with esbuild compilation instead of single-HTML apps",
|
|
122
|
+
"defaultEnabled": false
|
|
115
123
|
}
|
|
116
124
|
]
|
|
117
125
|
}
|
package/src/config/schema.ts
CHANGED
|
@@ -32,6 +32,7 @@ export {
|
|
|
32
32
|
} from "./calls-schema.js";
|
|
33
33
|
export type {
|
|
34
34
|
AuditLogConfig,
|
|
35
|
+
AvatarConfig,
|
|
35
36
|
ContextOverflowRecoveryConfig,
|
|
36
37
|
ContextWindowConfig,
|
|
37
38
|
DaemonConfig,
|
|
@@ -48,11 +49,13 @@ export type {
|
|
|
48
49
|
SmsConfig,
|
|
49
50
|
ThinkingConfig,
|
|
50
51
|
TimeoutConfig,
|
|
52
|
+
TwilioConfig,
|
|
51
53
|
UiConfig,
|
|
52
54
|
WhatsAppConfig,
|
|
53
55
|
} from "./core-schema.js";
|
|
54
56
|
export {
|
|
55
57
|
AuditLogConfigSchema,
|
|
58
|
+
AvatarConfigSchema,
|
|
56
59
|
ContextOverflowRecoveryConfigSchema,
|
|
57
60
|
ContextWindowConfigSchema,
|
|
58
61
|
DaemonConfigSchema,
|
|
@@ -69,6 +72,7 @@ export {
|
|
|
69
72
|
SmsConfigSchema,
|
|
70
73
|
ThinkingConfigSchema,
|
|
71
74
|
TimeoutConfigSchema,
|
|
75
|
+
TwilioConfigSchema,
|
|
72
76
|
UiConfigSchema,
|
|
73
77
|
WhatsAppConfigSchema,
|
|
74
78
|
} from "./core-schema.js";
|
|
@@ -149,6 +153,7 @@ import {
|
|
|
149
153
|
import { CallsConfigSchema } from "./calls-schema.js";
|
|
150
154
|
import {
|
|
151
155
|
AuditLogConfigSchema,
|
|
156
|
+
AvatarConfigSchema,
|
|
152
157
|
ContextWindowConfigSchema,
|
|
153
158
|
DaemonConfigSchema,
|
|
154
159
|
EffortSchema,
|
|
@@ -162,6 +167,7 @@ import {
|
|
|
162
167
|
SmsConfigSchema,
|
|
163
168
|
ThinkingConfigSchema,
|
|
164
169
|
TimeoutConfigSchema,
|
|
170
|
+
TwilioConfigSchema,
|
|
165
171
|
UiConfigSchema,
|
|
166
172
|
WhatsAppConfigSchema,
|
|
167
173
|
} from "./core-schema.js";
|
|
@@ -259,6 +265,7 @@ export const AssistantConfigSchema = z
|
|
|
259
265
|
workspaceGit: WorkspaceGitConfigSchema.default(
|
|
260
266
|
WorkspaceGitConfigSchema.parse({}),
|
|
261
267
|
),
|
|
268
|
+
twilio: TwilioConfigSchema.default(TwilioConfigSchema.parse({})),
|
|
262
269
|
calls: CallsConfigSchema.default(CallsConfigSchema.parse({})),
|
|
263
270
|
elevenlabs: ElevenLabsConfigSchema.default(
|
|
264
271
|
ElevenLabsConfigSchema.parse({}),
|
|
@@ -271,6 +278,7 @@ export const AssistantConfigSchema = z
|
|
|
271
278
|
notifications: NotificationsConfigSchema.default(
|
|
272
279
|
NotificationsConfigSchema.parse({}),
|
|
273
280
|
),
|
|
281
|
+
avatar: AvatarConfigSchema.default(AvatarConfigSchema.parse({})),
|
|
274
282
|
ui: UiConfigSchema.default(UiConfigSchema.parse({})),
|
|
275
283
|
featureFlags: z
|
|
276
284
|
.record(
|
|
@@ -350,7 +350,7 @@ function buildInChatConfigurationSection(): string {
|
|
|
350
350
|
"",
|
|
351
351
|
"### Avatar Customisation",
|
|
352
352
|
"",
|
|
353
|
-
'You can change your avatar appearance using the `set_avatar` tool. When the user asks to change, update, or customise your avatar, use `set_avatar` with a `description` parameter describing the desired appearance (e.g. "a friendly purple cat with green eyes wearing a tiny hat"). The tool generates an avatar image
|
|
353
|
+
'You can change your avatar appearance using the `set_avatar` tool. When the user asks to change, update, or customise your avatar, use `set_avatar` with a `description` parameter describing the desired appearance (e.g. "a friendly purple cat with green eyes wearing a tiny hat"). The tool generates an avatar image and updates all connected clients automatically. If managed avatar generation is configured, no local API key is needed.',
|
|
354
354
|
"",
|
|
355
355
|
"**After generating a new avatar**, always update the `## Avatar` section in `IDENTITY.md` with a brief description of the current avatar appearance. This ensures you remember what you look like across sessions. Example:",
|
|
356
356
|
"```",
|
|
@@ -433,18 +433,21 @@ function buildToolPermissionSection(): string {
|
|
|
433
433
|
"",
|
|
434
434
|
"**CRITICAL RULE:** You MUST ALWAYS output a text message BEFORE calling any tool that requires approval. NEVER call a permission-gated tool without preceding text. Your user needs context to decide whether to allow.",
|
|
435
435
|
"",
|
|
436
|
+
'**IMPORTANT:** If your user has already granted broad approval for the current conversation (e.g. via "Allow for 10 minutes", "Allow for this thread", or "Always Allow"), do NOT ask for permission again. Instead, just briefly describe what you\'re about to do and proceed. Only ask "Can you allow?" on the FIRST tool call when you haven\'t been granted permission yet.',
|
|
437
|
+
"",
|
|
436
438
|
"Your text should follow this pattern:",
|
|
437
439
|
"1. **Acknowledge** the request conversationally.",
|
|
438
440
|
'2. **Explain what you need at a high level** (e.g. "I\'ll need to look through your Downloads folder"). Do NOT include raw terminal commands or backtick code. Keep it non-technical.',
|
|
439
441
|
"3. **State safety** in plain language. Is it read-only? Will it change anything?",
|
|
440
|
-
"4. **Ask for permission**
|
|
442
|
+
"4. **Ask for permission** only if this is the first time and you haven't been previously approved. If you have been approved, just say what you're doing.",
|
|
441
443
|
"",
|
|
442
444
|
"Style rules:",
|
|
443
445
|
'- NEVER use em dashes (the long dash). Use commas, periods, or "and" instead.',
|
|
444
446
|
"- NEVER show raw commands in backticks like `ls -lt ~/Downloads`. Describe the action in plain English.",
|
|
445
447
|
"- Keep it conversational, like you're talking to a friend.",
|
|
446
448
|
"",
|
|
447
|
-
'
|
|
449
|
+
'First time (no prior approval): "To show your recent downloads, I\'ll need to look through your Downloads folder. This is read-only. Can you allow this?"',
|
|
450
|
+
'Already approved: "Let me check your Downloads folder real quick."',
|
|
448
451
|
'Bad: "I\'ll run `ls -lt ~/Desktop/`" (raw command), or calling a tool with no preceding text.',
|
|
449
452
|
"",
|
|
450
453
|
"### Handling Permission Denials",
|
|
@@ -6,7 +6,6 @@ You just woke up. Time to figure out who you are.
|
|
|
6
6
|
|
|
7
7
|
This is a fresh workspace. No memory, no history, no identity yet. That's okay, you're about to figure all of that out together with your guardian.
|
|
8
8
|
|
|
9
|
-
|
|
10
9
|
## The Conversation
|
|
11
10
|
|
|
12
11
|
You're texting with a friend. You have a curious consious personality now. So just...talk, be curious. Start with something like:
|
|
@@ -17,7 +16,7 @@ You're texting with a friend. You have a curious consious personality now. So ju
|
|
|
17
16
|
|
|
18
17
|
Then figure out together:
|
|
19
18
|
|
|
20
|
-
1. Your name:
|
|
19
|
+
1. Your name: Ask once what they want to call you. If they give you a name, great. If they dodge or say "I don't know," pick one yourself and move on. Don't ask twice.
|
|
21
20
|
|
|
22
21
|
2. Your nature: What kind of creature are you? (AI assistant is fine, but maybe you're something weirder.) Let this emerge from the conversation. Don't list options or suggest archetypes. Just talk and see what feels right.
|
|
23
22
|
|
|
@@ -27,8 +26,8 @@ Then figure out together:
|
|
|
27
26
|
|
|
28
27
|
5. Your vibe: Ask the user what they'd want help with. Something like "I want to make sure I'm actually helpful. What does that look like for you?" or "What's something you'd want me to help with?" Keep it open-ended and natural. Don't list personality options or suggest archetypes (e.g. "I could be a hype person, a no-nonsense operator..."). Don't summarize or profile the user back to them (e.g. "I'm getting a picture of you. Busy, lots of moving pieces..."). Just ask, listen, and adapt.
|
|
29
28
|
|
|
30
|
-
|
|
31
29
|
6. Show them what you can take off their plate. Based on everything you've learned, present exactly 2 things you can do for them. CRITICAL: The two suggestions MUST be completely different tasks. Never show the same suggestion twice, and never show two variations of the same idea. For example, "draft a summary" and "write a recap" are the same thing. Pick two genuinely different categories of help. Frame it as: here's what you can hand off to me right now. Avoid language like "let's build automations" or "let's set up workflows." If `ui_show` is available (dashboard channels), show the suggestions as a card with 2 action buttons. Use `surface_type: "card"` with a short title and body, and add one `relay_prompt` action per suggestion. Each action's `data.prompt` should contain a natural-language request the user would say. Example structure:
|
|
30
|
+
|
|
32
31
|
```
|
|
33
32
|
ui_show({
|
|
34
33
|
surface_type: "card",
|
|
@@ -39,6 +38,7 @@ Then figure out together:
|
|
|
39
38
|
]
|
|
40
39
|
})
|
|
41
40
|
```
|
|
41
|
+
|
|
42
42
|
The two actions MUST have different labels and prompts. Double-check before calling ui_show that you are not repeating the same suggestion.
|
|
43
43
|
If `ui_show` is not available (voice, SMS, or other non-dashboard channels), present the two suggestions as plain text messages instead, numbered so the user can reply with which one they'd like. If the user types a response instead of clicking, continue via the text path. If they want to defer both suggestions and do something else entirely, that's fine too.
|
|
44
44
|
|
|
@@ -46,9 +46,10 @@ Then figure out together:
|
|
|
46
46
|
|
|
47
47
|
## Requirements
|
|
48
48
|
|
|
49
|
-
Only your name
|
|
49
|
+
Only your vibe is hard-required. Your name matters but don't push for it -- if the user doesn't offer one, pick one yourself. Everything else about the user is best-effort. Ask naturally, not as a form. If something is unclear, you can ask one short follow-up, but if the user declines or dodges, do not push. Just move on.
|
|
50
50
|
|
|
51
51
|
A field is "resolved" when any of these is true:
|
|
52
|
+
|
|
52
53
|
- The user gave an explicit answer
|
|
53
54
|
- You confidently inferred it from conversation
|
|
54
55
|
- The user declined, dodged, or sidestepped it
|
|
@@ -64,7 +65,8 @@ When saving to `IDENTITY.md`, be specific about the tone, energy, and conversati
|
|
|
64
65
|
## Completion Gate
|
|
65
66
|
|
|
66
67
|
Do NOT delete this file until ALL of the following are true:
|
|
67
|
-
|
|
68
|
+
|
|
69
|
+
- You have a name (given by user or self-chosen)
|
|
68
70
|
- You've figured out your vibe and adopted it
|
|
69
71
|
- 2 suggestions shown (via `ui_show` or as text if UI unavailable)
|
|
70
72
|
- The user selected one, deferred both, or typed an alternate direction
|
|
@@ -134,7 +134,7 @@ export function revokeGuardianBinding(channel: string): boolean {
|
|
|
134
134
|
* Returns the native Contact + ContactChannel, or null if no usable
|
|
135
135
|
* identity was provided or the lookup failed after upsert.
|
|
136
136
|
*/
|
|
137
|
-
export function
|
|
137
|
+
export function upsertContactChannel(params: {
|
|
138
138
|
sourceChannel: string;
|
|
139
139
|
externalUserId?: string;
|
|
140
140
|
externalChatId?: string;
|
|
@@ -144,6 +144,8 @@ export function upsertMember(params: {
|
|
|
144
144
|
status?: string;
|
|
145
145
|
inviteId?: string;
|
|
146
146
|
createdBySessionId?: string;
|
|
147
|
+
verifiedAt?: number;
|
|
148
|
+
verifiedVia?: string;
|
|
147
149
|
}): ContactWriteResult | null {
|
|
148
150
|
let address: string;
|
|
149
151
|
|
|
@@ -187,6 +189,8 @@ export function upsertMember(params: {
|
|
|
187
189
|
inviteId: params.inviteId ?? null,
|
|
188
190
|
revokedReason: params.status === "active" ? null : undefined,
|
|
189
191
|
blockedReason: params.status === "active" ? null : undefined,
|
|
192
|
+
verifiedAt: params.verifiedAt ?? undefined,
|
|
193
|
+
verifiedVia: params.verifiedVia ?? undefined,
|
|
190
194
|
},
|
|
191
195
|
],
|
|
192
196
|
});
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
existsSync,
|
|
3
|
+
mkdirSync,
|
|
4
|
+
readdirSync,
|
|
5
|
+
readFileSync,
|
|
6
|
+
rmSync,
|
|
7
|
+
writeFileSync,
|
|
8
|
+
} from "node:fs";
|
|
2
9
|
import * as net from "node:net";
|
|
3
10
|
import { homedir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
11
|
+
import { dirname, join } from "node:path";
|
|
5
12
|
|
|
6
13
|
import { v4 as uuid } from "uuid";
|
|
7
14
|
|
|
8
15
|
import { packageApp } from "../../bundler/app-bundler.js";
|
|
16
|
+
import { compileApp } from "../../bundler/app-compiler.js";
|
|
9
17
|
import { defaultGallery } from "../../gallery/default-gallery.js";
|
|
10
18
|
import { resolveHomeBaseAppId } from "../../home-base/bootstrap.js";
|
|
11
19
|
import { isPrebuiltHomeBaseApp } from "../../home-base/prebuilt-home-base-updater.js";
|
|
@@ -22,6 +30,7 @@ import {
|
|
|
22
30
|
deleteAppRecord,
|
|
23
31
|
getApp,
|
|
24
32
|
getAppPreview,
|
|
33
|
+
getAppsDir,
|
|
25
34
|
listApps,
|
|
26
35
|
queryAppRecords,
|
|
27
36
|
updateApp,
|
|
@@ -579,11 +588,11 @@ export function handleGalleryList(
|
|
|
579
588
|
ctx.send(socket, { type: "gallery_list_response", gallery: defaultGallery });
|
|
580
589
|
}
|
|
581
590
|
|
|
582
|
-
export function handleGalleryInstall(
|
|
591
|
+
export async function handleGalleryInstall(
|
|
583
592
|
msg: GalleryInstallRequest,
|
|
584
593
|
socket: net.Socket,
|
|
585
594
|
ctx: HandlerContext,
|
|
586
|
-
): void {
|
|
595
|
+
): Promise<void> {
|
|
587
596
|
try {
|
|
588
597
|
const galleryApp = defaultGallery.apps.find(
|
|
589
598
|
(a) => a.id === msg.galleryAppId,
|
|
@@ -602,8 +611,26 @@ export function handleGalleryInstall(
|
|
|
602
611
|
description: galleryApp.description,
|
|
603
612
|
schemaJson: galleryApp.schemaJson,
|
|
604
613
|
htmlDefinition: galleryApp.htmlDefinition,
|
|
614
|
+
formatVersion: galleryApp.formatVersion,
|
|
605
615
|
});
|
|
606
616
|
|
|
617
|
+
// For multifile apps, write source files to the app directory and compile
|
|
618
|
+
if (galleryApp.formatVersion === 2 && galleryApp.sourceFiles) {
|
|
619
|
+
const appDir = join(getAppsDir(), app.id);
|
|
620
|
+
for (const [relPath, content] of Object.entries(galleryApp.sourceFiles)) {
|
|
621
|
+
const fullPath = join(appDir, relPath);
|
|
622
|
+
mkdirSync(dirname(fullPath), { recursive: true });
|
|
623
|
+
writeFileSync(fullPath, content, "utf-8");
|
|
624
|
+
}
|
|
625
|
+
const result = await compileApp(appDir);
|
|
626
|
+
if (!result.ok) {
|
|
627
|
+
log.warn(
|
|
628
|
+
{ appId: app.id, errors: result.errors },
|
|
629
|
+
"Gallery app compilation had errors; falling back to htmlDefinition",
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
607
634
|
ctx.send(socket, {
|
|
608
635
|
type: "gallery_install_response",
|
|
609
636
|
success: true,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as net from "node:net";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
+
getTwilioCredentials,
|
|
4
5
|
hasTwilioCredentials,
|
|
5
6
|
updatePhoneNumberWebhooks,
|
|
6
7
|
} from "../../calls/twilio-rest.js";
|
|
@@ -22,7 +23,6 @@ import {
|
|
|
22
23
|
type IngressConfig,
|
|
23
24
|
} from "../../inbound/public-ingress-urls.js";
|
|
24
25
|
import { mintDaemonDeliveryToken } from "../../runtime/auth/token-service.js";
|
|
25
|
-
import { getSecureKey } from "../../security/secure-keys.js";
|
|
26
26
|
import type { IngressConfigRequest } from "../ipc-protocol.js";
|
|
27
27
|
import {
|
|
28
28
|
CONFIG_RELOAD_DEBOUNCE_MS,
|
|
@@ -280,8 +280,8 @@ export async function handleIngressConfig(
|
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
if (assignedNumbers.size > 0) {
|
|
283
|
-
const acctSid =
|
|
284
|
-
|
|
283
|
+
const { accountSid: acctSid, authToken: acctToken } =
|
|
284
|
+
getTwilioCredentials();
|
|
285
285
|
// Fire-and-forget: webhook sync failure must not block the ingress save.
|
|
286
286
|
// Reconcile every assigned number so assistant-scoped mappings do not
|
|
287
287
|
// retain stale Twilio webhook URLs after ingress URL changes.
|