@poncho-ai/cli 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
 
2
- > @poncho-ai/cli@0.12.0 build /home/runner/work/poncho-ai/poncho-ai/packages/cli
2
+ > @poncho-ai/cli@0.13.0 build /home/runner/work/poncho-ai/poncho-ai/packages/cli
3
3
  > tsup src/index.ts src/cli.ts --format esm --dts
4
4
 
5
5
  CLI Building entry: src/cli.ts, src/index.ts
@@ -8,11 +8,11 @@
8
8
  CLI Target: es2022
9
9
  ESM Build start
10
10
  ESM dist/cli.js 94.00 B
11
- ESM dist/run-interactive-ink-64QEOUXL.js 53.83 KB
12
11
  ESM dist/index.js 857.00 B
13
- ESM dist/chunk-XIFWXRUB.js 241.46 KB
14
- ESM ⚡️ Build success in 59ms
12
+ ESM dist/run-interactive-ink-VZBOYJYS.js 53.83 KB
13
+ ESM dist/chunk-CUCEDHME.js 245.47 KB
14
+ ESM ⚡️ Build success in 47ms
15
15
  DTS Build start
16
- DTS ⚡️ Build success in 3442ms
16
+ DTS ⚡️ Build success in 3770ms
17
17
  DTS dist/cli.d.ts 20.00 B
18
18
  DTS dist/index.d.ts 3.56 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @poncho-ai/cli
2
2
 
3
+ ## 0.13.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#10](https://github.com/cesr/poncho-ai/pull/10) [`d5bce7b`](https://github.com/cesr/poncho-ai/commit/d5bce7be5890c657bea915eb0926feb6de66b218) Thanks [@cesr](https://github.com/cesr)! - Add generic messaging layer with Slack as the first adapter. Agents can now respond to @mentions in Slack by adding `messaging: [{ platform: 'slack' }]` to `poncho.config.js`. Includes signature verification, threaded conversations, processing indicators, and Vercel `waitUntil` support.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [[`d5bce7b`](https://github.com/cesr/poncho-ai/commit/d5bce7be5890c657bea915eb0926feb6de66b218)]:
12
+ - @poncho-ai/messaging@0.2.0
13
+ - @poncho-ai/harness@0.13.1
14
+ - @poncho-ai/sdk@1.0.1
15
+
3
16
  ## 0.12.0
4
17
 
5
18
  ### Minor Changes
@@ -22,6 +22,10 @@ import {
22
22
  resolveStateConfig
23
23
  } from "@poncho-ai/harness";
24
24
  import { getTextContent } from "@poncho-ai/sdk";
25
+ import {
26
+ AgentBridge,
27
+ SlackAdapter
28
+ } from "@poncho-ai/messaging";
25
29
  import Busboy from "busboy";
26
30
  import { Command } from "commander";
27
31
  import dotenv from "dotenv";
@@ -3509,12 +3513,17 @@ var buildConfigFromOnboardingAnswers = (answers) => {
3509
3513
  enabled: telemetryEnabled
3510
3514
  };
3511
3515
  maybeSet(telemetry, "otlp", answers["telemetry.otlp"]);
3512
- return {
3516
+ const messagingPlatform = String(answers["messaging.platform"] ?? "none");
3517
+ const config = {
3513
3518
  mcp: [],
3514
3519
  auth,
3515
3520
  storage,
3516
3521
  telemetry
3517
3522
  };
3523
+ if (messagingPlatform !== "none") {
3524
+ config.messaging = [{ platform: messagingPlatform }];
3525
+ }
3526
+ return config;
3518
3527
  };
3519
3528
  var collectEnvVars = (answers) => {
3520
3529
  const envVars = /* @__PURE__ */ new Set();
@@ -3658,11 +3667,13 @@ var summarizeConfig = (config) => {
3658
3667
  const memoryEnabled = config?.storage?.memory?.enabled ?? config?.memory?.enabled ?? false;
3659
3668
  const authRequired = config?.auth?.required ?? false;
3660
3669
  const telemetryEnabled = config?.telemetry?.enabled ?? true;
3670
+ const messagingPlatforms = (config?.messaging ?? []).map((m) => m.platform);
3661
3671
  return [
3662
3672
  `storage: ${provider}`,
3663
3673
  `memory tools: ${memoryEnabled ? "enabled" : "disabled"}`,
3664
3674
  `auth: ${authRequired ? "required" : "not required"}`,
3665
- `telemetry: ${telemetryEnabled ? "enabled" : "disabled"}`
3675
+ `telemetry: ${telemetryEnabled ? "enabled" : "disabled"}`,
3676
+ ...messagingPlatforms.length > 0 ? [`messaging: ${messagingPlatforms.join(", ")}`] : []
3666
3677
  ];
3667
3678
  };
3668
3679
  var getOnboardingMarkerPath = async (workingDir) => {
@@ -3738,6 +3749,7 @@ var consumeFirstRunIntro = async (workingDir, input2) => {
3738
3749
  "- **Turn on telemetry**: Track usage with OpenTelemetry/OTLP",
3739
3750
  "- **Add MCP servers**: Connect external tool servers",
3740
3751
  "- **Schedule cron jobs**: Set up recurring tasks in AGENT.md frontmatter",
3752
+ "- **Connect to Slack**: Set up messaging so users can @mention this agent in Slack",
3741
3753
  "",
3742
3754
  "Just let me know what you'd like to work on!\n"
3743
3755
  ].join("\n");
@@ -4181,6 +4193,24 @@ cron:
4181
4193
  - Docker/Fly.io: scheduler runs automatically.
4182
4194
  - Trigger manually: \`curl http://localhost:3000/api/cron/daily-report\`
4183
4195
 
4196
+ ## Messaging (Slack)
4197
+
4198
+ Connect your agent to Slack so it responds to @mentions:
4199
+
4200
+ 1. Create a Slack App at [api.slack.com/apps](https://api.slack.com/apps)
4201
+ 2. Add Bot Token Scopes: \`app_mentions:read\`, \`chat:write\`, \`reactions:write\`
4202
+ 3. Enable Event Subscriptions, set Request URL to \`https://<your-url>/api/messaging/slack\`, subscribe to \`app_mention\`
4203
+ 4. Install to workspace, copy Bot Token and Signing Secret
4204
+ 5. Set env vars:
4205
+ \`\`\`
4206
+ SLACK_BOT_TOKEN=xoxb-...
4207
+ SLACK_SIGNING_SECRET=...
4208
+ \`\`\`
4209
+ 6. Add to \`poncho.config.js\`:
4210
+ \`\`\`javascript
4211
+ messaging: [{ platform: 'slack' }]
4212
+ \`\`\`
4213
+
4184
4214
  ## Deployment
4185
4215
 
4186
4216
  \`\`\`bash
@@ -4883,6 +4913,90 @@ var createRequestHandler = async (options) => {
4883
4913
  workingDir,
4884
4914
  agentId: identity.id
4885
4915
  });
4916
+ const messagingRoutes = /* @__PURE__ */ new Map();
4917
+ const messagingRouteRegistrar = (method, path, routeHandler) => {
4918
+ let byMethod = messagingRoutes.get(path);
4919
+ if (!byMethod) {
4920
+ byMethod = /* @__PURE__ */ new Map();
4921
+ messagingRoutes.set(path, byMethod);
4922
+ }
4923
+ byMethod.set(method, routeHandler);
4924
+ };
4925
+ const messagingRunner = {
4926
+ async getOrCreateConversation(conversationId, meta) {
4927
+ const existing = await conversationStore.get(conversationId);
4928
+ if (existing) {
4929
+ return { messages: existing.messages };
4930
+ }
4931
+ const now = Date.now();
4932
+ const conversation = {
4933
+ conversationId,
4934
+ title: meta.title ?? `${meta.platform} thread`,
4935
+ messages: [],
4936
+ ownerId: meta.ownerId,
4937
+ tenantId: null,
4938
+ createdAt: now,
4939
+ updatedAt: now
4940
+ };
4941
+ await conversationStore.update(conversation);
4942
+ return { messages: [] };
4943
+ },
4944
+ async run(conversationId, input2) {
4945
+ const output = await harness.runToCompletion({
4946
+ task: input2.task,
4947
+ messages: input2.messages
4948
+ });
4949
+ const response = output.result.response ?? "";
4950
+ const conversation = await conversationStore.get(conversationId);
4951
+ if (conversation) {
4952
+ conversation.messages = [
4953
+ ...input2.messages,
4954
+ { role: "user", content: input2.task },
4955
+ { role: "assistant", content: response }
4956
+ ];
4957
+ await conversationStore.update(conversation);
4958
+ }
4959
+ return { response };
4960
+ }
4961
+ };
4962
+ const messagingBridges = [];
4963
+ if (config?.messaging && config.messaging.length > 0) {
4964
+ let waitUntilHook;
4965
+ if (process.env.VERCEL) {
4966
+ try {
4967
+ const modName = "@vercel/functions";
4968
+ const mod = await import(
4969
+ /* webpackIgnore: true */
4970
+ modName
4971
+ );
4972
+ waitUntilHook = mod.waitUntil;
4973
+ } catch {
4974
+ }
4975
+ }
4976
+ for (const channelConfig of config.messaging) {
4977
+ if (channelConfig.platform === "slack") {
4978
+ const adapter = new SlackAdapter({
4979
+ botTokenEnv: channelConfig.botTokenEnv,
4980
+ signingSecretEnv: channelConfig.signingSecretEnv
4981
+ });
4982
+ const bridge = new AgentBridge({
4983
+ adapter,
4984
+ runner: messagingRunner,
4985
+ waitUntil: waitUntilHook
4986
+ });
4987
+ adapter.registerRoutes(messagingRouteRegistrar);
4988
+ try {
4989
+ await bridge.start();
4990
+ messagingBridges.push(bridge);
4991
+ console.log(` Slack messaging enabled at /api/messaging/slack`);
4992
+ } catch (err) {
4993
+ console.warn(
4994
+ ` Slack messaging disabled: ${err instanceof Error ? err.message : String(err)}`
4995
+ );
4996
+ }
4997
+ }
4998
+ }
4999
+ }
4886
5000
  const sessionStore = new SessionStore();
4887
5001
  const loginRateLimiter = new LoginRateLimiter();
4888
5002
  const authToken = process.env.PONCHO_AUTH_TOKEN ?? "";
@@ -4940,6 +5054,14 @@ var createRequestHandler = async (options) => {
4940
5054
  writeJson(response, 200, { status: "ok" });
4941
5055
  return;
4942
5056
  }
5057
+ const messagingByMethod = messagingRoutes.get(pathname ?? "");
5058
+ if (messagingByMethod) {
5059
+ const routeHandler = messagingByMethod.get(request.method ?? "");
5060
+ if (routeHandler) {
5061
+ await routeHandler(request, response);
5062
+ return;
5063
+ }
5064
+ }
4943
5065
  const cookies = parseCookies(request);
4944
5066
  const sessionId = cookies.poncho_session;
4945
5067
  const session = sessionId ? sessionStore.get(sessionId) : void 0;
@@ -6036,7 +6158,7 @@ var runInteractive = async (workingDir, params) => {
6036
6158
  await harness.initialize();
6037
6159
  const identity = await ensureAgentIdentity2(workingDir);
6038
6160
  try {
6039
- const { runInteractiveInk } = await import("./run-interactive-ink-64QEOUXL.js");
6161
+ const { runInteractiveInk } = await import("./run-interactive-ink-VZBOYJYS.js");
6040
6162
  await runInteractiveInk({
6041
6163
  harness,
6042
6164
  params,
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  main
4
- } from "./chunk-XIFWXRUB.js";
4
+ } from "./chunk-CUCEDHME.js";
5
5
 
6
6
  // src/cli.ts
7
7
  void main();
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  runTests,
24
24
  startDevServer,
25
25
  updateAgentGuidance
26
- } from "./chunk-XIFWXRUB.js";
26
+ } from "./chunk-CUCEDHME.js";
27
27
  export {
28
28
  addSkill,
29
29
  buildCli,
@@ -2,7 +2,7 @@ import {
2
2
  consumeFirstRunIntro,
3
3
  inferConversationTitle,
4
4
  resolveHarnessEnvironment
5
- } from "./chunk-XIFWXRUB.js";
5
+ } from "./chunk-CUCEDHME.js";
6
6
 
7
7
  // src/run-interactive-ink.ts
8
8
  import * as readline from "readline";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poncho-ai/cli",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "CLI for building and deploying AI agents",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,8 +27,9 @@
27
27
  "react": "^19.2.4",
28
28
  "react-devtools-core": "^6.1.5",
29
29
  "yaml": "^2.8.1",
30
- "@poncho-ai/harness": "0.13.0",
31
- "@poncho-ai/sdk": "1.0.0"
30
+ "@poncho-ai/messaging": "0.2.0",
31
+ "@poncho-ai/harness": "0.13.1",
32
+ "@poncho-ai/sdk": "1.0.1"
32
33
  },
33
34
  "devDependencies": {
34
35
  "@types/busboy": "^1.5.4",
package/src/index.ts CHANGED
@@ -29,6 +29,13 @@ import {
29
29
  } from "@poncho-ai/harness";
30
30
  import type { AgentEvent, FileInput, Message, RunInput } from "@poncho-ai/sdk";
31
31
  import { getTextContent } from "@poncho-ai/sdk";
32
+ import {
33
+ AgentBridge,
34
+ SlackAdapter,
35
+ type AgentRunner,
36
+ type MessagingAdapter,
37
+ type RouteRegistrar,
38
+ } from "@poncho-ai/messaging";
32
39
  import Busboy from "busboy";
33
40
  import { Command } from "commander";
34
41
  import dotenv from "dotenv";
@@ -567,6 +574,24 @@ cron:
567
574
  - Docker/Fly.io: scheduler runs automatically.
568
575
  - Trigger manually: \`curl http://localhost:3000/api/cron/daily-report\`
569
576
 
577
+ ## Messaging (Slack)
578
+
579
+ Connect your agent to Slack so it responds to @mentions:
580
+
581
+ 1. Create a Slack App at [api.slack.com/apps](https://api.slack.com/apps)
582
+ 2. Add Bot Token Scopes: \`app_mentions:read\`, \`chat:write\`, \`reactions:write\`
583
+ 3. Enable Event Subscriptions, set Request URL to \`https://<your-url>/api/messaging/slack\`, subscribe to \`app_mention\`
584
+ 4. Install to workspace, copy Bot Token and Signing Secret
585
+ 5. Set env vars:
586
+ \`\`\`
587
+ SLACK_BOT_TOKEN=xoxb-...
588
+ SLACK_SIGNING_SECRET=...
589
+ \`\`\`
590
+ 6. Add to \`poncho.config.js\`:
591
+ \`\`\`javascript
592
+ messaging: [{ platform: 'slack' }]
593
+ \`\`\`
594
+
570
595
  ## Deployment
571
596
 
572
597
  \`\`\`bash
@@ -1371,6 +1396,100 @@ export const createRequestHandler = async (options?: {
1371
1396
  workingDir,
1372
1397
  agentId: identity.id,
1373
1398
  });
1399
+ // ---------------------------------------------------------------------------
1400
+ // Messaging adapters (Slack, etc.) — routes bypass Poncho auth; each
1401
+ // adapter handles its own request verification (e.g. Slack signing secret).
1402
+ // ---------------------------------------------------------------------------
1403
+ const messagingRoutes = new Map<string, Map<string, (req: IncomingMessage, res: ServerResponse) => Promise<void>>>();
1404
+ const messagingRouteRegistrar: RouteRegistrar = (method, path, routeHandler) => {
1405
+ let byMethod = messagingRoutes.get(path);
1406
+ if (!byMethod) {
1407
+ byMethod = new Map();
1408
+ messagingRoutes.set(path, byMethod);
1409
+ }
1410
+ byMethod.set(method, routeHandler);
1411
+ };
1412
+
1413
+ const messagingRunner: AgentRunner = {
1414
+ async getOrCreateConversation(conversationId, meta) {
1415
+ const existing = await conversationStore.get(conversationId);
1416
+ if (existing) {
1417
+ return { messages: existing.messages };
1418
+ }
1419
+ const now = Date.now();
1420
+ const conversation = {
1421
+ conversationId,
1422
+ title: meta.title ?? `${meta.platform} thread`,
1423
+ messages: [] as Message[],
1424
+ ownerId: meta.ownerId,
1425
+ tenantId: null,
1426
+ createdAt: now,
1427
+ updatedAt: now,
1428
+ };
1429
+ await conversationStore.update(conversation);
1430
+ return { messages: [] };
1431
+ },
1432
+ async run(conversationId, input) {
1433
+ const output = await harness.runToCompletion({
1434
+ task: input.task,
1435
+ messages: input.messages,
1436
+ });
1437
+ const response = output.result.response ?? "";
1438
+
1439
+ const conversation = await conversationStore.get(conversationId);
1440
+ if (conversation) {
1441
+ conversation.messages = [
1442
+ ...input.messages,
1443
+ { role: "user" as const, content: input.task },
1444
+ { role: "assistant" as const, content: response },
1445
+ ];
1446
+ await conversationStore.update(conversation);
1447
+ }
1448
+
1449
+ return { response };
1450
+ },
1451
+ };
1452
+
1453
+ const messagingBridges: AgentBridge[] = [];
1454
+ if (config?.messaging && config.messaging.length > 0) {
1455
+ let waitUntilHook: ((promise: Promise<unknown>) => void) | undefined;
1456
+ if (process.env.VERCEL) {
1457
+ try {
1458
+ // Dynamic require via variable so TypeScript doesn't attempt static
1459
+ // resolution of @vercel/functions (only present in Vercel deployments).
1460
+ const modName = "@vercel/functions";
1461
+ const mod = await import(/* webpackIgnore: true */ modName);
1462
+ waitUntilHook = mod.waitUntil;
1463
+ } catch {
1464
+ // @vercel/functions not installed -- fall through to no-op.
1465
+ }
1466
+ }
1467
+
1468
+ for (const channelConfig of config.messaging) {
1469
+ if (channelConfig.platform === "slack") {
1470
+ const adapter = new SlackAdapter({
1471
+ botTokenEnv: channelConfig.botTokenEnv,
1472
+ signingSecretEnv: channelConfig.signingSecretEnv,
1473
+ });
1474
+ const bridge = new AgentBridge({
1475
+ adapter,
1476
+ runner: messagingRunner,
1477
+ waitUntil: waitUntilHook,
1478
+ });
1479
+ adapter.registerRoutes(messagingRouteRegistrar);
1480
+ try {
1481
+ await bridge.start();
1482
+ messagingBridges.push(bridge);
1483
+ console.log(` Slack messaging enabled at /api/messaging/slack`);
1484
+ } catch (err) {
1485
+ console.warn(
1486
+ ` Slack messaging disabled: ${err instanceof Error ? err.message : String(err)}`,
1487
+ );
1488
+ }
1489
+ }
1490
+ }
1491
+ }
1492
+
1374
1493
  const sessionStore = new SessionStore();
1375
1494
  const loginRateLimiter = new LoginRateLimiter();
1376
1495
 
@@ -1442,6 +1561,17 @@ export const createRequestHandler = async (options?: {
1442
1561
  return;
1443
1562
  }
1444
1563
 
1564
+ // Messaging adapter routes bypass Poncho auth (they verify requests
1565
+ // using platform-specific mechanisms, e.g. Slack signing secret).
1566
+ const messagingByMethod = messagingRoutes.get(pathname ?? "");
1567
+ if (messagingByMethod) {
1568
+ const routeHandler = messagingByMethod.get(request.method ?? "");
1569
+ if (routeHandler) {
1570
+ await routeHandler(request, response);
1571
+ return;
1572
+ }
1573
+ }
1574
+
1445
1575
  const cookies = parseCookies(request);
1446
1576
  const sessionId = cookies.poncho_session;
1447
1577
  const session = sessionId ? sessionStore.get(sessionId) : undefined;
@@ -29,11 +29,15 @@ const summarizeConfig = (config: PonchoConfig | undefined): string[] => {
29
29
  const memoryEnabled = config?.storage?.memory?.enabled ?? config?.memory?.enabled ?? false;
30
30
  const authRequired = config?.auth?.required ?? false;
31
31
  const telemetryEnabled = config?.telemetry?.enabled ?? true;
32
+ const messagingPlatforms = (config?.messaging ?? []).map((m) => m.platform);
32
33
  return [
33
34
  `storage: ${provider}`,
34
35
  `memory tools: ${memoryEnabled ? "enabled" : "disabled"}`,
35
36
  `auth: ${authRequired ? "required" : "not required"}`,
36
37
  `telemetry: ${telemetryEnabled ? "enabled" : "disabled"}`,
38
+ ...(messagingPlatforms.length > 0
39
+ ? [`messaging: ${messagingPlatforms.join(", ")}`]
40
+ : []),
37
41
  ];
38
42
  };
39
43
 
@@ -127,6 +131,7 @@ export const consumeFirstRunIntro = async (
127
131
  "- **Turn on telemetry**: Track usage with OpenTelemetry/OTLP",
128
132
  "- **Add MCP servers**: Connect external tool servers",
129
133
  "- **Schedule cron jobs**: Set up recurring tasks in AGENT.md frontmatter",
134
+ "- **Connect to Slack**: Set up messaging so users can @mention this agent in Slack",
130
135
  "",
131
136
  "Just let me know what you'd like to work on!\n",
132
137
  ].join("\n");
@@ -339,12 +339,20 @@ export const buildConfigFromOnboardingAnswers = (
339
339
  };
340
340
  maybeSet(telemetry, "otlp", answers["telemetry.otlp"]);
341
341
 
342
- return {
342
+ const messagingPlatform = String(answers["messaging.platform"] ?? "none");
343
+
344
+ const config: PonchoConfig = {
343
345
  mcp: [],
344
346
  auth,
345
347
  storage,
346
348
  telemetry,
347
349
  };
350
+
351
+ if (messagingPlatform !== "none") {
352
+ config.messaging = [{ platform: messagingPlatform as "slack" }];
353
+ }
354
+
355
+ return config;
348
356
  };
349
357
 
350
358
  export const isDefaultOnboardingConfig = (
@@ -354,7 +362,7 @@ export const isDefaultOnboardingConfig = (
354
362
  return true;
355
363
  }
356
364
  const topLevelKeys = Object.keys(config);
357
- const allowedTopLevel = new Set(["mcp", "auth", "storage", "telemetry"]);
365
+ const allowedTopLevel = new Set(["mcp", "auth", "storage", "telemetry", "messaging"]);
358
366
  if (topLevelKeys.some((key) => !allowedTopLevel.has(key))) {
359
367
  return false;
360
368
  }