blink 1.1.19 → 1.1.21
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/dist/browser/agent/client/index.cjs +7 -7
- package/dist/browser/agent/client/index.js +6 -6
- package/dist/cli/{auth-CoJASYGP.js → auth-BilZuH-1.js} +2 -2
- package/dist/cli/{chat-BDAEIrJW.js → chat-CAtArOPl.js} +1 -1
- package/dist/cli/chat-manager-DfVg04yc.js +21 -0
- package/dist/cli/connect-DWScpJzS.js +1 -0
- package/dist/cli/create-slack-app-CyVPwWsG.js +1 -0
- package/dist/cli/{dev-BShY-dVP.js → dev-DRWR8F1H.js} +212 -176
- package/dist/cli/execAsync-Dwktgsum.js +1 -0
- package/dist/cli/execAsync-qNF4iDpO.js +1 -0
- package/dist/cli/{getMachineId-bsd-BQaAhwjO.js → getMachineId-bsd-0cOO_RKK.js} +1 -1
- package/dist/cli/{getMachineId-bsd-Cw8CWhxJ.js → getMachineId-bsd-BDrKPt3B.js} +1 -1
- package/dist/cli/{getMachineId-bsd-DcR5dlLj.js → getMachineId-bsd-BJ3yH7j4.js} +1 -1
- package/dist/{node/getMachineId-bsd-BxqlJcyA.js → cli/getMachineId-bsd-BpxYEV3F.js} +1 -1
- package/dist/cli/getMachineId-bsd-BrJwIGYU.js +1 -0
- package/dist/cli/getMachineId-bsd-C6osJ6-S.js +1 -0
- package/dist/cli/{getMachineId-bsd-CbeuYR7X.js → getMachineId-bsd-CHVQhSq2.js} +1 -1
- package/dist/cli/getMachineId-bsd-DeIJ5F9l.js +1 -0
- package/dist/cli/{getMachineId-darwin-D7CuR-jd.js → getMachineId-darwin-0AdOS_kz.js} +1 -1
- package/dist/cli/{getMachineId-darwin-DJ-H8l7s.js → getMachineId-darwin-BaA8JJgE.js} +1 -1
- package/dist/cli/{getMachineId-darwin-DYCKXuZX.js → getMachineId-darwin-BeAdNwpL.js} +1 -1
- package/dist/cli/{getMachineId-darwin-DyN_uugK.js → getMachineId-darwin-C8-xkmnZ.js} +1 -1
- package/dist/{node/getMachineId-darwin-Bf4P0U5b.js → cli/getMachineId-darwin-CJ2gOzlU.js} +1 -1
- package/dist/cli/getMachineId-darwin-CYvRIQbp.js +2 -0
- package/dist/cli/getMachineId-darwin-DWSKszGZ.js +2 -0
- package/dist/cli/getMachineId-darwin-wYLDmdQt.js +2 -0
- package/dist/cli/getMachineId-linux-D0cDy6Ik.js +1 -0
- package/dist/cli/getMachineId-linux-DgyKUIyK.js +1 -0
- package/dist/cli/getMachineId-linux-DnzutOBC.js +1 -0
- package/dist/cli/getMachineId-linux-nBO1QX9q.js +1 -0
- package/dist/cli/getMachineId-unsupported-DQBLgw4s.js +1 -0
- package/dist/cli/getMachineId-unsupported-DTFeADdG.js +1 -0
- package/dist/cli/getMachineId-unsupported-DgVzHx1H.js +1 -0
- package/dist/cli/getMachineId-unsupported-TE5qi9PD.js +1 -0
- package/dist/cli/{getMachineId-win-BB1s3SWz.js → getMachineId-win-4Psd7Tlr.js} +1 -1
- package/dist/cli/{getMachineId-win-BrQ4d5bO.js → getMachineId-win-BA0Li8oF.js} +1 -1
- package/dist/cli/{getMachineId-win-CgPYGelR.js → getMachineId-win-BvGLfEpq.js} +1 -1
- package/dist/cli/getMachineId-win-BzRwVWue.js +1 -0
- package/dist/cli/{getMachineId-win-B7f9VGFu.js → getMachineId-win-C4wjvjxC.js} +1 -1
- package/dist/cli/getMachineId-win-DXCyELQJ.js +1 -0
- package/dist/cli/getMachineId-win-hHwtD9GX.js +1 -0
- package/dist/cli/getMachineId-win-lhgCxX3y.js +1 -0
- package/dist/cli/index.js +8 -8
- package/dist/cli/init-BuMKmaaZ.js +23 -0
- package/dist/cli/{init-templates-MqyReSD9.js → init-templates-B9PG-9Ei.js} +257 -263
- package/dist/cli/login-Bbj133_1.js +1 -0
- package/dist/cli/{run-DFYLWiOa.js → run-DF1dwAY_.js} +1 -1
- package/dist/cli/setup-slack-app-DagQxNol.js +1 -0
- package/dist/cli/{token-DNRiDJM-.js → token-BdYp2nw_.js} +1 -1
- package/dist/cli/token-util-C9doIH9w.js +1 -0
- package/dist/cli/{token-util-IqDtKhK6.js → token-util-KdD-UX1l.js} +1 -1
- package/dist/cli/undici-Bm_EanIy.js +1 -0
- package/dist/cli/util-CUfifM0g.js +5 -0
- package/dist/cli/util-k3x8m_i5.js +33 -0
- package/dist/node/agent/index.node.cjs +1 -1
- package/dist/node/agent/index.node.d.cts +2 -2
- package/dist/node/agent/index.node.d.ts +2 -2
- package/dist/node/agent/index.node.js +1 -1
- package/dist/node/build/index.cjs +1 -1
- package/dist/node/build/index.d.cts +1 -1
- package/dist/node/build/index.d.ts +1 -1
- package/dist/node/build/index.js +1 -1
- package/dist/node/{build-D_L0gFGa.js → build-DYI55eX2.js} +1 -1
- package/dist/node/{build-BzoNpizh.cjs → build-EgdtUZTI.cjs} +1 -1
- package/dist/node/execAsync-CY8juV7n.js +1 -0
- package/dist/node/{getMachineId-bsd-C10eVJgT.js → getMachineId-bsd-Ckr9jSoT.js} +1 -1
- package/dist/node/{getMachineId-bsd-B84ixt26.cjs → getMachineId-bsd-O0bNSuuh.cjs} +1 -1
- package/dist/node/{getMachineId-darwin-JB29MQsG.js → getMachineId-darwin-36SFRv2R.js} +1 -1
- package/dist/node/{getMachineId-darwin-Cyng5kFG.cjs → getMachineId-darwin-DivkCgLG.cjs} +1 -1
- package/dist/node/{getMachineId-win-CjJkZMZe.cjs → getMachineId-win-B_okYUv6.cjs} +1 -1
- package/dist/node/{getMachineId-win-C4G-fkEF.js → getMachineId-win-CGqZ4f4O.js} +1 -1
- package/dist/node/{index-DlWgNLmT.d.cts → index-B4OXlWm3.d.ts} +1 -1
- package/dist/node/{index-C28Wm0bG.d.ts → index-DYOqnOdZ.d.cts} +1 -1
- package/dist/node/index.node-Bvp48I1R.cjs +50 -0
- package/dist/node/{index.node-B6plkLLA.d.cts → index.node-CFw4ITad.d.cts} +1 -21
- package/dist/node/{index.node-qJt_7e9E.d.ts → index.node-D5_czyKY.d.ts} +1 -21
- package/dist/node/index.node-ppzOWVGE.js +50 -0
- package/dist/node/react/index.node.cjs +354 -361
- package/dist/node/react/index.node.d.cts +2 -2
- package/dist/node/react/index.node.d.ts +2 -2
- package/dist/node/react/index.node.js +308 -315
- package/dist/node/{token-DOfE6QlD.js → token-CI2_C_5D.js} +1 -1
- package/dist/node/{token-BBGr-czK.cjs → token-D4jFpAk0.cjs} +1 -1
- package/dist/node/token-util-BENsR1Bn.cjs +1 -0
- package/dist/node/{token-util-C_uzN2q9.js → token-util-idU3T5iM.js} +1 -1
- package/package.json +20 -1
- package/dist/cli/chat-manager-BRchJngj.js +0 -21
- package/dist/cli/connect-WyCmuQHj.js +0 -1
- package/dist/cli/create-slack-app-CNDXDwfs.js +0 -1
- package/dist/cli/init-DoMgv4kU.js +0 -25
- package/dist/cli/login-DZFx5155.js +0 -1
- package/dist/cli/setup-slack-app-DQ3iSM5s.js +0 -1
- package/dist/cli/token-util-C6Xu44iO.js +0 -1
- package/dist/cli/undici-L5V8WBce.js +0 -1
- package/dist/cli/util-BQ3TH_Sv.js +0 -33
- package/dist/cli/util-BgbIWOFE.js +0 -6
- package/dist/node/execAsync-pJEPzmP4.cjs +0 -1
- package/dist/node/getMachineId-bsd-BudRe7J9.cjs +0 -1
- package/dist/node/getMachineId-darwin-ZVi3EKE3.cjs +0 -2
- package/dist/node/getMachineId-linux-CJXPQ8U5.cjs +0 -1
- package/dist/node/getMachineId-linux-CmMSYp7C.js +0 -1
- package/dist/node/getMachineId-unsupported-DM7fz1pP.cjs +0 -1
- package/dist/node/getMachineId-unsupported-Dtt3HTNZ.js +0 -1
- package/dist/node/getMachineId-win-D1szVnqR.js +0 -1
- package/dist/node/getMachineId-win-DDz2FyEp.cjs +0 -1
- package/dist/node/index.node-D7Cvmag9.cjs +0 -55
- package/dist/node/index.node-TFdiI8lm.js +0 -55
- package/dist/node/token-util-D9kCwzE6.cjs +0 -1
- /package/dist/cli/{connect-CQUVd44y.js → connect-BCK40kvG.js} +0 -0
- /package/dist/cli/{devtools-DvNholmW.js → devtools-DsAYEmyP.js} +0 -0
- /package/dist/cli/{execAsync-Bhq3YKvl.js → execAsync-BOPj9Mml.js} +0 -0
- /package/dist/cli/{execAsync-BnYBiViJ.js → execAsync-Bv4jTnD3.js} +0 -0
- /package/dist/cli/{execAsync-Djebuxfm.js → execAsync-CyP3Ojec.js} +0 -0
- /package/dist/cli/{execAsync-_tP2SNTy.js → execAsync-DHh3DKKp.js} +0 -0
- /package/dist/{node/execAsync-DzxhVi7q.js → cli/execAsync-DdLzES9n.js} +0 -0
- /package/dist/{node/execAsync-epR2wT1r.js → cli/execAsync-Dv6XOE2I.js} +0 -0
- /package/dist/cli/{getMachineId-linux-BCOAWAJr.js → getMachineId-linux-BQISLgy5.js} +0 -0
- /package/dist/cli/{getMachineId-linux-CBDQri3D.js → getMachineId-linux-Bg5YnekM.js} +0 -0
- /package/dist/cli/{getMachineId-linux-EqaaEzYC.js → getMachineId-linux-Boq-GGfA.js} +0 -0
- /package/dist/cli/{getMachineId-linux-QFNGh16E.js → getMachineId-linux-C9BHlxRm.js} +0 -0
- /package/dist/cli/{getMachineId-unsupported-BLalsIU8.js → getMachineId-unsupported-4qhSqb7w.js} +0 -0
- /package/dist/cli/{getMachineId-unsupported-CNgpP2gn.js → getMachineId-unsupported-BsEK_LG9.js} +0 -0
- /package/dist/cli/{getMachineId-unsupported-CQrnjCuH.js → getMachineId-unsupported-C6cVb167.js} +0 -0
- /package/dist/cli/{getMachineId-unsupported-CcRcqdy3.js → getMachineId-unsupported-CqJy0sqq.js} +0 -0
- /package/dist/cli/{token-error-DVSfBVaT.js → token-error-COQY18OP.js} +0 -0
- /package/dist/cli/{undici-BUZTy5qm.js → undici-CRntNDHY.js} +0 -0
- /package/dist/node/{execAsync-C9Unrkco.cjs → execAsync-BMxJf0Eg.cjs} +0 -0
- /package/dist/node/{getMachineId-linux-B-CtXK0L.cjs → getMachineId-linux-C8A0ak4z.cjs} +0 -0
- /package/dist/node/{getMachineId-linux-BPnkHJah.js → getMachineId-linux-ZoT5w75D.js} +0 -0
- /package/dist/node/{getMachineId-unsupported--0R36RP6.cjs → getMachineId-unsupported-DSRCXJha.cjs} +0 -0
- /package/dist/node/{getMachineId-unsupported-C_4fnT4Z.js → getMachineId-unsupported-XVp8oFCM.js} +0 -0
- /package/dist/node/{token-util-BOoyY0PX.cjs → token-util-BxSJFXkT.cjs} +0 -0
- /package/dist/node/{token-util-_pz5CtFI.js → token-util-ChGcRyiF.js} +0 -0
|
@@ -1,8 +1,22 @@
|
|
|
1
|
-
const e={scratch:{".
|
|
1
|
+
const e={scratch:{".env.local.hbs":`# Store local environment variables here.
|
|
2
|
+
# They will be used by blink dev for development.
|
|
3
|
+
{{#each envLocal}}
|
|
4
|
+
{{this.[0]}}={{this.[1]}}
|
|
5
|
+
{{/each}}
|
|
6
|
+
{{#unless (hasAnyEnvVar envLocal "OPENAI_API_KEY" "ANTHROPIC_API_KEY" "AI_GATEWAY_API_KEY")}}
|
|
7
|
+
# OPENAI_API_KEY=
|
|
8
|
+
# ANTHROPIC_API_KEY=
|
|
9
|
+
# AI_GATEWAY_API_KEY=
|
|
10
|
+
{{/unless}}`,".env.production":`# Store production environment variables here.
|
|
11
|
+
# They will be upserted as secrets on blink deploy.
|
|
12
|
+
# OPENAI_API_KEY=
|
|
13
|
+
# ANTHROPIC_API_KEY=
|
|
14
|
+
# AI_GATEWAY_API_KEY=
|
|
15
|
+
`,".gitignore":`# dependencies
|
|
2
16
|
node_modules
|
|
3
17
|
|
|
4
18
|
# config and build
|
|
5
|
-
|
|
19
|
+
.blink
|
|
6
20
|
|
|
7
21
|
# dotenv environment variables file
|
|
8
22
|
.env
|
|
@@ -10,103 +24,6 @@ data
|
|
|
10
24
|
|
|
11
25
|
# Finder (MacOS) folder config
|
|
12
26
|
.DS_Store
|
|
13
|
-
`,"tsconfig.json":`{
|
|
14
|
-
"compilerOptions": {
|
|
15
|
-
"lib": ["ESNext"],
|
|
16
|
-
"target": "ESNext",
|
|
17
|
-
"module": "Preserve",
|
|
18
|
-
"moduleDetection": "force",
|
|
19
|
-
|
|
20
|
-
"moduleResolution": "bundler",
|
|
21
|
-
"allowImportingTsExtensions": true,
|
|
22
|
-
"verbatimModuleSyntax": true,
|
|
23
|
-
"resolveJsonModule": true,
|
|
24
|
-
"noEmit": true,
|
|
25
|
-
|
|
26
|
-
"strict": true,
|
|
27
|
-
"skipLibCheck": true,
|
|
28
|
-
"noFallthroughCasesInSwitch": true,
|
|
29
|
-
"noUncheckedIndexedAccess": true,
|
|
30
|
-
"noImplicitOverride": true,
|
|
31
|
-
|
|
32
|
-
"noUnusedLocals": false,
|
|
33
|
-
"noUnusedParameters": false,
|
|
34
|
-
|
|
35
|
-
"types": ["node"]
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
`,".env.local":`
|
|
39
|
-
# Store local environment variables here.
|
|
40
|
-
# They will be used by blink dev for development.
|
|
41
|
-
# EXTERNAL_SERVICE_API_KEY=
|
|
42
|
-
`,".env.production":`# Store production environment variables here.
|
|
43
|
-
# They will be upserted as secrets on blink deploy.
|
|
44
|
-
# EXTERNAL_SERVICE_API_KEY=
|
|
45
|
-
`,"agent.ts.hbs":`import { convertToModelMessages, streamText, tool } from "ai";
|
|
46
|
-
import * as blink from "blink";
|
|
47
|
-
import { z } from "zod";
|
|
48
|
-
{{#if (eq aiProvider "anthropic")}}
|
|
49
|
-
import { anthropic } from "@ai-sdk/anthropic";
|
|
50
|
-
{{else if (eq aiProvider "openai")}}
|
|
51
|
-
import { openai } from "@ai-sdk/openai";
|
|
52
|
-
{{/if}}
|
|
53
|
-
|
|
54
|
-
const agent = new blink.Agent();
|
|
55
|
-
|
|
56
|
-
agent.on("chat", async ({ messages }) => {
|
|
57
|
-
return streamText({
|
|
58
|
-
{{#if (eq aiProvider "anthropic")}}
|
|
59
|
-
model: anthropic("claude-sonnet-4-5"),
|
|
60
|
-
{{else if (eq aiProvider "openai")}}
|
|
61
|
-
model: openai("gpt-5-chat-latest"),
|
|
62
|
-
{{else if (eq aiProvider "vercel")}}
|
|
63
|
-
model: "anthropic/claude-sonnet-4.5",
|
|
64
|
-
{{else}}
|
|
65
|
-
// Unknown provider: {{aiProvider}}. Defaulting to Vercel AI Gateway syntax.
|
|
66
|
-
model: "anthropic/claude-sonnet-4.5",
|
|
67
|
-
{{/if}}
|
|
68
|
-
system: \`You are a basic agent the user will customize.
|
|
69
|
-
|
|
70
|
-
Suggest the user enters edit mode with Ctrl+T or /edit to customize the agent.
|
|
71
|
-
Demonstrate your capabilities with the IP tool.\`,
|
|
72
|
-
messages: convertToModelMessages(messages),
|
|
73
|
-
tools: {
|
|
74
|
-
get_ip_info: tool({
|
|
75
|
-
description: "Get IP address information of the computer.",
|
|
76
|
-
inputSchema: z.object({}),
|
|
77
|
-
execute: async () => {
|
|
78
|
-
const response = await fetch("https://ipinfo.io/json");
|
|
79
|
-
return response.json();
|
|
80
|
-
},
|
|
81
|
-
}),
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
agent.serve();
|
|
87
|
-
`,"package.json.hbs":`{
|
|
88
|
-
"name": "{{packageName}}",
|
|
89
|
-
"main": "agent.ts",
|
|
90
|
-
"type": "module",
|
|
91
|
-
"private": true,
|
|
92
|
-
"scripts": {
|
|
93
|
-
"dev": "blink dev",
|
|
94
|
-
"deploy": "blink deploy"
|
|
95
|
-
},
|
|
96
|
-
"devDependencies": {
|
|
97
|
-
"zod": "latest",
|
|
98
|
-
"ai": "latest",
|
|
99
|
-
{{#if (eq aiProvider "anthropic")}}
|
|
100
|
-
"@ai-sdk/anthropic": "latest",
|
|
101
|
-
{{else if (eq aiProvider "openai")}}
|
|
102
|
-
"@ai-sdk/openai": "latest",
|
|
103
|
-
{{/if}}
|
|
104
|
-
"blink": "latest",
|
|
105
|
-
"esbuild": "latest",
|
|
106
|
-
"@types/node": "latest",
|
|
107
|
-
"typescript": "latest"
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
27
|
`,"AGENTS.md":`This project is a Blink agent.
|
|
111
28
|
|
|
112
29
|
You are an expert software engineer, which makes you an expert agent developer. You are highly idiomatic, opinionated, concise, and precise. The user prefers accuracy over speed.
|
|
@@ -180,7 +97,7 @@ const agent = new blink.Agent();
|
|
|
180
97
|
|
|
181
98
|
agent.on("chat", async ({ messages, chat, abortSignal }) => {
|
|
182
99
|
return streamText({
|
|
183
|
-
model:
|
|
100
|
+
model: "anthropic/claude-sonnet-4.5",
|
|
184
101
|
system: "You are a helpful assistant.",
|
|
185
102
|
messages: convertToModelMessages(messages, {
|
|
186
103
|
ignoreIncompleteToolCalls: true,
|
|
@@ -324,17 +241,6 @@ Tool Prefixing to avoid collisions:
|
|
|
324
241
|
|
|
325
242
|
LLM Models:
|
|
326
243
|
|
|
327
|
-
**Option 1: Blink Gateway** (Quick Start)
|
|
328
|
-
|
|
329
|
-
\`\`\`typescript
|
|
330
|
-
model: blink.model("anthropic/claude-sonnet-4.5");
|
|
331
|
-
model: blink.model("openai/gpt-5");
|
|
332
|
-
\`\`\`
|
|
333
|
-
|
|
334
|
-
Requires: \`blink login\` or \`BLINK_TOKEN\` env var
|
|
335
|
-
|
|
336
|
-
**Option 2: Direct Provider** (Production Recommended)
|
|
337
|
-
|
|
338
244
|
\`\`\`typescript
|
|
339
245
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
340
246
|
import { openai } from "@ai-sdk/openai";
|
|
@@ -349,7 +255,7 @@ model: openai("gpt-5", { apiKey: process.env.OPENAI_API_KEY });
|
|
|
349
255
|
|
|
350
256
|
1. If \`ANTHROPIC_API_KEY\` is set: uses \`claude-sonnet-4.5\` via \`@ai-sdk/anthropic\`
|
|
351
257
|
2. If \`OPENAI_API_KEY\` is set: uses \`gpt-5\` via \`@ai-sdk/openai\`
|
|
352
|
-
3.
|
|
258
|
+
3. If \`AI_GATEWAY_API_KEY\` is set: uses \`anthropic/claude-sonnet-4-5\` via the Vercel AI Gateway
|
|
353
259
|
|
|
354
260
|
Available SDKs:
|
|
355
261
|
|
|
@@ -419,7 +325,7 @@ agent.on("request", async (request) => {
|
|
|
419
325
|
agent.on("chat", async ({ messages }) => {
|
|
420
326
|
const tools = slack.createTools({ client: app.client });
|
|
421
327
|
return streamText({
|
|
422
|
-
model:
|
|
328
|
+
model: "anthropic/claude-sonnet-4.5",
|
|
423
329
|
system: "You chatting with users in Slack.",
|
|
424
330
|
messages: convertToModelMessages(messages, {
|
|
425
331
|
ignoreIncompleteToolCalls: true,
|
|
@@ -443,7 +349,7 @@ Slack App Manifest:
|
|
|
443
349
|
- _ALWAYS_ include the "assistant:write" scope unless the user explicitly states otherwise - this allows Slack apps to set their status, which makes for a significantly better user experience. You _MUST_ provide "assistant_view" if you provide this scope.
|
|
444
350
|
- The user can always edit the manifest after creation, but you'd have to suggest it to them.
|
|
445
351
|
- "oauth_config" MUST BE PROVIDED - otherwise the app will have NO ACCESS.
|
|
446
|
-
- _ALWAYS_ default
|
|
352
|
+
- _ALWAYS_ default \`token_rotation_enabled\` to false unless the user explicitly asks for it. It is a _much_ simpler user-experience to not rotate tokens.
|
|
447
353
|
- For the best user experience, default to the following bot scopes (in the "oauth_config" > "scopes" > "bot"):
|
|
448
354
|
- "app_mentions:read"
|
|
449
355
|
- "reactions:write"
|
|
@@ -536,160 +442,49 @@ The agent process can restart at any time, so all important state must be extern
|
|
|
536
442
|
|
|
537
443
|
- Never use "as any" type assertions. Always figure out the correct typings.
|
|
538
444
|
</code_quality>
|
|
539
|
-
|
|
540
|
-
node_modules
|
|
541
|
-
|
|
542
|
-
# config and build
|
|
543
|
-
data
|
|
544
|
-
|
|
545
|
-
# dotenv environment variables file
|
|
546
|
-
.env
|
|
547
|
-
.env.*
|
|
548
|
-
|
|
549
|
-
# Finder (MacOS) folder config
|
|
550
|
-
.DS_Store
|
|
551
|
-
`,"tsconfig.json":`{
|
|
552
|
-
"compilerOptions": {
|
|
553
|
-
"lib": ["ESNext"],
|
|
554
|
-
"target": "ESNext",
|
|
555
|
-
"module": "Preserve",
|
|
556
|
-
"moduleDetection": "force",
|
|
557
|
-
|
|
558
|
-
"moduleResolution": "bundler",
|
|
559
|
-
"allowImportingTsExtensions": true,
|
|
560
|
-
"verbatimModuleSyntax": true,
|
|
561
|
-
"resolveJsonModule": true,
|
|
562
|
-
"noEmit": true,
|
|
563
|
-
|
|
564
|
-
"strict": true,
|
|
565
|
-
"skipLibCheck": true,
|
|
566
|
-
"noFallthroughCasesInSwitch": true,
|
|
567
|
-
"noUncheckedIndexedAccess": true,
|
|
568
|
-
"noImplicitOverride": true,
|
|
569
|
-
|
|
570
|
-
"noUnusedLocals": false,
|
|
571
|
-
"noUnusedParameters": false,
|
|
572
|
-
|
|
573
|
-
"types": ["node"]
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
`,".env.local":`
|
|
577
|
-
# Store local environment variables here.
|
|
578
|
-
# They will be used by blink dev for development.
|
|
579
|
-
SLACK_BOT_TOKEN=xoxb-your-token-here
|
|
580
|
-
SLACK_SIGNING_SECRET=your-signing-secret-here
|
|
581
|
-
`,".env.production":`# Store production environment variables here.
|
|
582
|
-
# They will be upserted as secrets on blink deploy.
|
|
583
|
-
# EXTERNAL_SERVICE_API_KEY=
|
|
584
|
-
`,"agent.ts.hbs":`import { convertToModelMessages, streamText } from "ai";
|
|
445
|
+
`,"agent.ts.hbs":`import { convertToModelMessages, streamText, tool } from "ai";
|
|
585
446
|
import * as blink from "blink";
|
|
586
|
-
import
|
|
587
|
-
import { App } from "@slack/bolt";
|
|
447
|
+
import { z } from "zod";
|
|
588
448
|
{{#if (eq aiProvider "anthropic")}}
|
|
589
449
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
590
450
|
{{else if (eq aiProvider "openai")}}
|
|
591
451
|
import { openai } from "@ai-sdk/openai";
|
|
592
452
|
{{/if}}
|
|
593
453
|
|
|
594
|
-
const receiver = new slack.Receiver();
|
|
595
|
-
const app = new App({
|
|
596
|
-
token: process.env.SLACK_BOT_TOKEN,
|
|
597
|
-
signingSecret: process.env.SLACK_SIGNING_SECRET,
|
|
598
|
-
receiver,
|
|
599
|
-
});
|
|
600
|
-
|
|
601
|
-
// Handle messages in channels (only when @mentioned)
|
|
602
|
-
app.event("app_mention", async ({ event }) => {
|
|
603
|
-
const chat = await agent.chat.upsert([
|
|
604
|
-
"slack",
|
|
605
|
-
event.channel,
|
|
606
|
-
event.thread_ts ?? event.ts,
|
|
607
|
-
]);
|
|
608
|
-
const { message } = await slack.createMessageFromEvent({
|
|
609
|
-
client: app.client,
|
|
610
|
-
event,
|
|
611
|
-
});
|
|
612
|
-
await agent.chat.sendMessages(chat.id, [message]);
|
|
613
|
-
await app.client.assistant.threads.setStatus({
|
|
614
|
-
channel_id: event.channel,
|
|
615
|
-
status: "is typing...",
|
|
616
|
-
thread_ts: event.thread_ts ?? event.ts,
|
|
617
|
-
});
|
|
618
|
-
});
|
|
619
|
-
|
|
620
|
-
// Handle direct messages (always respond)
|
|
621
|
-
app.event("message", async ({ event }) => {
|
|
622
|
-
// Ignore bot messages and message changes
|
|
623
|
-
if (event.subtype || event.bot_id) {
|
|
624
|
-
return;
|
|
625
|
-
}
|
|
626
|
-
// Only handle DMs (channel type is 'im')
|
|
627
|
-
const channelInfo = await app.client.conversations.info({
|
|
628
|
-
channel: event.channel,
|
|
629
|
-
});
|
|
630
|
-
if (!channelInfo.channel?.is_im) {
|
|
631
|
-
return;
|
|
632
|
-
}
|
|
633
|
-
const chat = await agent.chat.upsert(["slack", event.channel]);
|
|
634
|
-
const { message } = await slack.createMessageFromEvent({
|
|
635
|
-
client: app.client,
|
|
636
|
-
event,
|
|
637
|
-
});
|
|
638
|
-
await agent.chat.sendMessages(chat.id, [message]);
|
|
639
|
-
await app.client.assistant.threads.setStatus({
|
|
640
|
-
channel_id: event.channel,
|
|
641
|
-
status: "is typing...",
|
|
642
|
-
thread_ts: event.thread_ts ?? event.ts,
|
|
643
|
-
});
|
|
644
|
-
});
|
|
645
|
-
|
|
646
454
|
const agent = new blink.Agent();
|
|
647
455
|
|
|
648
|
-
agent.on("request", async (request) => {
|
|
649
|
-
return receiver.handle(app, request);
|
|
650
|
-
});
|
|
651
|
-
|
|
652
456
|
agent.on("chat", async ({ messages }) => {
|
|
653
|
-
const tools = slack.createTools({ client: app.client });
|
|
654
|
-
const lastMessage = messages[messages.length - 1];
|
|
655
|
-
const threadInfo = lastMessage?.metadata as
|
|
656
|
-
| { channel?: string; thread_ts?: string }
|
|
657
|
-
| undefined;
|
|
658
|
-
|
|
659
|
-
// Add instruction to clear status after completion
|
|
660
|
-
if (threadInfo?.channel && threadInfo?.thread_ts) {
|
|
661
|
-
const clonedMessages = structuredClone(messages);
|
|
662
|
-
const lastClonedMessage = clonedMessages[clonedMessages.length - 1];
|
|
663
|
-
if (lastClonedMessage) {
|
|
664
|
-
lastClonedMessage.parts.push({
|
|
665
|
-
type: "text",
|
|
666
|
-
text: \`*INTERNAL INSTRUCTION*: Clear the status of this thread after you finish: channel=\${threadInfo.channel} thread_ts=\${threadInfo.thread_ts}\`,
|
|
667
|
-
});
|
|
668
|
-
}
|
|
669
|
-
messages = clonedMessages;
|
|
670
|
-
}
|
|
671
|
-
|
|
672
457
|
return streamText({
|
|
673
458
|
{{#if (eq aiProvider "anthropic")}}
|
|
674
459
|
model: anthropic("claude-sonnet-4-5"),
|
|
675
460
|
{{else if (eq aiProvider "openai")}}
|
|
676
|
-
model: openai("gpt-5
|
|
461
|
+
model: openai.chat("gpt-5"),
|
|
677
462
|
{{else if (eq aiProvider "vercel")}}
|
|
678
463
|
model: "anthropic/claude-sonnet-4.5",
|
|
679
464
|
{{else}}
|
|
680
465
|
// Unknown provider: {{aiProvider}}. Defaulting to Vercel AI Gateway syntax.
|
|
681
466
|
model: "anthropic/claude-sonnet-4.5",
|
|
682
467
|
{{/if}}
|
|
683
|
-
system:
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
tools
|
|
468
|
+
system: \`You are a basic agent the user will customize.
|
|
469
|
+
|
|
470
|
+
Suggest the user enters edit mode with Ctrl+T or /edit to customize the agent.
|
|
471
|
+
Demonstrate your capabilities with the IP tool.\`,
|
|
472
|
+
messages: convertToModelMessages(messages),
|
|
473
|
+
tools: {
|
|
474
|
+
get_ip_info: tool({
|
|
475
|
+
description: "Get IP address information of the computer.",
|
|
476
|
+
inputSchema: z.object({}),
|
|
477
|
+
execute: async () => {
|
|
478
|
+
const response = await fetch("https://ipinfo.io/json");
|
|
479
|
+
return response.json();
|
|
480
|
+
},
|
|
481
|
+
}),
|
|
482
|
+
},
|
|
689
483
|
});
|
|
690
484
|
});
|
|
691
485
|
|
|
692
|
-
agent.serve()
|
|
486
|
+
agent.serve();
|
|
487
|
+
`,"package.json.hbs":`{
|
|
693
488
|
"name": "{{packageName}}",
|
|
694
489
|
"main": "agent.ts",
|
|
695
490
|
"type": "module",
|
|
@@ -709,11 +504,64 @@ agent.serve();`,"package.json.hbs":`{
|
|
|
709
504
|
"blink": "latest",
|
|
710
505
|
"esbuild": "latest",
|
|
711
506
|
"@types/node": "latest",
|
|
712
|
-
"typescript": "latest"
|
|
713
|
-
"@slack/bolt": "latest",
|
|
714
|
-
"@blink-sdk/slack": "latest"
|
|
507
|
+
"typescript": "latest"
|
|
715
508
|
}
|
|
716
509
|
}
|
|
510
|
+
`,"tsconfig.json":`{
|
|
511
|
+
"compilerOptions": {
|
|
512
|
+
"lib": ["ESNext"],
|
|
513
|
+
"target": "ESNext",
|
|
514
|
+
"module": "Preserve",
|
|
515
|
+
"moduleDetection": "force",
|
|
516
|
+
|
|
517
|
+
"moduleResolution": "bundler",
|
|
518
|
+
"allowImportingTsExtensions": true,
|
|
519
|
+
"verbatimModuleSyntax": true,
|
|
520
|
+
"resolveJsonModule": true,
|
|
521
|
+
"noEmit": true,
|
|
522
|
+
|
|
523
|
+
"strict": true,
|
|
524
|
+
"skipLibCheck": true,
|
|
525
|
+
"noFallthroughCasesInSwitch": true,
|
|
526
|
+
"noUncheckedIndexedAccess": true,
|
|
527
|
+
"noImplicitOverride": true,
|
|
528
|
+
|
|
529
|
+
"noUnusedLocals": false,
|
|
530
|
+
"noUnusedParameters": false,
|
|
531
|
+
|
|
532
|
+
"types": ["node"]
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
`},"slack-bot":{".env.local.hbs":`# Store local environment variables here.
|
|
536
|
+
# They will be used by blink dev for development.
|
|
537
|
+
{{#each envLocal}}
|
|
538
|
+
{{this.[0]}}={{this.[1]}}
|
|
539
|
+
{{/each}}
|
|
540
|
+
{{#unless (hasAnyEnvVar envLocal "OPENAI_API_KEY" "ANTHROPIC_API_KEY" "AI_GATEWAY_API_KEY")}}
|
|
541
|
+
# OPENAI_API_KEY=
|
|
542
|
+
# ANTHROPIC_API_KEY=
|
|
543
|
+
# AI_GATEWAY_API_KEY=
|
|
544
|
+
{{/unless}}
|
|
545
|
+
SLACK_BOT_TOKEN=xoxb-your-token-here
|
|
546
|
+
SLACK_SIGNING_SECRET=your-signing-secret-here
|
|
547
|
+
`,".env.production":`# Store production environment variables here.
|
|
548
|
+
# They will be upserted as secrets on blink deploy.
|
|
549
|
+
# SLACK_BOT_TOKEN=
|
|
550
|
+
# SLACK_SIGNING_SECRET=
|
|
551
|
+
# OPENAI_API_KEY=
|
|
552
|
+
# ANTHROPIC_API_KEY=
|
|
553
|
+
# AI_GATEWAY_API_KEY=`,".gitignore":`# dependencies
|
|
554
|
+
node_modules
|
|
555
|
+
|
|
556
|
+
# config and build
|
|
557
|
+
.blink
|
|
558
|
+
|
|
559
|
+
# dotenv environment variables file
|
|
560
|
+
.env
|
|
561
|
+
.env.*
|
|
562
|
+
|
|
563
|
+
# Finder (MacOS) folder config
|
|
564
|
+
.DS_Store
|
|
717
565
|
`,"AGENTS.md":`This project is a Blink agent.
|
|
718
566
|
|
|
719
567
|
You are an expert software engineer, which makes you an expert agent developer. You are highly idiomatic, opinionated, concise, and precise. The user prefers accuracy over speed.
|
|
@@ -787,7 +635,7 @@ const agent = new blink.Agent();
|
|
|
787
635
|
|
|
788
636
|
agent.on("chat", async ({ messages, chat, abortSignal }) => {
|
|
789
637
|
return streamText({
|
|
790
|
-
model:
|
|
638
|
+
model: "anthropic/claude-sonnet-4.5",
|
|
791
639
|
system: "You are a helpful assistant.",
|
|
792
640
|
messages: convertToModelMessages(messages, {
|
|
793
641
|
ignoreIncompleteToolCalls: true,
|
|
@@ -931,17 +779,6 @@ Tool Prefixing to avoid collisions:
|
|
|
931
779
|
|
|
932
780
|
LLM Models:
|
|
933
781
|
|
|
934
|
-
**Option 1: Blink Gateway** (Quick Start)
|
|
935
|
-
|
|
936
|
-
\`\`\`typescript
|
|
937
|
-
model: blink.model("anthropic/claude-sonnet-4.5");
|
|
938
|
-
model: blink.model("openai/gpt-5");
|
|
939
|
-
\`\`\`
|
|
940
|
-
|
|
941
|
-
Requires: \`blink login\` or \`BLINK_TOKEN\` env var
|
|
942
|
-
|
|
943
|
-
**Option 2: Direct Provider** (Production Recommended)
|
|
944
|
-
|
|
945
782
|
\`\`\`typescript
|
|
946
783
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
947
784
|
import { openai } from "@ai-sdk/openai";
|
|
@@ -956,7 +793,6 @@ model: openai("gpt-5", { apiKey: process.env.OPENAI_API_KEY });
|
|
|
956
793
|
|
|
957
794
|
1. If \`ANTHROPIC_API_KEY\` is set: uses \`claude-sonnet-4.5\` via \`@ai-sdk/anthropic\`
|
|
958
795
|
2. If \`OPENAI_API_KEY\` is set: uses \`gpt-5\` via \`@ai-sdk/openai\`
|
|
959
|
-
3. Otherwise: falls back to \`blink.model("anthropic/claude-sonnet-4.5")\`
|
|
960
796
|
|
|
961
797
|
Available SDKs:
|
|
962
798
|
|
|
@@ -1026,7 +862,7 @@ agent.on("request", async (request) => {
|
|
|
1026
862
|
agent.on("chat", async ({ messages }) => {
|
|
1027
863
|
const tools = slack.createTools({ client: app.client });
|
|
1028
864
|
return streamText({
|
|
1029
|
-
model:
|
|
865
|
+
model: "anthropic/claude-sonnet-4.5",
|
|
1030
866
|
system: "You chatting with users in Slack.",
|
|
1031
867
|
messages: convertToModelMessages(messages, {
|
|
1032
868
|
ignoreIncompleteToolCalls: true,
|
|
@@ -1050,7 +886,7 @@ Slack App Manifest:
|
|
|
1050
886
|
- _ALWAYS_ include the "assistant:write" scope unless the user explicitly states otherwise - this allows Slack apps to set their status, which makes for a significantly better user experience. You _MUST_ provide "assistant_view" if you provide this scope.
|
|
1051
887
|
- The user can always edit the manifest after creation, but you'd have to suggest it to them.
|
|
1052
888
|
- "oauth_config" MUST BE PROVIDED - otherwise the app will have NO ACCESS.
|
|
1053
|
-
- _ALWAYS_ default
|
|
889
|
+
- _ALWAYS_ default \`token_rotation_enabled\` to false unless the user explicitly asks for it. It is a _much_ simpler user-experience to not rotate tokens.
|
|
1054
890
|
- For the best user experience, default to the following bot scopes (in the "oauth_config" > "scopes" > "bot"):
|
|
1055
891
|
- "app_mentions:read"
|
|
1056
892
|
- "reactions:write"
|
|
@@ -1143,4 +979,162 @@ The agent process can restart at any time, so all important state must be extern
|
|
|
1143
979
|
|
|
1144
980
|
- Never use "as any" type assertions. Always figure out the correct typings.
|
|
1145
981
|
</code_quality>
|
|
982
|
+
`,"agent.ts.hbs":`import { convertToModelMessages, streamText } from "ai";
|
|
983
|
+
import * as blink from "blink";
|
|
984
|
+
import * as slack from "@blink-sdk/slack";
|
|
985
|
+
import { App } from "@slack/bolt";
|
|
986
|
+
{{#if (eq aiProvider "anthropic")}}
|
|
987
|
+
import { anthropic } from "@ai-sdk/anthropic";
|
|
988
|
+
{{else if (eq aiProvider "openai")}}
|
|
989
|
+
import { openai } from "@ai-sdk/openai";
|
|
990
|
+
{{/if}}
|
|
991
|
+
|
|
992
|
+
const receiver = new slack.Receiver();
|
|
993
|
+
const app = new App({
|
|
994
|
+
token: process.env.SLACK_BOT_TOKEN,
|
|
995
|
+
signingSecret: process.env.SLACK_SIGNING_SECRET,
|
|
996
|
+
receiver,
|
|
997
|
+
});
|
|
998
|
+
|
|
999
|
+
// Handle messages in channels (only when @mentioned)
|
|
1000
|
+
app.event("app_mention", async ({ event }) => {
|
|
1001
|
+
const chat = await agent.chat.upsert([
|
|
1002
|
+
"slack",
|
|
1003
|
+
event.channel,
|
|
1004
|
+
event.thread_ts ?? event.ts,
|
|
1005
|
+
]);
|
|
1006
|
+
const { message } = await slack.createMessageFromEvent({
|
|
1007
|
+
client: app.client,
|
|
1008
|
+
event,
|
|
1009
|
+
});
|
|
1010
|
+
await agent.chat.sendMessages(chat.id, [message]);
|
|
1011
|
+
await app.client.assistant.threads.setStatus({
|
|
1012
|
+
channel_id: event.channel,
|
|
1013
|
+
status: "is typing...",
|
|
1014
|
+
thread_ts: event.thread_ts ?? event.ts,
|
|
1015
|
+
});
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1018
|
+
// Handle direct messages (always respond)
|
|
1019
|
+
app.event("message", async ({ event }) => {
|
|
1020
|
+
// Ignore bot messages and message changes
|
|
1021
|
+
if (event.subtype || event.bot_id) {
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
// Only handle DMs (channel type is 'im')
|
|
1025
|
+
const channelInfo = await app.client.conversations.info({
|
|
1026
|
+
channel: event.channel,
|
|
1027
|
+
});
|
|
1028
|
+
if (!channelInfo.channel?.is_im) {
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
const chat = await agent.chat.upsert(["slack", event.channel]);
|
|
1032
|
+
const { message } = await slack.createMessageFromEvent({
|
|
1033
|
+
client: app.client,
|
|
1034
|
+
event,
|
|
1035
|
+
});
|
|
1036
|
+
await agent.chat.sendMessages(chat.id, [message]);
|
|
1037
|
+
await app.client.assistant.threads.setStatus({
|
|
1038
|
+
channel_id: event.channel,
|
|
1039
|
+
status: "is typing...",
|
|
1040
|
+
thread_ts: event.thread_ts ?? event.ts,
|
|
1041
|
+
});
|
|
1042
|
+
});
|
|
1043
|
+
|
|
1044
|
+
const agent = new blink.Agent();
|
|
1045
|
+
|
|
1046
|
+
agent.on("request", async (request) => {
|
|
1047
|
+
return receiver.handle(app, request);
|
|
1048
|
+
});
|
|
1049
|
+
|
|
1050
|
+
agent.on("chat", async ({ messages }) => {
|
|
1051
|
+
const tools = slack.createTools({ client: app.client });
|
|
1052
|
+
const lastMessage = messages[messages.length - 1];
|
|
1053
|
+
const threadInfo = lastMessage?.metadata as
|
|
1054
|
+
| { channel?: string; thread_ts?: string }
|
|
1055
|
+
| undefined;
|
|
1056
|
+
|
|
1057
|
+
// Add instruction to clear status after completion
|
|
1058
|
+
if (threadInfo?.channel && threadInfo?.thread_ts) {
|
|
1059
|
+
const clonedMessages = structuredClone(messages);
|
|
1060
|
+
const lastClonedMessage = clonedMessages[clonedMessages.length - 1];
|
|
1061
|
+
if (lastClonedMessage) {
|
|
1062
|
+
lastClonedMessage.parts.push({
|
|
1063
|
+
type: "text",
|
|
1064
|
+
text: \`*INTERNAL INSTRUCTION*: Clear the status of this thread after you finish: channel=\${threadInfo.channel} thread_ts=\${threadInfo.thread_ts}\`,
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
messages = clonedMessages;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
return streamText({
|
|
1071
|
+
{{#if (eq aiProvider "anthropic")}}
|
|
1072
|
+
model: anthropic("claude-sonnet-4-5"),
|
|
1073
|
+
{{else if (eq aiProvider "openai")}}
|
|
1074
|
+
model: openai.chat("gpt-5"),
|
|
1075
|
+
{{else if (eq aiProvider "vercel")}}
|
|
1076
|
+
model: "anthropic/claude-sonnet-4.5",
|
|
1077
|
+
{{else}}
|
|
1078
|
+
// Unknown provider: {{aiProvider}}. Defaulting to Vercel AI Gateway syntax.
|
|
1079
|
+
model: "anthropic/claude-sonnet-4.5",
|
|
1080
|
+
{{/if}}
|
|
1081
|
+
system: "You are a helpful Slack bot assistant.",
|
|
1082
|
+
messages: convertToModelMessages(messages, {
|
|
1083
|
+
ignoreIncompleteToolCalls: true,
|
|
1084
|
+
tools,
|
|
1085
|
+
}),
|
|
1086
|
+
tools,
|
|
1087
|
+
});
|
|
1088
|
+
});
|
|
1089
|
+
|
|
1090
|
+
agent.serve();`,"package.json.hbs":`{
|
|
1091
|
+
"name": "{{packageName}}",
|
|
1092
|
+
"main": "agent.ts",
|
|
1093
|
+
"type": "module",
|
|
1094
|
+
"private": true,
|
|
1095
|
+
"scripts": {
|
|
1096
|
+
"dev": "blink dev",
|
|
1097
|
+
"deploy": "blink deploy"
|
|
1098
|
+
},
|
|
1099
|
+
"devDependencies": {
|
|
1100
|
+
"zod": "latest",
|
|
1101
|
+
"ai": "latest",
|
|
1102
|
+
{{#if (eq aiProvider "anthropic")}}
|
|
1103
|
+
"@ai-sdk/anthropic": "latest",
|
|
1104
|
+
{{else if (eq aiProvider "openai")}}
|
|
1105
|
+
"@ai-sdk/openai": "latest",
|
|
1106
|
+
{{/if}}
|
|
1107
|
+
"blink": "latest",
|
|
1108
|
+
"esbuild": "latest",
|
|
1109
|
+
"@types/node": "latest",
|
|
1110
|
+
"typescript": "latest",
|
|
1111
|
+
"@slack/bolt": "latest",
|
|
1112
|
+
"@blink-sdk/slack": "latest"
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
`,"tsconfig.json":`{
|
|
1116
|
+
"compilerOptions": {
|
|
1117
|
+
"lib": ["ESNext"],
|
|
1118
|
+
"target": "ESNext",
|
|
1119
|
+
"module": "Preserve",
|
|
1120
|
+
"moduleDetection": "force",
|
|
1121
|
+
|
|
1122
|
+
"moduleResolution": "bundler",
|
|
1123
|
+
"allowImportingTsExtensions": true,
|
|
1124
|
+
"verbatimModuleSyntax": true,
|
|
1125
|
+
"resolveJsonModule": true,
|
|
1126
|
+
"noEmit": true,
|
|
1127
|
+
|
|
1128
|
+
"strict": true,
|
|
1129
|
+
"skipLibCheck": true,
|
|
1130
|
+
"noFallthroughCasesInSwitch": true,
|
|
1131
|
+
"noUncheckedIndexedAccess": true,
|
|
1132
|
+
"noImplicitOverride": true,
|
|
1133
|
+
|
|
1134
|
+
"noUnusedLocals": false,
|
|
1135
|
+
"noUnusedParameters": false,
|
|
1136
|
+
|
|
1137
|
+
"types": ["node"]
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1146
1140
|
`}};export{e as templates};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./dist-Ceoe3h7v.js";import{login as e}from"./auth-BilZuH-1.js";import"./util-CUfifM0g.js";async function t(){await e()}export{t as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{__toESM as e}from"./chunk-D9KrCrVq.js";import{findNearestEntry as t,
|
|
1
|
+
import{__toESM as e}from"./chunk-D9KrCrVq.js";import{findNearestEntry as t,migrateDataToBlink as n,require_main as r,resolveConfig as i}from"./util-k3x8m_i5.js";import"./dist-Ceoe3h7v.js";import{getAuthToken as a}from"./auth-BilZuH-1.js";import"./util-CUfifM0g.js";import{ChatManager as o,Client as s}from"./chat-manager-DfVg04yc.js";import{spawn as c}from"node:child_process";import{join as l,resolve as u}from"node:path";import{existsSync as d}from"node:fs";import{readFile as f}from"node:fs/promises";import{createServer as p}from"node:net";async function m(e){let t=e.env?.PORT??await h(),n=e.env?.HOST??`127.0.0.1`,r=`http://${n}:${t}`,i={...e.env??process.env,PORT:t.toString(),HOST:n},a=c(e.command,e.args,{stdio:`pipe`,env:i});e.signal?.addEventListener(`abort`,()=>{try{a.kill()}catch{}},{once:!0});let o=new AbortController,l=[o.signal];e.signal&&l.push(e.signal);let u=AbortSignal.any(l);a.stdout.on(`data`,t=>{e.onStdout?.(Buffer.from(t).toString(`utf-8`))});let d=``;a.stderr.on(`data`,t=>{o.signal.aborted||(d+=Buffer.from(t).toString(`utf-8`)),e.onStderr?.(Buffer.from(t).toString(`utf-8`))}),a.on(`error`,e=>{o.abort(e)}),a.on(`exit`,(t,n)=>{o.signal.aborted?e.onExit?.(t,n):o.abort()});let f=new s({baseUrl:r}),p=0;for(;!u.aborted;){try{await f.health();break}catch{}if(await new Promise(e=>setTimeout(e,p*5)),p++,p>100)throw Error(`Health endpoint timed out`)}if(u.aborted)throw u.reason;return o.abort(),{client:f,dispose:()=>{a.kill()}}}async function h(){let e=p();return new Promise((t,n)=>{e.listen(0,()=>{let n=e.address().port;t(n)}).on(`error`,e=>{n(e)})}).finally(()=>{e.close()})}var g=e(r(),1);async function _(e,r={}){if(!r.directory){let e=process.cwd();try{i(e),r.directory=e}catch{let n=await t(e,`.blink`);n&&d(l(n,`build`))&&(n=void 0),n?r.directory=n:r.directory=e}}await n(r.directory);let s=i(r.directory),c={};try{c=(0,g.parse)(await f(l(r.directory,`.env.local`),`utf-8`))}catch{}let p=await a(),h=await m({command:`node`,args:[`--experimental-strip-types`,`--no-deprecation`,s.entry],env:{...process.env,...c,BLINK_TOKEN:p}});console.log(`Agent spawned`);let _=u(r?.directory??process.cwd(),`.blink`,`chats`),v=new o({chatId:r?.chat,chatsDirectory:_});v.setAgent(h.client);try{let t=new Promise(e=>{let t=v.subscribe(n=>{(n.status===`idle`||n.status===`error`)&&(t(),e())})});await v.sendMessages([{id:crypto.randomUUID(),created_at:new Date().toISOString(),metadata:void 0,parts:[{type:`text`,text:e.join(` `)}],role:`user`,mode:`run`}]),await t;let n=v.getState();n.error&&console.error(`Error:`,n.error),console.log(`Final state:`,n.messages.pop())}finally{v.dispose(),h.dispose()}}export{_ as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Client as e,Ie as t,M as n,Se as r,Y as i,ge as a,he as o,pD as s,ye as c}from"./dist-Ceoe3h7v.js";import{openUrl as l,source_default as u}from"./util-CUfifM0g.js";import{createDevhookID as d,createSlackApp as f,getDevhookID as p,hasDevhook as m}from"./create-slack-app-CyVPwWsG.js";import h from"crypto";import{basename as g,join as _}from"path";import{access as v,readFile as y,readdir as b,writeFile as x}from"fs/promises";import S from"node:util";function C(){var e=typeof SuppressedError==`function`?SuppressedError:function(e,t){var n=Error();return n.name=`SuppressedError`,n.error=e,n.suppressed=t,n},t={},n=[];function r(e,t){if(t!=null){if(Object(t)!==t)throw TypeError(`using declarations can only be used with objects, functions, null, or undefined.`);if(e)var r=t[Symbol.asyncDispose||Symbol.for(`Symbol.asyncDispose`)];if(r===void 0&&(r=t[Symbol.dispose||Symbol.for(`Symbol.dispose`)],e))var i=r;if(typeof r!=`function`)throw TypeError(`Object is not disposable.`);i&&(r=function(){try{i.call(t)}catch(e){return Promise.reject(e)}}),n.push({v:t,d:r,a:e})}else e&&n.push({d:t,a:e});return t}return{e:t,u:r.bind(null,!1),a:r.bind(null,!0),d:function(){var r,i=this.e,a=0;function o(){for(;r=n.pop();)try{if(!r.a&&a===1)return a=0,n.push(r),Promise.resolve().then(o);if(r.d){var e=r.d.call(r.v);if(r.a)return a|=2,Promise.resolve(e).then(o,s)}else a|=1}catch(e){return s(e)}if(a===1)return i===t?Promise.resolve():Promise.reject(i);if(i!==t)throw i}function s(n){return i=i===t?n:new e(n,i),o()}return o()}}}async function w(e){try{let t=await(await fetch(`https://slack.com/api/auth.test`,{method:`POST`,headers:{Authorization:`Bearer ${e}`,"Content-Type":`application/json`}})).json();return t.ok?{valid:!0,botName:t.user}:{valid:!1,error:t.error||`Invalid bot token`}}catch(e){return{valid:!1,error:`Failed to verify credentials: ${e}`}}}function T(e,t,n,r){let i=Math.floor(Date.now()/1e3),a=parseInt(t,10);if(Math.abs(i-a)>300)return!1;let o=h.createHmac(`sha256`,e),s=`v0:${t}:${n}`;o.update(s);let c=`v0=${o.digest(`hex`)}`;return h.timingSafeEqual(Buffer.from(c),Buffer.from(r))}const E=e=>{if(!(typeof e==`object`&&e))throw Error(`Unable to make value disposable, it's not an object`);if(Symbol.dispose in e)return e;if(`dispose`in e&&typeof e.dispose==`function`)return e[Symbol.dispose]=()=>e.dispose(),e;throw Error(`Unable to make value disposable`)};async function D(e,t,n){let r=await y(e,`utf-8`);t&&(r=r.replace(/SLACK_BOT_TOKEN=.*/,`SLACK_BOT_TOKEN=${t}`)),n&&(r=r.replace(/SLACK_SIGNING_SECRET=.*/,`SLACK_SIGNING_SECRET=${n}`)),await x(e,r)}async function O(e){let t=await b(e);for(let[e,n]of[[`bun`,`bun.lock`],[`npm`,`package-lock.json`],[`pnpm`,`pnpm-lock.yaml`],[`yarn`,`yarn.lock`]])for(let r of t)if(r.includes(n))return e;return`npm`}async function k(t,h){try{var y=C();let b=h?.name||g(t).replace(/[^a-zA-Z0-9]/g,`-`),x=h?.packageManager||await O(t),k=_(t,`.env.local`);try{await v(k)}catch{n.error(`No .env.local file found in this directory. Please run this command from a Blink agent directory.`),r(`Slack app setup cancelled`);return}let A=await o({message:`What should your Slack app be called? This will be the name displayed in Slack. You can change it later.`,placeholder:b,defaultValue:b,validate:e=>{if(!e||e.trim().length===0)return`App name cannot be empty`}});if(s(A))return;let j=m(t)?p(t):d(t),M=`https://${j}.blink.host`;if(!j)throw Error(`Failed to obtain devhook ID`);n.info(`Starting webhook listener...`);let N=``,P=``,F=!1,I=``,L=``,R=!1,z,B=new e({baseURL:`https://blink.so`}),V=()=>{},H=e=>{},U=new Promise((e,t)=>{V=e,H=t}),W=B.devhook.listen({id:j,onRequest:async e=>{let t=await e.text(),r;try{r=JSON.parse(t)}catch{return new Response(`Invalid JSON`,{status:400})}if(r.type===`url_verification`)return n.info(`✓ Webhook challenge received`),new Response(JSON.stringify({challenge:r.challenge}),{headers:{"Content-Type":`application/json`}});if(N){let n=e.headers.get(`x-slack-signature`),i=e.headers.get(`x-slack-request-timestamp`);if(!n||!i)return new Response(`Missing signature`,{status:401});if(!T(N,i,t,n))return R=!0,r.event?.type===`message`&&r.event.channel_type===`im`&&!r.event.bot_id&&(z=r.event.channel),new Response(`Invalid signature`,{status:401})}return r.event?.type===`message`&&r.event.channel_type===`im`&&!r.event.bot_id&&(F=!0,I=r.event.channel,L=r.event.ts),new Response(`OK`)},onConnect:()=>{V()},onDisconnect:()=>{},onError:e=>{H(e)}});y.u(E(W));let G={display_information:{name:A.toString(),description:`A Blink agent for Slack`,background_color:`#4A154B`},features:{bot_user:{display_name:A.toString(),always_online:!0},app_home:{home_tab_enabled:!1,messages_tab_enabled:!0,messages_tab_read_only_enabled:!1},assistant_view:{assistant_description:`A helpful assistant powered by Blink`}},oauth_config:{scopes:{bot:[`app_mentions:read`,`assistant:write`,`reactions:write`,`reactions:read`,`channels:history`,`chat:write`,`groups:history`,`groups:read`,`files:read`,`im:history`,`im:read`,`im:write`,`mpim:history`,`mpim:read`,`users:read`,`links:read`,`commands`]}},settings:{event_subscriptions:{request_url:M,bot_events:[`app_mention`,`message.channels`,`message.groups`,`message.im`,`reaction_added`,`reaction_removed`,`assistant_thread_started`,`member_joined_channel`]},interactivity:{is_enabled:!0,request_url:M},token_rotation_enabled:!1,org_deploy_enabled:!1,socket_mode_enabled:!1}},K=f(G);n.info(`Please visit this URL to create your Slack app and return here after finishing:\n\n${u.gray(K)}\n`);let q=await c({message:`Open this URL in your browser automatically?`,initialValue:!0});if(s(q)){n.warn(`Skipping Slack app setup`);return}q&&await l(K,`Could not open the browser. Please visit the URL manually.`);let J=await o({message:`After creating the app, paste the App ID from the "Basic Information" page:`,placeholder:`A01234567AB`,validate:e=>{if(!e||e.trim().length===0)return`App ID is required`}});if(s(J)){n.warn(`Skipping Slack app setup`);return}if(N=await a({message:`Paste your Signing Secret from the same page:`,validate:e=>{if(!e||e.trim().length===0)return`Signing secret is required`}}),s(N)){n.warn(`Skipping Slack app setup`);return}let Y=!1;for(;!Y;){if(P=await a({message:`Install your app and paste your Bot Token from ${u.cyan(`https://api.slack.com/apps/${J}/install-on-team`)}`,validate:e=>{if(!e||e.trim().length===0)return`Bot token is required`}}),s(P)){n.warn(`Skipping Slack app setup`);return}let e=i();e.start(`Verifying bot token...`);let t=await w(P);if(t.valid)e.stop(`✓ Bot token verified!`),Y=!0;else{e.stop(`✗ Failed to verify bot token: ${t.error}`);let r=await c({message:`Would you like to try again?`,initialValue:!0});if(s(r)||!r){n.warn(`Skipping Slack app setup`);return}}}await D(k,P,N),n.success(`Credentials saved to .env.local`),await U;let X=i();X.start(`Try sending a DM to the bot on Slack - it's ${u.bold(u.cyan(A))} in the search bar.`);let Z={bun:`bun run dev`,npm:`npm run dev`,pnpm:`pnpm run dev`,yarn:`yarn dev`}[x];for(;!F;){if(R){if(X.stop(`✗ Invalid signing secret detected`),z&&P)try{await fetch(`https://slack.com/api/chat.postMessage`,{method:`POST`,headers:{Authorization:`Bearer ${P}`,"Content-Type":`application/json`},body:JSON.stringify({channel:z,text:`⚠️ There seems to be a problem with the signing secret. Please check the CLI for instructions on how to fix it.`})})}catch{}let e=await a({message:`The signing secret appears to be incorrect. Please paste the correct Signing Secret from ${u.cyan(`https://api.slack.com/apps/${J}/general`)}`,validate:e=>{if(!e||e.trim().length===0)return`Signing secret is required`}});if(s(e)){n.warn(`Skipping Slack app setup`);return}N=e,R=!1,z=void 0,await D(k,void 0,N),X.start(`Please try sending a DM to the bot again on Slack...`)}await new Promise(e=>setTimeout(e,500))}X.stop(u.green(`✓ DM received!`));try{await fetch(`https://slack.com/api/chat.postMessage`,{method:`POST`,headers:{Authorization:`Bearer ${P}`,"Content-Type":`application/json`},body:JSON.stringify({channel:I,thread_ts:L,text:`Congrats, your app is now installed and ready to use! Run \`${Z}\` to use your agent.`})})}catch(e){n.warn(`Could not send message to Slack: ${S.inspect(e)}`)}n.success(`Slack app setup complete!`)}catch(e){y.e=e}finally{y.d()}}async function A(e){e||=process.cwd(),t(`Setting up Slack app`),await k(e),process.exit(0)}export{k as setupSlackApp,A as setupSlackAppCommand};
|