@poncho-ai/cli 0.18.0 → 0.19.1

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/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  main
4
- } from "./chunk-ETZ3YKFP.js";
4
+ } from "./chunk-7P53QSP5.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-ETZ3YKFP.js";
26
+ } from "./chunk-7P53QSP5.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-ETZ3YKFP.js";
5
+ } from "./chunk-7P53QSP5.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.18.0",
3
+ "version": "0.19.1",
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.18.0",
31
- "@poncho-ai/messaging": "0.2.6",
32
- "@poncho-ai/sdk": "1.3.0"
30
+ "@poncho-ai/harness": "0.19.1",
31
+ "@poncho-ai/sdk": "1.4.0",
32
+ "@poncho-ai/messaging": "0.2.7"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/busboy": "^1.5.4",
package/src/index.ts CHANGED
@@ -545,11 +545,17 @@ export default {
545
545
  ],
546
546
  // Tool access: true (available), false (disabled), 'approval' (requires human approval)
547
547
  tools: {
548
+ list_directory: true,
549
+ read_file: true,
548
550
  write_file: true, // gated by environment for writes
551
+ delete_file: 'approval', // requires human approval
552
+ delete_directory: 'approval', // requires human approval
549
553
  send_email: 'approval', // requires human approval
550
554
  byEnvironment: {
551
555
  production: {
552
556
  write_file: false,
557
+ delete_file: false,
558
+ delete_directory: false,
553
559
  },
554
560
  development: {
555
561
  send_email: true, // skip approval in dev
@@ -632,6 +638,7 @@ Connect your agent to email so users can interact by sending emails:
632
638
  RESEND_API_KEY=re_...
633
639
  RESEND_WEBHOOK_SECRET=whsec_...
634
640
  RESEND_FROM=Agent <agent@yourdomain.com>
641
+ RESEND_REPLY_TO=support@yourdomain.com # optional
635
642
  \`\`\`
636
643
  5. Add to \`poncho.config.js\`:
637
644
  \`\`\`javascript
@@ -1463,7 +1470,7 @@ export const createRequestHandler = async (options?: {
1463
1470
  // Pending subagent approvals: when a subagent hits an approval checkpoint,
1464
1471
  // we store a resolver here so the approval endpoint can signal the waiting runSubagent.
1465
1472
  type PendingSubagentApproval = {
1466
- resolve: (approved: boolean) => void;
1473
+ resolve: (decidedApprovals: NonNullable<Conversation["pendingApprovals"]>) => void;
1467
1474
  childHarness: AgentHarness;
1468
1475
  checkpoint: NonNullable<Conversation["pendingApprovals"]>[number];
1469
1476
  childConversationId: string;
@@ -1584,84 +1591,86 @@ export const createRequestHandler = async (options?: {
1584
1591
  });
1585
1592
  }
1586
1593
  if (event.type === "tool:approval:checkpoint") {
1587
- // Persist checkpoint so the approval endpoint can find it
1588
1594
  const cpConv = await conversationStore.get(childConversationId);
1589
1595
  if (cpConv) {
1590
- const cpData: NonNullable<Conversation["pendingApprovals"]>[number] = {
1591
- approvalId: event.approvalId,
1596
+ const allCpData: NonNullable<Conversation["pendingApprovals"]> = event.approvals.map(a => ({
1597
+ approvalId: a.approvalId,
1592
1598
  runId: latestRunId,
1593
- tool: event.tool,
1594
- toolCallId: event.toolCallId,
1595
- input: event.input,
1599
+ tool: a.tool,
1600
+ toolCallId: a.toolCallId,
1601
+ input: a.input,
1596
1602
  checkpointMessages: [...historyMessages, ...event.checkpointMessages],
1597
1603
  baseMessageCount: 0,
1598
1604
  pendingToolCalls: event.pendingToolCalls,
1599
- };
1600
- cpConv.pendingApprovals = [cpData];
1605
+ }));
1606
+ cpConv.pendingApprovals = allCpData;
1601
1607
  cpConv.updatedAt = Date.now();
1602
1608
  await conversationStore.update(cpConv);
1603
1609
 
1604
- // Wait for approval decision (signaled by the approval endpoint)
1605
- const approved = await new Promise<boolean>((resolve) => {
1606
- pendingSubagentApprovals.set(event.approvalId, {
1607
- resolve,
1608
- childHarness,
1609
- checkpoint: cpData,
1610
- childConversationId,
1611
- parentConversationId,
1612
- });
1610
+ // Wait for all approval decisions (signaled by the approval endpoint
1611
+ // once every entry in the batch has a decision)
1612
+ const decidedApprovals = await new Promise<NonNullable<Conversation["pendingApprovals"]>>((resolve) => {
1613
+ for (const cpData of allCpData) {
1614
+ pendingSubagentApprovals.set(cpData.approvalId, {
1615
+ resolve,
1616
+ childHarness,
1617
+ checkpoint: cpData,
1618
+ childConversationId,
1619
+ parentConversationId,
1620
+ });
1621
+ }
1613
1622
  });
1614
1623
 
1615
- // Execute tool and resume the run
1616
- let toolResults: Array<{ callId: string; toolName: string; result?: unknown; error?: string }>;
1617
- if (approved) {
1618
- const toolContext = {
1619
- runId: cpData.runId,
1620
- agentId: identity.id,
1621
- step: 0,
1622
- workingDir,
1623
- parameters: {},
1624
- conversationId: childConversationId,
1625
- };
1626
- const execResults = await childHarness.executeTools(
1627
- [{ id: cpData.toolCallId!, name: cpData.tool, input: cpData.input }],
1628
- toolContext,
1629
- );
1630
- toolResults = execResults.map(r => ({
1624
+ // Execute approved tools and collect results
1625
+ const checkpointRef = allCpData[0]!;
1626
+ const toolContext = {
1627
+ runId: checkpointRef.runId,
1628
+ agentId: identity.id,
1629
+ step: 0,
1630
+ workingDir,
1631
+ parameters: {},
1632
+ conversationId: childConversationId,
1633
+ };
1634
+
1635
+ const approvalToolCallIds = new Set(decidedApprovals.map(a => a.toolCallId));
1636
+ const callsToExecute: Array<{ id: string; name: string; input: Record<string, unknown> }> = [];
1637
+ const deniedResults: Array<{ callId: string; toolName: string; error: string }> = [];
1638
+
1639
+ for (const a of decidedApprovals) {
1640
+ if (a.decision === "approved" && a.toolCallId) {
1641
+ callsToExecute.push({ id: a.toolCallId, name: a.tool, input: a.input });
1642
+ const toolText = `- done \`${a.tool}\``;
1643
+ toolTimeline.push(toolText);
1644
+ currentTools.push(toolText);
1645
+ } else if (a.toolCallId) {
1646
+ deniedResults.push({ callId: a.toolCallId, toolName: a.tool, error: "Tool execution denied by user" });
1647
+ const toolText = `- denied \`${a.tool}\``;
1648
+ toolTimeline.push(toolText);
1649
+ currentTools.push(toolText);
1650
+ }
1651
+ }
1652
+
1653
+ // Auto-approved tools that were deferred alongside approval-needing ones
1654
+ const pendingToolCalls = checkpointRef.pendingToolCalls ?? [];
1655
+ for (const tc of pendingToolCalls) {
1656
+ if (!approvalToolCallIds.has(tc.id)) {
1657
+ callsToExecute.push(tc);
1658
+ }
1659
+ }
1660
+
1661
+ let toolResults: Array<{ callId: string; toolName: string; result?: unknown; error?: string }> = [...deniedResults];
1662
+ if (callsToExecute.length > 0) {
1663
+ const execResults = await childHarness.executeTools(callsToExecute, toolContext);
1664
+ toolResults.push(...execResults.map(r => ({
1631
1665
  callId: r.callId,
1632
1666
  toolName: r.tool,
1633
1667
  result: r.output,
1634
1668
  error: r.error,
1635
- }));
1636
- const toolText = `- done \`${cpData.tool}\``;
1637
- toolTimeline.push(toolText);
1638
- currentTools.push(toolText);
1639
- } else {
1640
- toolResults = [{
1641
- callId: cpData.toolCallId!,
1642
- toolName: cpData.tool,
1643
- error: "Tool execution denied by user",
1644
- }];
1645
- const toolText = `- denied \`${cpData.tool}\``;
1646
- toolTimeline.push(toolText);
1647
- currentTools.push(toolText);
1648
- }
1649
-
1650
- broadcastEvent(childConversationId,
1651
- approved
1652
- ? { type: "tool:approval:granted", approvalId: event.approvalId }
1653
- : { type: "tool:approval:denied", approvalId: event.approvalId },
1654
- );
1655
-
1656
- // Clear pending approval from conversation
1657
- const cpConv2 = await conversationStore.get(childConversationId);
1658
- if (cpConv2) {
1659
- cpConv2.pendingApprovals = [];
1660
- await conversationStore.update(cpConv2);
1669
+ })));
1661
1670
  }
1662
1671
 
1663
1672
  // Resume the run -- process continuation events
1664
- const resumeMessages = [...cpData.checkpointMessages!];
1673
+ const resumeMessages = [...checkpointRef.checkpointMessages!];
1665
1674
  for await (const resumeEvent of childHarness.continueFromToolResult({
1666
1675
  messages: resumeMessages,
1667
1676
  toolResults,
@@ -1986,16 +1995,16 @@ export const createRequestHandler = async (options?: {
1986
1995
  if (event.type === "tool:approval:checkpoint") {
1987
1996
  const conv = await conversationStore.get(conversationId);
1988
1997
  if (conv) {
1989
- conv.pendingApprovals = [{
1990
- approvalId: event.approvalId,
1998
+ conv.pendingApprovals = event.approvals.map(a => ({
1999
+ approvalId: a.approvalId,
1991
2000
  runId: latestRunId,
1992
- tool: event.tool,
1993
- toolCallId: event.toolCallId,
1994
- input: event.input,
2001
+ tool: a.tool,
2002
+ toolCallId: a.toolCallId,
2003
+ input: a.input,
1995
2004
  checkpointMessages: [...fullCheckpointMessages, ...event.checkpointMessages],
1996
2005
  baseMessageCount: 0,
1997
2006
  pendingToolCalls: event.pendingToolCalls,
1998
- }];
2007
+ }));
1999
2008
  conv.updatedAt = Date.now();
2000
2009
  await conversationStore.update(conv);
2001
2010
  }
@@ -2263,16 +2272,16 @@ export const createRequestHandler = async (options?: {
2263
2272
  if (event.type === "tool:approval:checkpoint") {
2264
2273
  await updateConversation((c) => {
2265
2274
  c.messages = buildMessages();
2266
- c.pendingApprovals = [{
2267
- approvalId: event.approvalId,
2275
+ c.pendingApprovals = event.approvals.map(a => ({
2276
+ approvalId: a.approvalId,
2268
2277
  runId: latestRunId,
2269
- tool: event.tool,
2270
- toolCallId: event.toolCallId,
2271
- input: event.input,
2278
+ tool: a.tool,
2279
+ toolCallId: a.toolCallId,
2280
+ input: a.input,
2272
2281
  checkpointMessages: event.checkpointMessages,
2273
2282
  baseMessageCount: historyMessages.length,
2274
2283
  pendingToolCalls: event.pendingToolCalls,
2275
- }];
2284
+ }));
2276
2285
  });
2277
2286
  checkpointedRun = true;
2278
2287
  }
@@ -2352,9 +2361,9 @@ export const createRequestHandler = async (options?: {
2352
2361
  waitUntil: waitUntilHook,
2353
2362
  ownerId: "local-owner",
2354
2363
  });
2355
- adapter.registerRoutes(messagingRouteRegistrar);
2356
2364
  try {
2357
2365
  await bridge.start();
2366
+ adapter.registerRoutes(messagingRouteRegistrar);
2358
2367
  messagingBridges.push(bridge);
2359
2368
  console.log(` Slack messaging enabled at /api/messaging/slack`);
2360
2369
  } catch (err) {
@@ -2367,6 +2376,7 @@ export const createRequestHandler = async (options?: {
2367
2376
  apiKeyEnv: channelConfig.apiKeyEnv,
2368
2377
  webhookSecretEnv: channelConfig.webhookSecretEnv,
2369
2378
  fromEnv: channelConfig.fromEnv,
2379
+ replyToEnv: channelConfig.replyToEnv,
2370
2380
  allowedSenders: channelConfig.allowedSenders,
2371
2381
  mode: channelConfig.mode,
2372
2382
  allowedRecipients: channelConfig.allowedRecipients,
@@ -2378,9 +2388,9 @@ export const createRequestHandler = async (options?: {
2378
2388
  waitUntil: waitUntilHook,
2379
2389
  ownerId: "local-owner",
2380
2390
  });
2381
- adapter.registerRoutes(messagingRouteRegistrar);
2382
2391
  try {
2383
2392
  await bridge.start();
2393
+ adapter.registerRoutes(messagingRouteRegistrar);
2384
2394
  messagingBridges.push(bridge);
2385
2395
  const adapterTools = adapter.getToolDefinitions?.() ?? [];
2386
2396
  if (adapterTools.length > 0) {
@@ -2405,6 +2415,10 @@ export const createRequestHandler = async (options?: {
2405
2415
  const authRequired = config?.auth?.required ?? false;
2406
2416
  const requireAuth = authRequired && authToken.length > 0;
2407
2417
 
2418
+ if (requireAuth) {
2419
+ sessionStore.setSigningKey(authToken);
2420
+ }
2421
+
2408
2422
  const webUiEnabled = config?.webUi !== false;
2409
2423
  const isProduction = resolveHarnessEnvironment() === "production";
2410
2424
  const secureCookies = isProduction;
@@ -2493,8 +2507,10 @@ export const createRequestHandler = async (options?: {
2493
2507
  }
2494
2508
 
2495
2509
  const cookies = parseCookies(request);
2496
- const sessionId = cookies.poncho_session;
2497
- const session = sessionId ? sessionStore.get(sessionId) : undefined;
2510
+ const cookieValue = cookies.poncho_session;
2511
+ const session = cookieValue
2512
+ ? (sessionStore.get(cookieValue) ?? sessionStore.restoreFromSigned(cookieValue))
2513
+ : undefined;
2498
2514
  const ownerId = session?.ownerId ?? "local-owner";
2499
2515
  const requiresCsrfValidation =
2500
2516
  request.method !== "GET" && request.method !== "HEAD" && request.method !== "OPTIONS";
@@ -2545,7 +2561,8 @@ export const createRequestHandler = async (options?: {
2545
2561
  }
2546
2562
  loginRateLimiter.registerSuccess(ip);
2547
2563
  const createdSession = sessionStore.create(ownerId);
2548
- setCookie(response, "poncho_session", createdSession.sessionId, {
2564
+ const signedValue = sessionStore.signSession(createdSession);
2565
+ setCookie(response, "poncho_session", signedValue ?? createdSession.sessionId, {
2549
2566
  httpOnly: true,
2550
2567
  secure: secureCookies,
2551
2568
  sameSite: "Lax",
@@ -2787,14 +2804,32 @@ export const createRequestHandler = async (options?: {
2787
2804
  // Check if this is a pending subagent approval (handled inline by runSubagent)
2788
2805
  const pendingSubagent = pendingSubagentApprovals.get(approvalId);
2789
2806
  if (pendingSubagent) {
2790
- pendingSubagentApprovals.delete(approvalId);
2791
- // Clear pendingApprovals from the subagent's conversation immediately
2807
+ pendingSubagent.checkpoint.decision = approved ? "approved" : "denied";
2808
+
2809
+ broadcastEvent(pendingSubagent.childConversationId,
2810
+ approved
2811
+ ? { type: "tool:approval:granted", approvalId }
2812
+ : { type: "tool:approval:denied", approvalId },
2813
+ );
2814
+
2792
2815
  const childConv = await conversationStore.get(pendingSubagent.childConversationId);
2793
- if (childConv && Array.isArray(childConv.pendingApprovals)) {
2794
- childConv.pendingApprovals = childConv.pendingApprovals.filter(pa => pa.approvalId !== approvalId);
2816
+ const allApprovals = childConv?.pendingApprovals ?? [];
2817
+ const allDecided = allApprovals.length > 0 && allApprovals.every(pa => pa.decision != null);
2818
+
2819
+ if (allDecided) {
2820
+ // All approvals in the batch are decided — resolve the subagent
2821
+ for (const pa of allApprovals) {
2822
+ pendingSubagentApprovals.delete(pa.approvalId);
2823
+ }
2824
+ if (childConv) {
2825
+ childConv.pendingApprovals = [];
2826
+ await conversationStore.update(childConv);
2827
+ }
2828
+ pendingSubagent.resolve(allApprovals);
2829
+ } else if (childConv) {
2795
2830
  await conversationStore.update(childConv);
2796
2831
  }
2797
- pendingSubagent.resolve(approved);
2832
+
2798
2833
  writeJson(response, 200, { ok: true, approvalId, approved });
2799
2834
  return;
2800
2835
  }
@@ -2824,7 +2859,6 @@ export const createRequestHandler = async (options?: {
2824
2859
  const conversationId = foundConversation.conversationId;
2825
2860
 
2826
2861
  if (!foundApproval.checkpointMessages || !foundApproval.toolCallId) {
2827
- // Legacy approval without checkpoint data — cannot resume
2828
2862
  foundConversation.pendingApprovals = (foundConversation.pendingApprovals ?? [])
2829
2863
  .filter(a => a.approvalId !== approvalId);
2830
2864
  await conversationStore.update(foundConversation);
@@ -2835,55 +2869,82 @@ export const createRequestHandler = async (options?: {
2835
2869
  return;
2836
2870
  }
2837
2871
 
2838
- // Clear this approval from the conversation before resuming
2839
- foundConversation.pendingApprovals = (foundConversation.pendingApprovals ?? [])
2840
- .filter(a => a.approvalId !== approvalId);
2841
- await conversationStore.update(foundConversation);
2872
+ // Record the decision on this approval entry
2873
+ foundApproval.decision = approved ? "approved" : "denied";
2842
2874
 
2843
- // Initialize the event stream so the web UI can connect immediately
2844
2875
  broadcastEvent(conversationId,
2845
2876
  approved
2846
2877
  ? { type: "tool:approval:granted", approvalId }
2847
2878
  : { type: "tool:approval:denied", approvalId },
2848
2879
  );
2849
2880
 
2850
- // Resume the run asynchronously (tool execution + continuation)
2881
+ const allApprovals = foundConversation.pendingApprovals ?? [];
2882
+ const allDecided = allApprovals.length > 0 && allApprovals.every(a => a.decision != null);
2883
+
2884
+ if (!allDecided) {
2885
+ // Still waiting for more decisions — persist and respond
2886
+ await conversationStore.update(foundConversation);
2887
+ writeJson(response, 200, { ok: true, approvalId, approved, batchComplete: false });
2888
+ return;
2889
+ }
2890
+
2891
+ // All approvals in the batch are decided — execute and resume
2892
+ foundConversation.pendingApprovals = [];
2893
+ await conversationStore.update(foundConversation);
2894
+
2895
+ // Use the first approval as the checkpoint reference (all share the same checkpoint data)
2896
+ const checkpointRef = allApprovals[0]!;
2897
+
2851
2898
  void (async () => {
2852
- let toolResults: Array<{ callId: string; toolName: string; result?: unknown; error?: string }>;
2853
- if (approved) {
2854
- const toolContext = {
2855
- runId: foundApproval.runId,
2856
- agentId: identity.id,
2857
- step: 0,
2858
- workingDir,
2859
- parameters: {},
2860
- };
2861
- const execResults = await harness.executeTools(
2862
- [{ id: foundApproval.toolCallId!, name: foundApproval.tool, input: foundApproval.input }],
2863
- toolContext,
2864
- );
2865
- toolResults = execResults.map(r => ({
2899
+ const toolContext = {
2900
+ runId: checkpointRef.runId,
2901
+ agentId: identity.id,
2902
+ step: 0,
2903
+ workingDir,
2904
+ parameters: {},
2905
+ };
2906
+
2907
+ // Collect tool calls to execute: approved approval-gated tools + auto-approved deferred tools
2908
+ const approvalToolCallIds = new Set(allApprovals.map(a => a.toolCallId));
2909
+ const callsToExecute: Array<{ id: string; name: string; input: Record<string, unknown> }> = [];
2910
+ const deniedResults: Array<{ callId: string; toolName: string; error: string }> = [];
2911
+
2912
+ for (const a of allApprovals) {
2913
+ if (a.decision === "approved" && a.toolCallId) {
2914
+ callsToExecute.push({ id: a.toolCallId, name: a.tool, input: a.input });
2915
+ } else if (a.decision === "denied" && a.toolCallId) {
2916
+ deniedResults.push({ callId: a.toolCallId, toolName: a.tool, error: "Tool execution denied by user" });
2917
+ }
2918
+ }
2919
+
2920
+ // Auto-approved tools that were deferred alongside the approval-needing ones
2921
+ const pendingToolCalls = checkpointRef.pendingToolCalls ?? [];
2922
+ for (const tc of pendingToolCalls) {
2923
+ if (!approvalToolCallIds.has(tc.id)) {
2924
+ callsToExecute.push(tc);
2925
+ }
2926
+ }
2927
+
2928
+ let toolResults: Array<{ callId: string; toolName: string; result?: unknown; error?: string }> = [...deniedResults];
2929
+ if (callsToExecute.length > 0) {
2930
+ const execResults = await harness.executeTools(callsToExecute, toolContext);
2931
+ toolResults.push(...execResults.map(r => ({
2866
2932
  callId: r.callId,
2867
2933
  toolName: r.tool,
2868
2934
  result: r.output,
2869
2935
  error: r.error,
2870
- }));
2871
- } else {
2872
- toolResults = [{
2873
- callId: foundApproval.toolCallId!,
2874
- toolName: foundApproval.tool,
2875
- error: "Tool execution denied by user",
2876
- }];
2936
+ })));
2877
2937
  }
2938
+
2878
2939
  await resumeRunFromCheckpoint(
2879
2940
  conversationId,
2880
2941
  foundConversation!,
2881
- foundApproval!,
2942
+ checkpointRef,
2882
2943
  toolResults,
2883
2944
  );
2884
2945
  })();
2885
2946
 
2886
- writeJson(response, 200, { ok: true, approvalId, approved });
2947
+ writeJson(response, 200, { ok: true, approvalId, approved, batchComplete: true });
2887
2948
  return;
2888
2949
  }
2889
2950
 
@@ -3402,16 +3463,16 @@ export const createRequestHandler = async (options?: {
3402
3463
  }]
3403
3464
  : []),
3404
3465
  ];
3405
- conversation.pendingApprovals = [{
3406
- approvalId: event.approvalId,
3466
+ conversation.pendingApprovals = event.approvals.map(a => ({
3467
+ approvalId: a.approvalId,
3407
3468
  runId: latestRunId,
3408
- tool: event.tool,
3409
- toolCallId: event.toolCallId,
3410
- input: event.input,
3469
+ tool: a.tool,
3470
+ toolCallId: a.toolCallId,
3471
+ input: a.input,
3411
3472
  checkpointMessages: event.checkpointMessages,
3412
3473
  baseMessageCount: historyMessages.length,
3413
3474
  pendingToolCalls: event.pendingToolCalls,
3414
- }];
3475
+ }));
3415
3476
  conversation.updatedAt = Date.now();
3416
3477
  await conversationStore.update(conversation);
3417
3478
  checkpointedRun = true;