@poncho-ai/cli 0.30.3 → 0.30.5

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.3 build /home/runner/work/poncho-ai/poncho-ai/packages/cli
2
+ > @poncho-ai/cli@0.30.5 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-FUMHN6DS.js 56.86 KB
13
- ESM dist/chunk-FA546WPW.js 490.84 KB
14
- ESM ⚡️ Build success in 63ms
12
+ ESM dist/run-interactive-ink-KA5V5BSJ.js 56.86 KB
13
+ ESM dist/chunk-V3H773RB.js 492.00 KB
14
+ ESM ⚡️ Build success in 62ms
15
15
  DTS Build start
16
- DTS ⚡️ Build success in 3898ms
16
+ DTS ⚡️ Build success in 4158ms
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,24 @@
1
1
  # @poncho-ai/cli
2
2
 
3
+ ## 0.30.5
4
+
5
+ ### Patch Changes
6
+
7
+ - [`031abc7`](https://github.com/cesr/poncho-ai/commit/031abc770b85141da5fdd209c6bf8f594f5552e4) Thanks [@cesr](https://github.com/cesr)! - Fix cron job continuation on serverless
8
+ - Persist \_continuationMessages so cron continuations resume from correct harness state
9
+ - Use selfFetchWithRetry with doWaitUntil instead of raw fetch for cron continuation trigger
10
+ - Extend internal auth bypass to /api/cron/ paths for continuation self-fetch
11
+ - Add startup warning when VERCEL_AUTOMATION_BYPASS_SECRET is missing
12
+
13
+ ## 0.30.4
14
+
15
+ ### Patch Changes
16
+
17
+ - [`ea8b5da`](https://github.com/cesr/poncho-ai/commit/ea8b5da1bca5d45c05a68a43c4850aacee612ffb) Thanks [@cesr](https://github.com/cesr)! - Fix internal self-fetch blocked by Vercel Deployment Protection and PONCHO_AUTH_TOKEN
18
+ - Include x-vercel-protection-bypass header when VERCEL_AUTOMATION_BYPASS_SECRET is set
19
+ - Internal requests with valid x-poncho-internal header bypass the PONCHO_AUTH_TOKEN auth gate
20
+ - Better error messages distinguishing Vercel Deployment Protection from internal auth failures
21
+
3
22
  ## 0.30.3
4
23
 
5
24
  ### Patch Changes
@@ -9821,6 +9821,12 @@ ${resultBody}`,
9821
9821
  const doWaitUntil = (promise) => {
9822
9822
  if (waitUntilHook) waitUntilHook(promise);
9823
9823
  };
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
+ }
9824
9830
  const selfFetchWithRetry = async (path, body, retries = 3) => {
9825
9831
  if (!selfBaseUrl) {
9826
9832
  console.error(`[poncho][self-fetch] Missing self base URL for ${path}`);
@@ -9829,12 +9835,16 @@ ${resultBody}`,
9829
9835
  let lastError;
9830
9836
  for (let attempt = 0; attempt < retries; attempt++) {
9831
9837
  try {
9838
+ const headers = {
9839
+ "Content-Type": "application/json",
9840
+ "x-poncho-internal": internalSecret
9841
+ };
9842
+ if (vercelBypassSecret) {
9843
+ headers["x-vercel-protection-bypass"] = vercelBypassSecret;
9844
+ }
9832
9845
  const result = await fetch(`${selfBaseUrl}${path}`, {
9833
9846
  method: "POST",
9834
- headers: {
9835
- "Content-Type": "application/json",
9836
- "x-poncho-internal": internalSecret
9837
- },
9847
+ headers,
9838
9848
  body: body ? JSON.stringify(body) : void 0
9839
9849
  });
9840
9850
  if (result.ok) {
@@ -9858,9 +9868,15 @@ ${resultBody}`,
9858
9868
  lastError instanceof Error ? lastError.message : String(lastError)
9859
9869
  );
9860
9870
  if (lastError instanceof Error && (lastError.message.includes("HTTP 403") || lastError.message.includes("HTTP 401"))) {
9861
- console.error(
9862
- "[poncho][self-fetch] Internal auth failed. Ensure all serverless instances share PONCHO_INTERNAL_SECRET."
9863
- );
9871
+ if (lastError.message.includes("HTTP 401") && lastError.message.includes("<!doctype")) {
9872
+ console.error(
9873
+ "[poncho][self-fetch] Blocked by Vercel Deployment Protection. Set VERCEL_AUTOMATION_BYPASS_SECRET in your Vercel project settings and env vars."
9874
+ );
9875
+ } else {
9876
+ console.error(
9877
+ "[poncho][self-fetch] Internal auth failed. Ensure all serverless instances share PONCHO_INTERNAL_SECRET."
9878
+ );
9879
+ }
9864
9880
  }
9865
9881
  } else {
9866
9882
  console.error(`[poncho][self-fetch] Failed ${path} after ${retries} attempt(s).`);
@@ -10309,8 +10325,10 @@ ${resultBody}`,
10309
10325
  return;
10310
10326
  }
10311
10327
  if (pathname.startsWith("/api/")) {
10328
+ const isInternalPath = pathname.startsWith("/api/internal/") || pathname.startsWith("/api/cron/");
10329
+ const isInternal = isInternalPath && request.method === "POST" && isValidInternalRequest(request.headers);
10312
10330
  const hasBearerToken = request.headers.authorization?.startsWith("Bearer ");
10313
- const isAuthenticated = !requireAuth || session || validateBearerToken(request.headers.authorization);
10331
+ const isAuthenticated = isInternal || !requireAuth || session || validateBearerToken(request.headers.authorization);
10314
10332
  if (!isAuthenticated) {
10315
10333
  writeJson(response, 401, {
10316
10334
  code: "AUTH_ERROR",
@@ -11592,7 +11610,7 @@ ${cronJob.task}`;
11592
11610
  });
11593
11611
  return;
11594
11612
  }
11595
- historyMessages = [...conversation.messages];
11613
+ historyMessages = conversation._continuationMessages?.length ? [...conversation._continuationMessages] : [...conversation.messages];
11596
11614
  } else {
11597
11615
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
11598
11616
  conversation = await conversationStore.create(
@@ -11610,6 +11628,7 @@ ${cronJob.task}`;
11610
11628
  const abortController = new AbortController();
11611
11629
  let assistantResponse = "";
11612
11630
  let latestRunId = "";
11631
+ let runContinuationMessages;
11613
11632
  const toolTimeline = [];
11614
11633
  const sections = [];
11615
11634
  let currentTools = [];
@@ -11668,6 +11687,9 @@ ${cronJob.task}`;
11668
11687
  contextTokens: event.result.contextTokens,
11669
11688
  contextWindow: event.result.contextWindow
11670
11689
  };
11690
+ if (event.result.continuation && event.result.continuationMessages) {
11691
+ runContinuationMessages = event.result.continuationMessages;
11692
+ }
11671
11693
  if (!assistantResponse && event.result.response) {
11672
11694
  assistantResponse = event.result.response;
11673
11695
  }
@@ -11695,37 +11717,30 @@ ${cronJob.task}`;
11695
11717
  ];
11696
11718
  const freshConv = await conversationStore.get(convId);
11697
11719
  if (freshConv) {
11698
- freshConv.messages = messages;
11720
+ if (runContinuationMessages) {
11721
+ freshConv._continuationMessages = runContinuationMessages;
11722
+ } else {
11723
+ freshConv._continuationMessages = void 0;
11724
+ freshConv.messages = messages;
11725
+ }
11699
11726
  freshConv.runtimeRunId = latestRunId || freshConv.runtimeRunId;
11700
11727
  if (runResult.contextTokens) freshConv.contextTokens = runResult.contextTokens;
11701
11728
  if (runResult.contextWindow) freshConv.contextWindow = runResult.contextWindow;
11702
11729
  freshConv.updatedAt = Date.now();
11703
11730
  await conversationStore.update(freshConv);
11704
11731
  }
11705
- if (runResult.continuation && softDeadlineMs > 0) {
11706
- const selfUrl = `http://${request.headers.host ?? "localhost"}${pathname}?continue=${encodeURIComponent(convId)}&continuation=${continuationCount + 1}`;
11707
- try {
11708
- const selfRes = await fetch(selfUrl, {
11709
- method: "GET",
11710
- headers: request.headers.authorization ? { authorization: request.headers.authorization } : {}
11711
- });
11712
- const selfBody = await selfRes.json();
11713
- writeJson(response, 200, {
11714
- conversationId: convId,
11715
- status: "continued",
11716
- continuations: continuationCount + 1,
11717
- finalResult: selfBody,
11718
- duration: Date.now() - start
11719
- });
11720
- } catch (continueError) {
11721
- writeJson(response, 200, {
11722
- conversationId: convId,
11723
- status: "continuation_failed",
11724
- error: continueError instanceof Error ? continueError.message : "Unknown error",
11725
- duration: Date.now() - start,
11726
- steps: runResult.steps
11727
- });
11728
- }
11732
+ if (runResult.continuation) {
11733
+ const continuationPath = `/api/cron/${encodeURIComponent(jobName)}?continue=${encodeURIComponent(convId)}&continuation=${continuationCount + 1}`;
11734
+ const work = selfFetchWithRetry(continuationPath).catch(
11735
+ (err) => console.error(`[poncho][cron] Continuation self-fetch failed:`, err instanceof Error ? err.message : err)
11736
+ );
11737
+ doWaitUntil(work);
11738
+ writeJson(response, 200, {
11739
+ conversationId: convId,
11740
+ status: "continued",
11741
+ continuations: continuationCount + 1,
11742
+ duration: Date.now() - start
11743
+ });
11729
11744
  return;
11730
11745
  }
11731
11746
  writeJson(response, 200, {
@@ -12171,7 +12186,7 @@ var runInteractive = async (workingDir, params) => {
12171
12186
  await harness.initialize();
12172
12187
  const identity = await ensureAgentIdentity2(workingDir);
12173
12188
  try {
12174
- const { runInteractiveInk } = await import("./run-interactive-ink-FUMHN6DS.js");
12189
+ const { runInteractiveInk } = await import("./run-interactive-ink-KA5V5BSJ.js");
12175
12190
  await runInteractiveInk({
12176
12191
  harness,
12177
12192
  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-FA546WPW.js";
4
+ } from "./chunk-V3H773RB.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-FA546WPW.js";
26
+ } from "./chunk-V3H773RB.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-FA546WPW.js";
5
+ } from "./chunk-V3H773RB.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.3",
3
+ "version": "0.30.5",
4
4
  "description": "CLI for building and deploying AI agents",
5
5
  "repository": {
6
6
  "type": "git",
package/src/index.ts CHANGED
@@ -3074,6 +3074,16 @@ export const createRequestHandler = async (options?: {
3074
3074
  if (waitUntilHook) waitUntilHook(promise);
3075
3075
  };
3076
3076
 
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
+
3077
3087
  const selfFetchWithRetry = async (path: string, body?: Record<string, unknown>, retries = 3): Promise<Response | void> => {
3078
3088
  if (!selfBaseUrl) {
3079
3089
  console.error(`[poncho][self-fetch] Missing self base URL for ${path}`);
@@ -3082,12 +3092,16 @@ export const createRequestHandler = async (options?: {
3082
3092
  let lastError: unknown;
3083
3093
  for (let attempt = 0; attempt < retries; attempt++) {
3084
3094
  try {
3095
+ const headers: Record<string, string> = {
3096
+ "Content-Type": "application/json",
3097
+ "x-poncho-internal": internalSecret,
3098
+ };
3099
+ if (vercelBypassSecret) {
3100
+ headers["x-vercel-protection-bypass"] = vercelBypassSecret;
3101
+ }
3085
3102
  const result = await fetch(`${selfBaseUrl}${path}`, {
3086
3103
  method: "POST",
3087
- headers: {
3088
- "Content-Type": "application/json",
3089
- "x-poncho-internal": internalSecret,
3090
- },
3104
+ headers,
3091
3105
  body: body ? JSON.stringify(body) : undefined,
3092
3106
  });
3093
3107
  if (result.ok) {
@@ -3114,9 +3128,15 @@ export const createRequestHandler = async (options?: {
3114
3128
  lastError instanceof Error
3115
3129
  && (lastError.message.includes("HTTP 403") || lastError.message.includes("HTTP 401"))
3116
3130
  ) {
3117
- console.error(
3118
- "[poncho][self-fetch] Internal auth failed. Ensure all serverless instances share PONCHO_INTERNAL_SECRET.",
3119
- );
3131
+ if (lastError.message.includes("HTTP 401") && lastError.message.includes("<!doctype")) {
3132
+ console.error(
3133
+ "[poncho][self-fetch] Blocked by Vercel Deployment Protection. Set VERCEL_AUTOMATION_BYPASS_SECRET in your Vercel project settings and env vars.",
3134
+ );
3135
+ } else {
3136
+ console.error(
3137
+ "[poncho][self-fetch] Internal auth failed. Ensure all serverless instances share PONCHO_INTERNAL_SECRET.",
3138
+ );
3139
+ }
3120
3140
  }
3121
3141
  } else {
3122
3142
  console.error(`[poncho][self-fetch] Failed ${path} after ${retries} attempt(s).`);
@@ -3634,9 +3654,13 @@ export const createRequestHandler = async (options?: {
3634
3654
  }
3635
3655
 
3636
3656
  if (pathname.startsWith("/api/")) {
3637
- // Check authentication: either valid session (Web UI) or valid Bearer token (API)
3657
+ // Internal self-fetch requests bypass user-facing auth
3658
+ const isInternalPath = pathname.startsWith("/api/internal/") || pathname.startsWith("/api/cron/");
3659
+ const isInternal = isInternalPath && request.method === "POST" && isValidInternalRequest(request.headers);
3660
+
3661
+ // Check authentication: either valid session (Web UI), valid Bearer token (API), or valid internal request
3638
3662
  const hasBearerToken = request.headers.authorization?.startsWith("Bearer ");
3639
- const isAuthenticated = !requireAuth || session || validateBearerToken(request.headers.authorization);
3663
+ const isAuthenticated = isInternal || !requireAuth || session || validateBearerToken(request.headers.authorization);
3640
3664
 
3641
3665
  if (!isAuthenticated) {
3642
3666
  writeJson(response, 401, {
@@ -5095,7 +5119,9 @@ export const createRequestHandler = async (options?: {
5095
5119
  });
5096
5120
  return;
5097
5121
  }
5098
- historyMessages = [...conversation.messages];
5122
+ historyMessages = conversation._continuationMessages?.length
5123
+ ? [...conversation._continuationMessages]
5124
+ : [...conversation.messages];
5099
5125
  } else {
5100
5126
  const timestamp = new Date().toISOString();
5101
5127
  conversation = await conversationStore.create(
@@ -5115,6 +5141,7 @@ export const createRequestHandler = async (options?: {
5115
5141
  const abortController = new AbortController();
5116
5142
  let assistantResponse = "";
5117
5143
  let latestRunId = "";
5144
+ let runContinuationMessages: Message[] | undefined;
5118
5145
  const toolTimeline: string[] = [];
5119
5146
  const sections: Array<{ type: "text" | "tools"; content: string | string[] }> = [];
5120
5147
  let currentTools: string[] = [];
@@ -5177,6 +5204,9 @@ export const createRequestHandler = async (options?: {
5177
5204
  contextTokens: event.result.contextTokens,
5178
5205
  contextWindow: event.result.contextWindow,
5179
5206
  };
5207
+ if (event.result.continuation && event.result.continuationMessages) {
5208
+ runContinuationMessages = event.result.continuationMessages;
5209
+ }
5180
5210
  if (!assistantResponse && event.result.response) {
5181
5211
  assistantResponse = event.result.response;
5182
5212
  }
@@ -5216,7 +5246,12 @@ export const createRequestHandler = async (options?: {
5216
5246
  ];
5217
5247
  const freshConv = await conversationStore.get(convId);
5218
5248
  if (freshConv) {
5219
- freshConv.messages = messages;
5249
+ if (runContinuationMessages) {
5250
+ freshConv._continuationMessages = runContinuationMessages;
5251
+ } else {
5252
+ freshConv._continuationMessages = undefined;
5253
+ freshConv.messages = messages;
5254
+ }
5220
5255
  freshConv.runtimeRunId = latestRunId || freshConv.runtimeRunId;
5221
5256
  if (runResult.contextTokens) freshConv.contextTokens = runResult.contextTokens;
5222
5257
  if (runResult.contextWindow) freshConv.contextWindow = runResult.contextWindow;
@@ -5224,33 +5259,18 @@ export const createRequestHandler = async (options?: {
5224
5259
  await conversationStore.update(freshConv);
5225
5260
  }
5226
5261
 
5227
- // Self-continuation for serverless timeouts
5228
- if (runResult.continuation && softDeadlineMs > 0) {
5229
- const selfUrl = `http://${request.headers.host ?? "localhost"}${pathname}?continue=${encodeURIComponent(convId)}&continuation=${continuationCount + 1}`;
5230
- try {
5231
- const selfRes = await fetch(selfUrl, {
5232
- method: "GET",
5233
- headers: request.headers.authorization
5234
- ? { authorization: request.headers.authorization }
5235
- : {},
5236
- });
5237
- const selfBody = await selfRes.json() as Record<string, unknown>;
5238
- writeJson(response, 200, {
5239
- conversationId: convId,
5240
- status: "continued",
5241
- continuations: continuationCount + 1,
5242
- finalResult: selfBody,
5243
- duration: Date.now() - start,
5244
- });
5245
- } catch (continueError) {
5246
- writeJson(response, 200, {
5247
- conversationId: convId,
5248
- status: "continuation_failed",
5249
- error: continueError instanceof Error ? continueError.message : "Unknown error",
5250
- duration: Date.now() - start,
5251
- steps: runResult.steps,
5252
- });
5253
- }
5262
+ if (runResult.continuation) {
5263
+ const continuationPath = `/api/cron/${encodeURIComponent(jobName)}?continue=${encodeURIComponent(convId)}&continuation=${continuationCount + 1}`;
5264
+ const work = selfFetchWithRetry(continuationPath).catch(err =>
5265
+ console.error(`[poncho][cron] Continuation self-fetch failed:`, err instanceof Error ? err.message : err),
5266
+ );
5267
+ doWaitUntil(work);
5268
+ writeJson(response, 200, {
5269
+ conversationId: convId,
5270
+ status: "continued",
5271
+ continuations: continuationCount + 1,
5272
+ duration: Date.now() - start,
5273
+ });
5254
5274
  return;
5255
5275
  }
5256
5276