@poncho-ai/cli 0.11.1 → 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.
@@ -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
 
@@ -126,6 +130,8 @@ export const consumeFirstRunIntro = async (
126
130
  "- **Enable auth**: Add bearer tokens or custom authentication",
127
131
  "- **Turn on telemetry**: Track usage with OpenTelemetry/OTLP",
128
132
  "- **Add MCP servers**: Connect external tool servers",
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",
129
135
  "",
130
136
  "Just let me know what you'd like to work on!\n",
131
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
  }
package/test/cli.test.ts CHANGED
@@ -11,7 +11,10 @@ import {
11
11
  initializeOnboardingMarker,
12
12
  } from "../src/init-feature-context.js";
13
13
 
14
- vi.mock("@poncho-ai/harness", () => ({
14
+ vi.mock("@poncho-ai/harness", async (importOriginal) => {
15
+ const actual = await importOriginal<typeof import("@poncho-ai/harness")>();
16
+ return {
17
+ parseAgentMarkdown: actual.parseAgentMarkdown,
15
18
  AgentHarness: class MockHarness {
16
19
  async initialize(): Promise<void> {}
17
20
  listTools(): Array<{ name: string; description: string }> {
@@ -160,7 +163,7 @@ vi.mock("@poncho-ai/harness", () => ({
160
163
  get: async () => Buffer.from(""),
161
164
  delete: async () => {},
162
165
  }),
163
- }));
166
+ };});
164
167
 
165
168
  import {
166
169
  buildTarget,
@@ -920,6 +923,43 @@ describe("cli", () => {
920
923
  expect(result.failed).toBe(0);
921
924
  });
922
925
 
926
+ it("includes crons in vercel.json when AGENT.md has cron jobs", async () => {
927
+ await initProject("cron-agent", { workingDir: tempDir });
928
+ const projectDir = join(tempDir, "cron-agent");
929
+ const agentMdPath = join(projectDir, "AGENT.md");
930
+ const agentMd = await readFile(agentMdPath, "utf8");
931
+ // Insert cron block before the closing --- of frontmatter
932
+ const updatedAgentMd = agentMd.replace(
933
+ /^(---\n[\s\S]*?)(---\n)/m,
934
+ `$1cron:\n daily-report:\n schedule: "0 9 * * *"\n task: "Generate the daily report"\n health-check:\n schedule: "*/30 * * * *"\n task: "Check all APIs"\n$2`,
935
+ );
936
+ await writeFile(agentMdPath, updatedAgentMd, "utf8");
937
+ await buildTarget(projectDir, "vercel", { force: true });
938
+ const vercelConfig = JSON.parse(
939
+ await readFile(join(projectDir, "vercel.json"), "utf8"),
940
+ ) as { crons?: Array<{ path: string; schedule: string }> };
941
+ expect(vercelConfig.crons).toBeDefined();
942
+ expect(vercelConfig.crons).toHaveLength(2);
943
+ expect(vercelConfig.crons).toContainEqual({
944
+ path: "/api/cron/daily-report",
945
+ schedule: "0 9 * * *",
946
+ });
947
+ expect(vercelConfig.crons).toContainEqual({
948
+ path: "/api/cron/health-check",
949
+ schedule: "*/30 * * * *",
950
+ });
951
+ });
952
+
953
+ it("omits crons from vercel.json when AGENT.md has no cron jobs", async () => {
954
+ await initProject("no-cron-agent", { workingDir: tempDir });
955
+ const projectDir = join(tempDir, "no-cron-agent");
956
+ await buildTarget(projectDir, "vercel", { force: true });
957
+ const vercelConfig = JSON.parse(
958
+ await readFile(join(projectDir, "vercel.json"), "utf8"),
959
+ ) as { crons?: unknown };
960
+ expect(vercelConfig.crons).toBeUndefined();
961
+ });
962
+
923
963
  it("fails on existing deploy files unless force is enabled", async () => {
924
964
  await initProject("collision-agent", { workingDir: tempDir });
925
965
  const projectDir = join(tempDir, "collision-agent");