@poncho-ai/cli 0.30.4 → 0.30.6

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.30.4 build /home/runner/work/poncho-ai/poncho-ai/packages/cli
2
+ > @poncho-ai/cli@0.30.6 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
@@ -9,10 +9,10 @@
9
9
  ESM Build start
10
10
  ESM dist/cli.js 94.00 B
11
11
  ESM dist/index.js 857.00 B
12
- ESM dist/run-interactive-ink-VEUZATR3.js 56.86 KB
13
- ESM dist/chunk-EZUW7UI3.js 491.51 KB
14
- ESM ⚡️ Build success in 62ms
12
+ ESM dist/run-interactive-ink-OX4CI23D.js 56.86 KB
13
+ ESM dist/chunk-3QT2S6AJ.js 492.58 KB
14
+ ESM ⚡️ Build success in 65ms
15
15
  DTS Build start
16
- DTS ⚡️ Build success in 3983ms
16
+ DTS ⚡️ Build success in 4618ms
17
17
  DTS dist/cli.d.ts 20.00 B
18
18
  DTS dist/index.d.ts 4.16 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @poncho-ai/cli
2
2
 
3
+ ## 0.30.6
4
+
5
+ ### Patch Changes
6
+
7
+ - [`56001f5`](https://github.com/cesr/poncho-ai/commit/56001f52f599f013a08e57e5de4891c02ca358d5) Thanks [@cesr](https://github.com/cesr)! - Warn at startup when CRON_SECRET is missing on Vercel with auth enabled and cron jobs configured
8
+
9
+ ## 0.30.5
10
+
11
+ ### Patch Changes
12
+
13
+ - [`031abc7`](https://github.com/cesr/poncho-ai/commit/031abc770b85141da5fdd209c6bf8f594f5552e4) Thanks [@cesr](https://github.com/cesr)! - Fix cron job continuation on serverless
14
+ - Persist \_continuationMessages so cron continuations resume from correct harness state
15
+ - Use selfFetchWithRetry with doWaitUntil instead of raw fetch for cron continuation trigger
16
+ - Extend internal auth bypass to /api/cron/ paths for continuation self-fetch
17
+ - Add startup warning when VERCEL_AUTOMATION_BYPASS_SECRET is missing
18
+
3
19
  ## 0.30.4
4
20
 
5
21
  ### Patch Changes
@@ -9822,6 +9822,18 @@ ${resultBody}`,
9822
9822
  if (waitUntilHook) waitUntilHook(promise);
9823
9823
  };
9824
9824
  const vercelBypassSecret = process.env.VERCEL_AUTOMATION_BYPASS_SECRET?.trim();
9825
+ if (process.env.VERCEL && !vercelBypassSecret) {
9826
+ console.warn(
9827
+ "\n[poncho] Vercel Deployment Protection will block subagents and auto-continuation.\n Enable 'Protection Bypass for Automation' in your Vercel project settings:\n -> Project Settings > Deployment Protection > Protection Bypass for Automation\n The secret is auto-provisioned as VERCEL_AUTOMATION_BYPASS_SECRET.\n"
9828
+ );
9829
+ }
9830
+ const hasCronJobs = Object.keys(cronJobs).length > 0;
9831
+ const authTokenConfigured = !!process.env[config?.auth?.tokenEnv ?? "PONCHO_AUTH_TOKEN"] && (config?.auth?.required ?? false);
9832
+ if (process.env.VERCEL && hasCronJobs && authTokenConfigured && !process.env.CRON_SECRET) {
9833
+ console.warn(
9834
+ "\n[poncho] Cron jobs are configured but CRON_SECRET is not set.\n Vercel sends CRON_SECRET as a Bearer token when invoking cron endpoints.\n Set CRON_SECRET to the same value as PONCHO_AUTH_TOKEN in your Vercel env vars,\n otherwise cron invocations will be rejected with 401.\n"
9835
+ );
9836
+ }
9825
9837
  const selfFetchWithRetry = async (path, body, retries = 3) => {
9826
9838
  if (!selfBaseUrl) {
9827
9839
  console.error(`[poncho][self-fetch] Missing self base URL for ${path}`);
@@ -10320,7 +10332,8 @@ ${resultBody}`,
10320
10332
  return;
10321
10333
  }
10322
10334
  if (pathname.startsWith("/api/")) {
10323
- const isInternal = pathname.startsWith("/api/internal/") && request.method === "POST" && isValidInternalRequest(request.headers);
10335
+ const isInternalPath = pathname.startsWith("/api/internal/") || pathname.startsWith("/api/cron/");
10336
+ const isInternal = isInternalPath && request.method === "POST" && isValidInternalRequest(request.headers);
10324
10337
  const hasBearerToken = request.headers.authorization?.startsWith("Bearer ");
10325
10338
  const isAuthenticated = isInternal || !requireAuth || session || validateBearerToken(request.headers.authorization);
10326
10339
  if (!isAuthenticated) {
@@ -11604,7 +11617,7 @@ ${cronJob.task}`;
11604
11617
  });
11605
11618
  return;
11606
11619
  }
11607
- historyMessages = [...conversation.messages];
11620
+ historyMessages = conversation._continuationMessages?.length ? [...conversation._continuationMessages] : [...conversation.messages];
11608
11621
  } else {
11609
11622
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
11610
11623
  conversation = await conversationStore.create(
@@ -11622,6 +11635,7 @@ ${cronJob.task}`;
11622
11635
  const abortController = new AbortController();
11623
11636
  let assistantResponse = "";
11624
11637
  let latestRunId = "";
11638
+ let runContinuationMessages;
11625
11639
  const toolTimeline = [];
11626
11640
  const sections = [];
11627
11641
  let currentTools = [];
@@ -11680,6 +11694,9 @@ ${cronJob.task}`;
11680
11694
  contextTokens: event.result.contextTokens,
11681
11695
  contextWindow: event.result.contextWindow
11682
11696
  };
11697
+ if (event.result.continuation && event.result.continuationMessages) {
11698
+ runContinuationMessages = event.result.continuationMessages;
11699
+ }
11683
11700
  if (!assistantResponse && event.result.response) {
11684
11701
  assistantResponse = event.result.response;
11685
11702
  }
@@ -11707,37 +11724,30 @@ ${cronJob.task}`;
11707
11724
  ];
11708
11725
  const freshConv = await conversationStore.get(convId);
11709
11726
  if (freshConv) {
11710
- freshConv.messages = messages;
11727
+ if (runContinuationMessages) {
11728
+ freshConv._continuationMessages = runContinuationMessages;
11729
+ } else {
11730
+ freshConv._continuationMessages = void 0;
11731
+ freshConv.messages = messages;
11732
+ }
11711
11733
  freshConv.runtimeRunId = latestRunId || freshConv.runtimeRunId;
11712
11734
  if (runResult.contextTokens) freshConv.contextTokens = runResult.contextTokens;
11713
11735
  if (runResult.contextWindow) freshConv.contextWindow = runResult.contextWindow;
11714
11736
  freshConv.updatedAt = Date.now();
11715
11737
  await conversationStore.update(freshConv);
11716
11738
  }
11717
- if (runResult.continuation && softDeadlineMs > 0) {
11718
- const selfUrl = `http://${request.headers.host ?? "localhost"}${pathname}?continue=${encodeURIComponent(convId)}&continuation=${continuationCount + 1}`;
11719
- try {
11720
- const selfRes = await fetch(selfUrl, {
11721
- method: "GET",
11722
- headers: request.headers.authorization ? { authorization: request.headers.authorization } : {}
11723
- });
11724
- const selfBody = await selfRes.json();
11725
- writeJson(response, 200, {
11726
- conversationId: convId,
11727
- status: "continued",
11728
- continuations: continuationCount + 1,
11729
- finalResult: selfBody,
11730
- duration: Date.now() - start
11731
- });
11732
- } catch (continueError) {
11733
- writeJson(response, 200, {
11734
- conversationId: convId,
11735
- status: "continuation_failed",
11736
- error: continueError instanceof Error ? continueError.message : "Unknown error",
11737
- duration: Date.now() - start,
11738
- steps: runResult.steps
11739
- });
11740
- }
11739
+ if (runResult.continuation) {
11740
+ const continuationPath = `/api/cron/${encodeURIComponent(jobName)}?continue=${encodeURIComponent(convId)}&continuation=${continuationCount + 1}`;
11741
+ const work = selfFetchWithRetry(continuationPath).catch(
11742
+ (err) => console.error(`[poncho][cron] Continuation self-fetch failed:`, err instanceof Error ? err.message : err)
11743
+ );
11744
+ doWaitUntil(work);
11745
+ writeJson(response, 200, {
11746
+ conversationId: convId,
11747
+ status: "continued",
11748
+ continuations: continuationCount + 1,
11749
+ duration: Date.now() - start
11750
+ });
11741
11751
  return;
11742
11752
  }
11743
11753
  writeJson(response, 200, {
@@ -12183,7 +12193,7 @@ var runInteractive = async (workingDir, params) => {
12183
12193
  await harness.initialize();
12184
12194
  const identity = await ensureAgentIdentity2(workingDir);
12185
12195
  try {
12186
- const { runInteractiveInk } = await import("./run-interactive-ink-VEUZATR3.js");
12196
+ const { runInteractiveInk } = await import("./run-interactive-ink-OX4CI23D.js");
12187
12197
  await runInteractiveInk({
12188
12198
  harness,
12189
12199
  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-EZUW7UI3.js";
4
+ } from "./chunk-3QT2S6AJ.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-EZUW7UI3.js";
26
+ } from "./chunk-3QT2S6AJ.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-EZUW7UI3.js";
5
+ } from "./chunk-3QT2S6AJ.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.30.4",
3
+ "version": "0.30.6",
4
4
  "description": "CLI for building and deploying AI agents",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,9 +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.28.3",
30
31
  "@poncho-ai/messaging": "0.7.2",
31
- "@poncho-ai/sdk": "1.6.1",
32
- "@poncho-ai/harness": "0.28.3"
32
+ "@poncho-ai/sdk": "1.6.1"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/busboy": "^1.5.4",
package/src/index.ts CHANGED
@@ -3075,6 +3075,24 @@ export const createRequestHandler = async (options?: {
3075
3075
  };
3076
3076
 
3077
3077
  const vercelBypassSecret = process.env.VERCEL_AUTOMATION_BYPASS_SECRET?.trim();
3078
+ if (process.env.VERCEL && !vercelBypassSecret) {
3079
+ console.warn(
3080
+ "\n[poncho] Vercel Deployment Protection will block subagents and auto-continuation." +
3081
+ "\n Enable 'Protection Bypass for Automation' in your Vercel project settings:" +
3082
+ "\n -> Project Settings > Deployment Protection > Protection Bypass for Automation" +
3083
+ "\n The secret is auto-provisioned as VERCEL_AUTOMATION_BYPASS_SECRET.\n",
3084
+ );
3085
+ }
3086
+ const hasCronJobs = Object.keys(cronJobs).length > 0;
3087
+ const authTokenConfigured = !!(process.env[config?.auth?.tokenEnv ?? "PONCHO_AUTH_TOKEN"]) && (config?.auth?.required ?? false);
3088
+ if (process.env.VERCEL && hasCronJobs && authTokenConfigured && !process.env.CRON_SECRET) {
3089
+ console.warn(
3090
+ "\n[poncho] Cron jobs are configured but CRON_SECRET is not set." +
3091
+ "\n Vercel sends CRON_SECRET as a Bearer token when invoking cron endpoints." +
3092
+ "\n Set CRON_SECRET to the same value as PONCHO_AUTH_TOKEN in your Vercel env vars," +
3093
+ "\n otherwise cron invocations will be rejected with 401.\n",
3094
+ );
3095
+ }
3078
3096
 
3079
3097
  const selfFetchWithRetry = async (path: string, body?: Record<string, unknown>, retries = 3): Promise<Response | void> => {
3080
3098
  if (!selfBaseUrl) {
@@ -3647,7 +3665,8 @@ export const createRequestHandler = async (options?: {
3647
3665
 
3648
3666
  if (pathname.startsWith("/api/")) {
3649
3667
  // Internal self-fetch requests bypass user-facing auth
3650
- const isInternal = pathname.startsWith("/api/internal/") && request.method === "POST" && isValidInternalRequest(request.headers);
3668
+ const isInternalPath = pathname.startsWith("/api/internal/") || pathname.startsWith("/api/cron/");
3669
+ const isInternal = isInternalPath && request.method === "POST" && isValidInternalRequest(request.headers);
3651
3670
 
3652
3671
  // Check authentication: either valid session (Web UI), valid Bearer token (API), or valid internal request
3653
3672
  const hasBearerToken = request.headers.authorization?.startsWith("Bearer ");
@@ -5110,7 +5129,9 @@ export const createRequestHandler = async (options?: {
5110
5129
  });
5111
5130
  return;
5112
5131
  }
5113
- historyMessages = [...conversation.messages];
5132
+ historyMessages = conversation._continuationMessages?.length
5133
+ ? [...conversation._continuationMessages]
5134
+ : [...conversation.messages];
5114
5135
  } else {
5115
5136
  const timestamp = new Date().toISOString();
5116
5137
  conversation = await conversationStore.create(
@@ -5130,6 +5151,7 @@ export const createRequestHandler = async (options?: {
5130
5151
  const abortController = new AbortController();
5131
5152
  let assistantResponse = "";
5132
5153
  let latestRunId = "";
5154
+ let runContinuationMessages: Message[] | undefined;
5133
5155
  const toolTimeline: string[] = [];
5134
5156
  const sections: Array<{ type: "text" | "tools"; content: string | string[] }> = [];
5135
5157
  let currentTools: string[] = [];
@@ -5192,6 +5214,9 @@ export const createRequestHandler = async (options?: {
5192
5214
  contextTokens: event.result.contextTokens,
5193
5215
  contextWindow: event.result.contextWindow,
5194
5216
  };
5217
+ if (event.result.continuation && event.result.continuationMessages) {
5218
+ runContinuationMessages = event.result.continuationMessages;
5219
+ }
5195
5220
  if (!assistantResponse && event.result.response) {
5196
5221
  assistantResponse = event.result.response;
5197
5222
  }
@@ -5231,7 +5256,12 @@ export const createRequestHandler = async (options?: {
5231
5256
  ];
5232
5257
  const freshConv = await conversationStore.get(convId);
5233
5258
  if (freshConv) {
5234
- freshConv.messages = messages;
5259
+ if (runContinuationMessages) {
5260
+ freshConv._continuationMessages = runContinuationMessages;
5261
+ } else {
5262
+ freshConv._continuationMessages = undefined;
5263
+ freshConv.messages = messages;
5264
+ }
5235
5265
  freshConv.runtimeRunId = latestRunId || freshConv.runtimeRunId;
5236
5266
  if (runResult.contextTokens) freshConv.contextTokens = runResult.contextTokens;
5237
5267
  if (runResult.contextWindow) freshConv.contextWindow = runResult.contextWindow;
@@ -5239,33 +5269,18 @@ export const createRequestHandler = async (options?: {
5239
5269
  await conversationStore.update(freshConv);
5240
5270
  }
5241
5271
 
5242
- // Self-continuation for serverless timeouts
5243
- if (runResult.continuation && softDeadlineMs > 0) {
5244
- const selfUrl = `http://${request.headers.host ?? "localhost"}${pathname}?continue=${encodeURIComponent(convId)}&continuation=${continuationCount + 1}`;
5245
- try {
5246
- const selfRes = await fetch(selfUrl, {
5247
- method: "GET",
5248
- headers: request.headers.authorization
5249
- ? { authorization: request.headers.authorization }
5250
- : {},
5251
- });
5252
- const selfBody = await selfRes.json() as Record<string, unknown>;
5253
- writeJson(response, 200, {
5254
- conversationId: convId,
5255
- status: "continued",
5256
- continuations: continuationCount + 1,
5257
- finalResult: selfBody,
5258
- duration: Date.now() - start,
5259
- });
5260
- } catch (continueError) {
5261
- writeJson(response, 200, {
5262
- conversationId: convId,
5263
- status: "continuation_failed",
5264
- error: continueError instanceof Error ? continueError.message : "Unknown error",
5265
- duration: Date.now() - start,
5266
- steps: runResult.steps,
5267
- });
5268
- }
5272
+ if (runResult.continuation) {
5273
+ const continuationPath = `/api/cron/${encodeURIComponent(jobName)}?continue=${encodeURIComponent(convId)}&continuation=${continuationCount + 1}`;
5274
+ const work = selfFetchWithRetry(continuationPath).catch(err =>
5275
+ console.error(`[poncho][cron] Continuation self-fetch failed:`, err instanceof Error ? err.message : err),
5276
+ );
5277
+ doWaitUntil(work);
5278
+ writeJson(response, 200, {
5279
+ conversationId: convId,
5280
+ status: "continued",
5281
+ continuations: continuationCount + 1,
5282
+ duration: Date.now() - start,
5283
+ });
5269
5284
  return;
5270
5285
  }
5271
5286