@pushpalsdev/cli 1.1.10 → 1.1.12

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.
Files changed (23) hide show
  1. package/dist/pushpals-cli.js +76 -11
  2. package/monitor-ui/+not-found.html +1 -1
  3. package/monitor-ui/_expo/static/js/web/{entry-ff425ab85ad13c1920b8ee00abfae7dd.js → entry-e8aa7049f746aaa8f1e865615e248f21.js} +1 -1
  4. package/monitor-ui/_sitemap.html +1 -1
  5. package/monitor-ui/index.html +1 -1
  6. package/monitor-ui/modal.html +1 -1
  7. package/package.json +1 -1
  8. package/runtime/configs/default.toml +1 -1
  9. package/runtime/protocol/schemas/events.schema.json +2 -1
  10. package/runtime/sandbox/.pushpals-remotebuddy-fallback.js +1 -1
  11. package/runtime/sandbox/apps/workerpals/src/backends/openai_codex/openai_codex_executor.py +6 -1
  12. package/runtime/sandbox/apps/workerpals/src/backends/openai_codex/test_openai_codex_runtime_config.py +78 -0
  13. package/runtime/sandbox/apps/workerpals/src/backends/openai_codex_backend.ts +0 -1
  14. package/runtime/sandbox/apps/workerpals/src/backends/shared/executor_base.py +70 -0
  15. package/runtime/sandbox/apps/workerpals/src/common/generic_python_executor.ts +39 -1
  16. package/runtime/sandbox/apps/workerpals/src/docker_executor.ts +9 -8
  17. package/runtime/sandbox/apps/workerpals/src/execute_job.ts +155 -1
  18. package/runtime/sandbox/apps/workerpals/src/workerpals_main.ts +77 -4
  19. package/runtime/sandbox/configs/default.toml +1 -1
  20. package/runtime/sandbox/packages/protocol/src/schemas/events.schema.json +2 -1
  21. package/runtime/sandbox/packages/protocol/src/types.ts +1 -0
  22. package/runtime/sandbox/packages/shared/src/config.ts +1 -1
  23. package/runtime/sandbox/protocol/schemas/events.schema.json +2 -1
@@ -1023,7 +1023,7 @@ function loadPushPalsConfig(options = {}) {
1023
1023
  workerpalLabels: firstNonEmpty(process.env.REMOTEBUDDY_WORKERPAL_LABELS) ? firstNonEmpty(process.env.REMOTEBUDDY_WORKERPAL_LABELS).split(",").map((value) => value.trim()).filter(Boolean) : asStringArray(remoteNode.workerpal_labels),
1024
1024
  executionBudgetInteractiveMs: Math.max(60000, asInt(parseIntEnv("REMOTEBUDDY_EXECUTION_BUDGET_INTERACTIVE_MS") ?? remoteNode.execution_budget_interactive_ms, 300000)),
1025
1025
  executionBudgetNormalMs: Math.max(120000, asInt(parseIntEnv("REMOTEBUDDY_EXECUTION_BUDGET_NORMAL_MS") ?? remoteNode.execution_budget_normal_ms, 900000)),
1026
- executionBudgetBackgroundMs: Math.max(180000, asInt(parseIntEnv("REMOTEBUDDY_EXECUTION_BUDGET_BACKGROUND_MS") ?? remoteNode.execution_budget_background_ms, 1800000)),
1026
+ executionBudgetBackgroundMs: Math.max(180000, asInt(parseIntEnv("REMOTEBUDDY_EXECUTION_BUDGET_BACKGROUND_MS") ?? remoteNode.execution_budget_background_ms, 1200000)),
1027
1027
  finalizationBudgetMs: Math.max(30000, asInt(parseIntEnv("REMOTEBUDDY_FINALIZATION_BUDGET_MS") ?? remoteNode.finalization_budget_ms, 120000)),
1028
1028
  crashRestartEnabled: parseBoolEnv("REMOTEBUDDY_CRASH_RESTART_ENABLED") ?? asBoolean(remoteNode.crash_restart_enabled, true),
1029
1029
  crashRestartMaxRestarts: Math.max(0, asInt(parseIntEnv("REMOTEBUDDY_CRASH_RESTART_MAX_RESTARTS") ?? remoteNode.crash_restart_max_restarts, 3)),
@@ -3036,6 +3036,17 @@ async function downloadBinaryAssetWithWindowsCurlFallback(url, outPath, cause) {
3036
3036
  renameSync(tmpPath, outPath);
3037
3037
  return true;
3038
3038
  }
3039
+ async function runWithConcurrency(items, concurrency, worker) {
3040
+ const workerCount = Math.max(1, Math.min(items.length, Math.floor(concurrency)));
3041
+ let nextIndex = 0;
3042
+ await Promise.all(Array.from({ length: workerCount }, async () => {
3043
+ while (nextIndex < items.length) {
3044
+ const currentIndex = nextIndex;
3045
+ nextIndex += 1;
3046
+ await worker(items[currentIndex], currentIndex);
3047
+ }
3048
+ }));
3049
+ }
3039
3050
  async function ensureRuntimeBinaries(runtimeRoot, runtimeTag) {
3040
3051
  const platformKey = resolveRuntimePlatformKey();
3041
3052
  console.log(`[pushpals] Preparing embedded runtime binaries for ${runtimeTag} (${platformKey})...`);
@@ -3057,14 +3068,15 @@ async function ensureRuntimeBinaries(runtimeRoot, runtimeTag) {
3057
3068
  runtimeBinaries.sourceControlManager
3058
3069
  ];
3059
3070
  const shouldRefreshAll = installedTag !== runtimeTag;
3060
- let downloadedCount = 0;
3061
- for (const binaryPath of requiredAssets) {
3062
- if (!shouldRefreshAll && existsSync5(binaryPath))
3063
- continue;
3071
+ const assetsToDownload = requiredAssets.filter((binaryPath) => shouldRefreshAll || !existsSync5(binaryPath));
3072
+ if (assetsToDownload.length > 1) {
3073
+ console.log(`[pushpals] Downloading ${assetsToDownload.length} runtime binary asset(s) with bounded parallelism...`);
3074
+ }
3075
+ await runWithConcurrency(assetsToDownload, 3, async (binaryPath) => {
3064
3076
  const assetName = binaryPath.split(/[\\/]/).pop() || "";
3065
3077
  await downloadBinaryAsset(runtimeTag, assetName, binaryPath);
3066
- downloadedCount++;
3067
- }
3078
+ });
3079
+ const downloadedCount = assetsToDownload.length;
3068
3080
  writeFileSync(tagMarkerPath, `${runtimeTag}
3069
3081
  `, "utf8");
3070
3082
  cleanupLegacyRuntimeBinaryLayouts(runtimeRoot, platformKey, binDir);
@@ -4695,6 +4707,8 @@ ${tail}` : ""}`);
4695
4707
  const deadline = Date.now() + DEFAULT_RUNTIME_BOOT_TIMEOUT_MS;
4696
4708
  const readinessPhaseStartedAt = Date.now();
4697
4709
  const optionalServiceExitWarned = new Set;
4710
+ let lastReadinessWaitLogAt = 0;
4711
+ let lastReadinessWaitDetail = "";
4698
4712
  while (Date.now() < deadline) {
4699
4713
  reportRemoteBuddyAutonomousEngineState();
4700
4714
  if (maybeActivateRemoteBuddyWindowsFallback("silent_startup")) {
@@ -4738,6 +4752,17 @@ ${tail}` : ""}`);
4738
4752
  }
4739
4753
  const health = localBuddyEnabled ? await probeLocalBuddy(opts.localAgentUrl) : null;
4740
4754
  const remoteBuddyHealth2 = await probeRemoteBuddySessionConsumer(opts.serverUrl, opts.sessionId);
4755
+ if (localBuddyEnabled && !health?.ok || !remoteBuddyHealth2.ok) {
4756
+ const localBuddyDetail = localBuddyEnabled ? health?.ok ? "LocalBuddy ready" : "LocalBuddy not ready" : "LocalBuddy skipped";
4757
+ const readinessDetail = `${localBuddyDetail}; ${remoteBuddyHealth2.detail}`;
4758
+ const now = Date.now();
4759
+ if (readinessDetail !== lastReadinessWaitDetail || now - lastReadinessWaitLogAt >= 5000) {
4760
+ console.log(`[pushpals] Waiting for embedded runtime readiness: ${readinessDetail}`);
4761
+ appendRuntimeServicesLogLine(runtimeServicesLogPath, `[pushpals] waiting for embedded runtime readiness: ${readinessDetail}`);
4762
+ lastReadinessWaitDetail = readinessDetail;
4763
+ lastReadinessWaitLogAt = now;
4764
+ }
4765
+ }
4741
4766
  if ((!localBuddyEnabled || health?.ok) && remoteBuddyHealth2.ok) {
4742
4767
  reportRemoteBuddyAutonomousEngineState();
4743
4768
  const stabilityDeadline = Date.now() + DEFAULT_SERVICE_STABILITY_GRACE_MS;
@@ -5208,8 +5233,10 @@ function formatSessionEventLine(event) {
5208
5233
  if (type === "job_log") {
5209
5234
  const jobId = String(payload.jobId ?? "").slice(0, 8);
5210
5235
  const stream = String(payload.stream ?? "").toLowerCase() === "stderr" ? " stderr" : "";
5211
- const line = compactCliSessionJobLogLine(String(payload.line ?? "").trim());
5212
- return line ? `[job ${jobId}${stream}] ${line}` : null;
5236
+ const phase = compactCliSessionJobLogLine(String(payload.phase ?? "").trim());
5237
+ const phaseLabel = phase ? ` phase:${phase}` : "";
5238
+ const line = formatCliSessionJobLogLine(String(payload.line ?? "").trim());
5239
+ return line ? `[job ${jobId}${stream}${phaseLabel}] ${line}` : null;
5213
5240
  }
5214
5241
  if (type === "job_failed") {
5215
5242
  const jobId = String(payload.jobId ?? "").slice(0, 8);
@@ -5247,8 +5274,7 @@ function formatSessionEventLine(event) {
5247
5274
  return `[job ${jobId}] completed${summary ? `: ${summary}` : ""}`;
5248
5275
  }
5249
5276
  if (type === "error") {
5250
- const message = String(payload.message ?? "").trim();
5251
- return `[event error] ${message || "unknown"}`;
5277
+ return null;
5252
5278
  }
5253
5279
  if (type === "status") {
5254
5280
  const state = String(payload.state ?? "").trim();
@@ -5264,6 +5290,45 @@ function compactCliSessionJobLogLine(line) {
5264
5290
  return compacted;
5265
5291
  return `${compacted.slice(0, CLI_SESSION_JOB_LOG_MAX_CHARS - 3)}...`;
5266
5292
  }
5293
+ function formatCliSessionJobLogLine(line) {
5294
+ const compacted = compactCliSessionJobLogLine(line);
5295
+ if (!compacted)
5296
+ return null;
5297
+ if (shouldSuppressCliSessionJobLogLine(compacted))
5298
+ return null;
5299
+ const codexItem = compacted.match(/^\[OpenAICodexExecutor\]\s+\[codex\]\s+item\.(?:completed|updated)\s+\|\s+(.+)$/i);
5300
+ if (codexItem?.[1]) {
5301
+ return `[codex] ${compactCliSessionJobLogLine(codexItem[1])}`;
5302
+ }
5303
+ return compacted;
5304
+ }
5305
+ function shouldSuppressCliSessionJobLogLine(line) {
5306
+ const text = String(line ?? "").trim();
5307
+ if (!text)
5308
+ return true;
5309
+ if (/^(___RESULT___|__PUSHPALS_OH_RESULT__)\b/.test(text))
5310
+ return true;
5311
+ if (/^\[DockerExecutor\]\s+Linked worktree dependency artifact/i.test(text))
5312
+ return true;
5313
+ if (/^\[OpenAICodexExecutor\]\s+(?:Planner guidance|Codex auth mode|ChatGPT auth mode|Starting codex exec|codex exec finished|Codex JSON stream captured|Codex stdout captured|No reasoning-like|Reasoning-like event|Usage observed|Temporarily masked repo-local)/i.test(text)) {
5314
+ return true;
5315
+ }
5316
+ if (/^\[OpenAICodexExecutor\]\s+codex exec still running\b/i.test(text))
5317
+ return true;
5318
+ if (/^\[OpenAICodexExecutor\]\s+\[codex\]\s+(?:thread|turn)\.started\b/i.test(text)) {
5319
+ return true;
5320
+ }
5321
+ if (/^\[OpenAICodexExecutor\]\s+\[codex\]\s+item\.started\b/i.test(text))
5322
+ return true;
5323
+ if (/^\[OpenAICodexExecutor\]\s+\[codex\]\s+item\.completed\s*$/i.test(text))
5324
+ return true;
5325
+ if (/^\[OpenAICodexExecutor\]\s+\[codex\]\s+item\.updated\s*$/i.test(text))
5326
+ return true;
5327
+ if (/^\[OpenAICodexExecutor\]\s+\[stderr\].*codex_core::tools::router: error=exec_command failed/i.test(text)) {
5328
+ return true;
5329
+ }
5330
+ return false;
5331
+ }
5267
5332
  function buildSessionEventReplayFingerprint(event) {
5268
5333
  const type = String(event.type ?? "").trim().toLowerCase();
5269
5334
  if (type !== "status")
@@ -435,5 +435,5 @@ input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-web
435
435
  @keyframes r-1pzkwqh{0%{transform:translateY(100%);}100%{transform:translateY(0%);}}
436
436
  @keyframes r-imtty0{0%{opacity:0;}100%{opacity:1;}}
437
437
  @keyframes r-q67da2{0%{transform:translateX(-100%);}100%{transform:translateX(400%);}}
438
- @keyframes r-t2lo5v{0%{opacity:1;}100%{opacity:0;}}</style><script type="module">globalThis.__EXPO_ROUTER_HYDRATE__=true;</script><link rel="icon" href="/favicon.ico" /></head><body><div id="root"><div class="css-g5y9jx r-13awgt0"></div></div><script src="/_expo/static/js/web/entry-ff425ab85ad13c1920b8ee00abfae7dd.js" defer></script>
438
+ @keyframes r-t2lo5v{0%{opacity:1;}100%{opacity:0;}}</style><script type="module">globalThis.__EXPO_ROUTER_HYDRATE__=true;</script><link rel="icon" href="/favicon.ico" /></head><body><div id="root"><div class="css-g5y9jx r-13awgt0"></div></div><script src="/_expo/static/js/web/entry-e8aa7049f746aaa8f1e865615e248f21.js" defer></script>
439
439
  </body></html>
@@ -1117,7 +1117,7 @@ __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,"__esModule",{v
1117
1117
  __d(function(g,r,i,a,m,_e,d){"use strict";function f(f,t){return{validate:f,compare:t}}function t(f){return f%4==0&&(f%100!=0||f%400==0)}Object.defineProperty(_e,"__esModule",{value:!0}),_e.formatNames=_e.fastFormats=_e.fullFormats=void 0,_e.fullFormats={date:f(u,o),time:f(s(!0),$),"date-time":f(_(!0),v),"iso-time":f(s(),c),"iso-date-time":f(_(),p),duration:/^P(?!$)((\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?|(\d+W)?)$/,uri:function(f){return b.test(f)&&x.test(f)},"uri-reference":/^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'"()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i,"uri-template":/^(?:(?:[^\x00-\x20"'<>%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i,url:/^(?:https?|ftp):\/\/(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u{00a1}-\u{ffff}]+-)*[a-z0-9\u{00a1}-\u{ffff}]+)(?:\.(?:[a-z0-9\u{00a1}-\u{ffff}]+-)*[a-z0-9\u{00a1}-\u{ffff}]+)*(?:\.(?:[a-z\u{00a1}-\u{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iu,email:/^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i,hostname:/^(?=.{1,253}\.?$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*\.?$/i,ipv4:/^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/,ipv6:/^((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))$/i,regex:function(f){if(j.test(f))return!1;try{return new RegExp(f),!0}catch(f){return!1}},uuid:/^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i,"json-pointer":/^(?:\/(?:[^~/]|~0|~1)*)*$/,"json-pointer-uri-fragment":/^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i,"relative-json-pointer":/^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/,byte:function(f){return y.lastIndex=0,y.test(f)},int32:{type:"number",validate:function(f){return Number.isInteger(f)&&f<=F&&f>=w}},int64:{type:"number",validate:function(f){return Number.isInteger(f)}},float:{type:"number",validate:O},double:{type:"number",validate:O},password:!0,binary:!0},_e.fastFormats={..._e.fullFormats,date:f(/^\d\d\d\d-[0-1]\d-[0-3]\d$/,o),time:f(/^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)$/i,$),"date-time":f(/^\d\d\d\d-[0-1]\d-[0-3]\dt(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)$/i,v),"iso-time":f(/^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)?$/i,c),"iso-date-time":f(/^\d\d\d\d-[0-1]\d-[0-3]\d[t\s](?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)?$/i,p),uri:/^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/)?[^\s]*$/i,"uri-reference":/^(?:(?:[a-z][a-z0-9+\-.]*:)?\/?\/)?(?:[^\\\s#][^\s#]*)?(?:#[^\\\s]*)?$/i,email:/^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i},_e.formatNames=Object.keys(_e.fullFormats);const e=/^(\d\d\d\d)-(\d\d)-(\d\d)$/,n=[0,31,28,31,30,31,30,31,31,30,31,30,31];function u(f){const u=e.exec(f);if(!u)return!1;const o=+u[1],z=+u[2],s=+u[3];return z>=1&&z<=12&&s>=1&&s<=(2===z&&t(o)?29:n[z])}function o(f,t){if(f&&t)return f>t?1:f<t?-1:0}const z=/^(\d\d):(\d\d):(\d\d(?:\.\d+)?)(z|([+-])(\d\d)(?::?(\d\d))?)?$/i;function s(f){return function(t){const e=z.exec(t);if(!e)return!1;const n=+e[1],u=+e[2],o=+e[3],s=e[4],$="-"===e[5]?-1:1,c=+(e[6]||0),l=+(e[7]||0);if(c>23||l>59||f&&!s)return!1;if(n<=23&&u<=59&&o<60)return!0;const _=u-l*$,v=n-c*$-(_<0?1:0);return(23===v||-1===v)&&(59===_||-1===_)&&o<61}}function $(f,t){if(!f||!t)return;const e=new Date("2020-01-01T"+f).valueOf(),n=new Date("2020-01-01T"+t).valueOf();return e&&n?e-n:void 0}function c(f,t){if(!f||!t)return;const e=z.exec(f),n=z.exec(t);return e&&n?(f=e[1]+e[2]+e[3])>(t=n[1]+n[2]+n[3])?1:f<t?-1:0:void 0}const l=/t|\s/i;function _(f){const t=s(f);return function(f){const e=f.split(l);return 2===e.length&&u(e[0])&&t(e[1])}}function v(f,t){if(!f||!t)return;const e=new Date(f).valueOf(),n=new Date(t).valueOf();return e&&n?e-n:void 0}function p(f,t){if(!f||!t)return;const[e,n]=f.split(l),[u,z]=t.split(l),s=o(e,u);return void 0!==s?s||$(n,z):void 0}const b=/\/|:/,x=/^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i;const y=/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/gm;const w=-2147483648,F=2147483647;function O(){return!0}const j=/[^\\]\\Z/},1100,[]);
1118
1118
  __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.formatLimitDefinition=void 0;const o=r(d[0]),t=r(d[1]),f=t.operators,n={formatMaximum:{okStr:"<=",ok:f.LTE,fail:f.GT},formatMinimum:{okStr:">=",ok:f.GTE,fail:f.LT},formatExclusiveMaximum:{okStr:"<",ok:f.LT,fail:f.GTE},formatExclusiveMinimum:{okStr:">",ok:f.GT,fail:f.LTE}},s={message:({keyword:o,schemaCode:f})=>t.str`should be ${n[o].okStr} ${f}`,params:({keyword:o,schemaCode:f})=>t._`{comparison: ${n[o].okStr}, limit: ${f}}`};e.formatLimitDefinition={keyword:Object.keys(n),type:"string",schemaType:"string",$data:!0,error:s,code(f){const{gen:s,data:c,schemaCode:u,keyword:p,it:$}=f,{opts:l,self:k}=$;if(!l.validateFormats)return;const y=new o.KeywordCxt($,k.RULES.all.format.definition,"format");function _(o){return t._`${o}.compare(${c}, ${u}) ${n[p].fail} 0`}y.$data?(function(){const o=s.scopeValue("formats",{ref:k.formats,code:l.code.formats}),n=s.const("fmt",t._`${o}[${y.schemaCode}]`);f.fail$data((0,t.or)(t._`typeof ${n} != "object"`,t._`${n} instanceof RegExp`,t._`typeof ${n}.compare != "function"`,_(n)))})():(function(){const o=y.schema,n=k.formats[o];if(!n||!0===n)return;if("object"!=typeof n||n instanceof RegExp||"function"!=typeof n.compare)throw new Error(`"${p}": format "${o}" does not define "compare" function`);const c=s.scopeValue("formats",{key:o,ref:n,code:l.code.formats?t._`${l.code.formats}${(0,t.getProperty)(o)}`:void 0});f.fail$data(_(c))})()},dependencies:["format"]};e.default=o=>(o.addKeyword(e.formatLimitDefinition),o)},1101,[1032,1037]);
1119
1119
  __d(function(e,t,o,s,i,r,n){i.exports={$schema:"http://json-schema.org/draft-07/schema#",title:"EventEnvelope",type:"object",required:["protocolVersion","id","ts","sessionId","type","payload"],properties:{protocolVersion:{type:"string",const:"0.1.0",description:"Protocol version must be 0.1.0"},id:{type:"string",description:"Unique event identifier (e.g., UUID)"},ts:{type:"string",format:"date-time",description:"ISO-8601 timestamp"},sessionId:{type:"string",description:"Session identifier"},type:{type:"string",enum:["log","scan_result","suggestions","diff_ready","approval_required","approved","denied","committed","assistant_message","error","done","agent_status","task_created","task_started","task_progress","task_completed","task_failed","tool_call","tool_result","delegate_request","delegate_response","job_enqueued","job_claimed","job_completed","job_failed","message","job_log","status","autonomy_cycle_started","autonomy_candidates_generated","autonomy_objective_dispatched","autonomy_objective_blocked","autonomy_feedback_recorded","question_asked","question_answered"],description:"Event type discriminator"},traceId:{type:"string",description:"Optional trace ID for debugging"},from:{type:"string",description:"Originator identifier (e.g. client, agent:local1, worker:lint)"},to:{type:"string",description:"Destination identifier (e.g. broadcast, agent:local1, worker:queue:default)"},correlationId:{type:"string",description:"Threads a whole conversation turn together"},parentId:{type:"string",description:"Links tool calls/results under their parent task event"},turnId:{type:"string",description:"One per user message; groups all downstream events"},payload:{type:"object",description:"Payload depends on event type"}},additionalProperties:!1}},1102,[]);
1120
- __d(function(e,t,r,i,p,o,a){p.exports={$schema:"http://json-schema.org/draft-07/schema#",title:"EventTypePayloads",definitions:{artifact:{type:"object",required:["kind"],properties:{kind:{type:"string"},uri:{type:"string"},text:{type:"string"}},additionalProperties:!1}},oneOf:[{type:"object",required:["type","payload"],properties:{type:{const:"log"},payload:{type:"object",required:["level","message"],properties:{level:{type:"string",enum:["debug","info","warn","error"]},message:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"scan_result"},payload:{type:"object",required:["summary","filesRead","gitStatusPorcelain","gitDiff"],properties:{summary:{type:"string"},filesRead:{type:"array",items:{type:"string"}},gitStatusPorcelain:{type:"string"},gitDiff:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"suggestions"},payload:{type:"object",required:["items"],properties:{items:{type:"array",items:{type:"object",required:["id","title","detail","effort"],properties:{id:{type:"string"},title:{type:"string"},detail:{type:"string"},effort:{type:"string",enum:["S","M","L"]}},additionalProperties:!1}}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"assistant_message"},payload:{type:"object",required:["text"],properties:{text:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"diff_ready"},payload:{type:"object",required:["unifiedDiff","diffStat","branch"],properties:{unifiedDiff:{type:"string"},diffStat:{type:"string"},branch:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"approval_required"},payload:{type:"object",required:["approvalId","action","summary","details"],properties:{approvalId:{type:"string"},action:{type:"string",enum:["git.commit","git.push","other"]},summary:{type:"string"},details:{type:"object",additionalProperties:!0}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"approved"},payload:{type:"object",required:["approvalId"],properties:{approvalId:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"denied"},payload:{type:"object",required:["approvalId"],properties:{approvalId:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"committed"},payload:{type:"object",required:["branch","commitHash","message"],properties:{branch:{type:"string"},commitHash:{type:"string"},message:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"error"},payload:{type:"object",required:["message"],properties:{message:{type:"string"},detail:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"done"},payload:{type:"object",required:["ok"],properties:{ok:{type:"boolean"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"agent_status"},payload:{type:"object",required:["agentId","status"],properties:{agentId:{type:"string"},status:{type:"string",enum:["idle","busy","error"]},message:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"task_created"},payload:{type:"object",required:["taskId","title","description","createdBy"],properties:{taskId:{type:"string"},title:{type:"string"},description:{type:"string"},createdBy:{type:"string"},priority:{type:"string"},tags:{type:"array",items:{type:"string"}}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"task_started"},payload:{type:"object",required:["taskId"],properties:{taskId:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"task_progress"},payload:{type:"object",required:["taskId","message"],properties:{taskId:{type:"string"},message:{type:"string"},percent:{type:"number",minimum:0,maximum:100}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"task_completed"},payload:{type:"object",required:["taskId","summary"],properties:{taskId:{type:"string"},summary:{type:"string"},origin:{type:"string",enum:["user","autonomy"]},artifacts:{type:"array",items:{$ref:"#/definitions/artifact"}}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"task_failed"},payload:{type:"object",required:["taskId","message"],properties:{taskId:{type:"string"},message:{type:"string"},detail:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"tool_call"},payload:{type:"object",required:["toolCallId","tool","args"],properties:{toolCallId:{type:"string"},taskId:{type:"string"},tool:{type:"string"},args:{type:"object",additionalProperties:!0},requiresApproval:{type:"boolean"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"tool_result"},payload:{type:"object",required:["toolCallId","ok"],properties:{toolCallId:{type:"string"},taskId:{type:"string"},ok:{type:"boolean"},stdout:{type:"string"},stderr:{type:"string"},exitCode:{type:"integer"},artifacts:{type:"array",items:{$ref:"#/definitions/artifact"}}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"delegate_request"},payload:{type:"object",required:["requestId","toAgentId","input"],properties:{requestId:{type:"string"},toAgentId:{type:"string"},input:{type:"object",additionalProperties:!0}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"delegate_response"},payload:{type:"object",required:["requestId","ok"],properties:{requestId:{type:"string"},ok:{type:"boolean"},output:{type:"object",additionalProperties:!0},error:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"job_enqueued"},payload:{type:"object",required:["jobId","taskId","kind","params"],properties:{jobId:{type:"string"},taskId:{type:"string"},kind:{type:"string"},params:{type:"object",additionalProperties:!0},origin:{type:"string",enum:["user","autonomy"]},autonomy:{type:"object",properties:{objectiveId:{type:"string"},runId:{type:"string"},snapshotId:{type:"string"},patternKey:{type:"string"}},additionalProperties:!1}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"job_claimed"},payload:{type:"object",required:["jobId","workerId"],properties:{jobId:{type:"string"},workerId:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"job_completed"},payload:{type:"object",required:["jobId"],properties:{jobId:{type:"string"},summary:{type:"string"},origin:{type:"string",enum:["user","autonomy"]},artifacts:{type:"array",items:{$ref:"#/definitions/artifact"}}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"job_failed"},payload:{type:"object",required:["jobId","message"],properties:{jobId:{type:"string"},message:{type:"string"},detail:{type:"string"},origin:{type:"string",enum:["user","autonomy"]}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"message"},payload:{type:"object",required:["text"],properties:{text:{type:"string"},intent:{type:"object",additionalProperties:!0}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"job_log"},payload:{type:"object",required:["jobId","stream","seq","line"],properties:{jobId:{type:"string"},stream:{type:"string",enum:["stdout","stderr"]},seq:{type:"integer",minimum:1},line:{type:"string"},ts:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"status"},payload:{type:"object",required:["agentId","state"],properties:{agentId:{type:"string"},state:{type:"string",enum:["idle","busy","error","shutting_down"]},uptimeMs:{type:"number"},detail:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"autonomy_cycle_started"},payload:{type:"object",required:["runId","snapshotId"],properties:{runId:{type:"string"},snapshotId:{type:"string"},phase:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"autonomy_candidates_generated"},payload:{type:"object",required:["runId","snapshotId","candidateCount"],properties:{runId:{type:"string"},snapshotId:{type:"string"},candidateCount:{type:"integer",minimum:0},topCandidateIds:{type:"array",items:{type:"string"}}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"autonomy_objective_dispatched"},payload:{type:"object",required:["runId","snapshotId","objectiveId","requestId","patternKey"],properties:{runId:{type:"string"},snapshotId:{type:"string"},objectiveId:{type:"string"},requestId:{type:"string"},patternKey:{type:"string"},origin:{type:"string",enum:["autonomy"]}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"autonomy_objective_blocked"},payload:{type:"object",required:["runId","snapshotId","objectiveId","reason"],properties:{runId:{type:"string"},snapshotId:{type:"string"},objectiveId:{type:"string"},reason:{type:"string"},questionId:{type:"string"},patternKey:{type:"string"},origin:{type:"string",enum:["autonomy"]}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"autonomy_feedback_recorded"},payload:{type:"object",required:["objectiveId","patternKey","outcome","success"],properties:{objectiveId:{type:"string"},patternKey:{type:"string"},outcome:{type:"string"},success:{type:"boolean"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"question_asked"},payload:{type:"object",required:["questionId","objectiveId","question","questionType"],properties:{questionId:{type:"string"},objectiveId:{type:"string"},question:{type:"string"},questionType:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"question_answered"},payload:{type:"object",required:["questionId","objectiveId","status"],properties:{questionId:{type:"string"},objectiveId:{type:"string"},status:{type:"string",enum:["valid","invalid"]},answerSummary:{type:"string"}},additionalProperties:!1}},additionalProperties:!1}]}},1103,[]);
1120
+ __d(function(e,t,r,i,p,o,a){p.exports={$schema:"http://json-schema.org/draft-07/schema#",title:"EventTypePayloads",definitions:{artifact:{type:"object",required:["kind"],properties:{kind:{type:"string"},uri:{type:"string"},text:{type:"string"}},additionalProperties:!1}},oneOf:[{type:"object",required:["type","payload"],properties:{type:{const:"log"},payload:{type:"object",required:["level","message"],properties:{level:{type:"string",enum:["debug","info","warn","error"]},message:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"scan_result"},payload:{type:"object",required:["summary","filesRead","gitStatusPorcelain","gitDiff"],properties:{summary:{type:"string"},filesRead:{type:"array",items:{type:"string"}},gitStatusPorcelain:{type:"string"},gitDiff:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"suggestions"},payload:{type:"object",required:["items"],properties:{items:{type:"array",items:{type:"object",required:["id","title","detail","effort"],properties:{id:{type:"string"},title:{type:"string"},detail:{type:"string"},effort:{type:"string",enum:["S","M","L"]}},additionalProperties:!1}}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"assistant_message"},payload:{type:"object",required:["text"],properties:{text:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"diff_ready"},payload:{type:"object",required:["unifiedDiff","diffStat","branch"],properties:{unifiedDiff:{type:"string"},diffStat:{type:"string"},branch:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"approval_required"},payload:{type:"object",required:["approvalId","action","summary","details"],properties:{approvalId:{type:"string"},action:{type:"string",enum:["git.commit","git.push","other"]},summary:{type:"string"},details:{type:"object",additionalProperties:!0}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"approved"},payload:{type:"object",required:["approvalId"],properties:{approvalId:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"denied"},payload:{type:"object",required:["approvalId"],properties:{approvalId:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"committed"},payload:{type:"object",required:["branch","commitHash","message"],properties:{branch:{type:"string"},commitHash:{type:"string"},message:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"error"},payload:{type:"object",required:["message"],properties:{message:{type:"string"},detail:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"done"},payload:{type:"object",required:["ok"],properties:{ok:{type:"boolean"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"agent_status"},payload:{type:"object",required:["agentId","status"],properties:{agentId:{type:"string"},status:{type:"string",enum:["idle","busy","error"]},message:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"task_created"},payload:{type:"object",required:["taskId","title","description","createdBy"],properties:{taskId:{type:"string"},title:{type:"string"},description:{type:"string"},createdBy:{type:"string"},priority:{type:"string"},tags:{type:"array",items:{type:"string"}}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"task_started"},payload:{type:"object",required:["taskId"],properties:{taskId:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"task_progress"},payload:{type:"object",required:["taskId","message"],properties:{taskId:{type:"string"},message:{type:"string"},percent:{type:"number",minimum:0,maximum:100}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"task_completed"},payload:{type:"object",required:["taskId","summary"],properties:{taskId:{type:"string"},summary:{type:"string"},origin:{type:"string",enum:["user","autonomy"]},artifacts:{type:"array",items:{$ref:"#/definitions/artifact"}}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"task_failed"},payload:{type:"object",required:["taskId","message"],properties:{taskId:{type:"string"},message:{type:"string"},detail:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"tool_call"},payload:{type:"object",required:["toolCallId","tool","args"],properties:{toolCallId:{type:"string"},taskId:{type:"string"},tool:{type:"string"},args:{type:"object",additionalProperties:!0},requiresApproval:{type:"boolean"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"tool_result"},payload:{type:"object",required:["toolCallId","ok"],properties:{toolCallId:{type:"string"},taskId:{type:"string"},ok:{type:"boolean"},stdout:{type:"string"},stderr:{type:"string"},exitCode:{type:"integer"},artifacts:{type:"array",items:{$ref:"#/definitions/artifact"}}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"delegate_request"},payload:{type:"object",required:["requestId","toAgentId","input"],properties:{requestId:{type:"string"},toAgentId:{type:"string"},input:{type:"object",additionalProperties:!0}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"delegate_response"},payload:{type:"object",required:["requestId","ok"],properties:{requestId:{type:"string"},ok:{type:"boolean"},output:{type:"object",additionalProperties:!0},error:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"job_enqueued"},payload:{type:"object",required:["jobId","taskId","kind","params"],properties:{jobId:{type:"string"},taskId:{type:"string"},kind:{type:"string"},params:{type:"object",additionalProperties:!0},origin:{type:"string",enum:["user","autonomy"]},autonomy:{type:"object",properties:{objectiveId:{type:"string"},runId:{type:"string"},snapshotId:{type:"string"},patternKey:{type:"string"}},additionalProperties:!1}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"job_claimed"},payload:{type:"object",required:["jobId","workerId"],properties:{jobId:{type:"string"},workerId:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"job_completed"},payload:{type:"object",required:["jobId"],properties:{jobId:{type:"string"},summary:{type:"string"},origin:{type:"string",enum:["user","autonomy"]},artifacts:{type:"array",items:{$ref:"#/definitions/artifact"}}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"job_failed"},payload:{type:"object",required:["jobId","message"],properties:{jobId:{type:"string"},message:{type:"string"},detail:{type:"string"},origin:{type:"string",enum:["user","autonomy"]}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"message"},payload:{type:"object",required:["text"],properties:{text:{type:"string"},intent:{type:"object",additionalProperties:!0}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"job_log"},payload:{type:"object",required:["jobId","stream","seq","line"],properties:{jobId:{type:"string"},stream:{type:"string",enum:["stdout","stderr"]},seq:{type:"integer",minimum:1},line:{type:"string"},ts:{type:"string"},phase:{type:["string","null"]}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"status"},payload:{type:"object",required:["agentId","state"],properties:{agentId:{type:"string"},state:{type:"string",enum:["idle","busy","error","shutting_down"]},uptimeMs:{type:"number"},detail:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"autonomy_cycle_started"},payload:{type:"object",required:["runId","snapshotId"],properties:{runId:{type:"string"},snapshotId:{type:"string"},phase:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"autonomy_candidates_generated"},payload:{type:"object",required:["runId","snapshotId","candidateCount"],properties:{runId:{type:"string"},snapshotId:{type:"string"},candidateCount:{type:"integer",minimum:0},topCandidateIds:{type:"array",items:{type:"string"}}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"autonomy_objective_dispatched"},payload:{type:"object",required:["runId","snapshotId","objectiveId","requestId","patternKey"],properties:{runId:{type:"string"},snapshotId:{type:"string"},objectiveId:{type:"string"},requestId:{type:"string"},patternKey:{type:"string"},origin:{type:"string",enum:["autonomy"]}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"autonomy_objective_blocked"},payload:{type:"object",required:["runId","snapshotId","objectiveId","reason"],properties:{runId:{type:"string"},snapshotId:{type:"string"},objectiveId:{type:"string"},reason:{type:"string"},questionId:{type:"string"},patternKey:{type:"string"},origin:{type:"string",enum:["autonomy"]}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"autonomy_feedback_recorded"},payload:{type:"object",required:["objectiveId","patternKey","outcome","success"],properties:{objectiveId:{type:"string"},patternKey:{type:"string"},outcome:{type:"string"},success:{type:"boolean"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"question_asked"},payload:{type:"object",required:["questionId","objectiveId","question","questionType"],properties:{questionId:{type:"string"},objectiveId:{type:"string"},question:{type:"string"},questionType:{type:"string"}},additionalProperties:!1}},additionalProperties:!1},{type:"object",required:["type","payload"],properties:{type:{const:"question_answered"},payload:{type:"object",required:["questionId","objectiveId","status"],properties:{questionId:{type:"string"},objectiveId:{type:"string"},status:{type:"string",enum:["valid","invalid"]},answerSummary:{type:"string"}},additionalProperties:!1}},additionalProperties:!1}]}},1103,[]);
1121
1121
  __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.usePushPalsSession=function(p="http://localhost:3001"){const v="string"==typeof p?{baseUrl:p}:p??{},f=String(v.baseUrl??"http://localhost:3001").trim().replace(/\/+$/,""),y=String(v.sessionId??"dev").trim()||"dev",I=String(v.authToken??"").trim()||void 0,b=v.clientInfo,[k,h]=(0,t.useState)({sessionId:null,events:[],isConnected:!1,error:null}),[S,_]=(0,t.useReducer)(o.eventReducer,(0,o.initialState)()),[w,C]=(0,t.useState)({}),M=(0,t.useRef)(null),j=(0,t.useRef)(0),R=(0,t.useRef)(null);(0,t.useEffect)(()=>((async()=>{try{const t=await(0,n.resolveClientRegistration)(b,y);R.current=t;const o=await(0,s.createSession)(f,y,I,t);if(!o)return void h(t=>({...t,error:"Failed to create session"}));const c=o.sessionId;h(t=>({...t,sessionId:c,isConnected:!0}));const p=o.created?0:await l(c);j.current=p,o.created&&(0,u.setItem)(`pushpals:cursor:${c}`,"0");const v=(0,s.subscribeEvents)(f,c,(t,s)=>{h(s=>({...s,events:[...s.events,t]})),_({type:"event",envelope:t,cursor:s}),s>j.current&&(j.current=s,(0,u.setItem)(`pushpals:cursor:${c}`,String(s)))},void 0,p,I,t);M.current=v}catch(t){h(s=>({...s,error:String(t)}))}})(),()=>{M.current&&M.current()}),[I,f,y]);const A=(0,t.useCallback)(async t=>!!k.sessionId&&(0,s.sendSessionMessage)(f,k.sessionId,t),[f,k.sessionId]),E=(0,t.useCallback)(async t=>(0,s.submitApprovalDecision)(f,t,"approve",I),[I,f]),F=(0,t.useCallback)(async t=>(0,s.submitApprovalDecision)(f,t,"deny",I),[I,f]),T=(0,t.useMemo)(()=>{const t=new Set;for(const s of k.events)s.from&&t.add(s.from);return Array.from(t).sort()},[k.events]),$=(0,t.useMemo)(()=>{const t=new Set;for(const s of k.events)s.turnId&&t.add(s.turnId);return Array.from(t)},[k.events]),D=(0,t.useMemo)(()=>{const t=new Map,s=new Map;for(const n of k.events){const o=n.payload,u="string"==typeof o?.taskId?o.taskId:void 0,c="string"==typeof o?.jobId?o.jobId:void 0;"job_enqueued"===n.type&&u&&c&&s.set(c,u);const l=u??("job_failed"===n.type&&c?s.get(c):void 0);if(!l)continue;t.has(l)||t.set(l,{taskId:l,title:o.title??l,status:"created",events:[]});const p=t.get(l);p.events.push(n),p.title&&p.title!==l||"string"!=typeof o?.title||!o.title.trim()||(p.title=o.title),"task_started"===n.type?p.status="started":"task_progress"===n.type?p.status="in_progress":"task_completed"===n.type?p.status="completed":("task_failed"===n.type||"job_failed"===n.type&&"completed"!==p.status)&&(p.status="failed")}return Array.from(t.values())},[k.events]),P=(0,t.useMemo)(()=>k.events.filter(t=>{if(!(0,c.shouldDisplayInteractiveSessionEvent)(t))return!1;if(w.agentFrom&&t.from!==w.agentFrom)return!1;if(w.turnId&&t.turnId!==w.turnId)return!1;if(w.taskId){const s=t.payload;if(s?.taskId!==w.taskId)return!1}return!(w.eventTypes&&w.eventTypes.length>0&&!w.eventTypes.includes(t.type))}),[k.events,w]);return{sessionId:k.sessionId,events:k.events,filteredEvents:P,isConnected:k.isConnected,error:k.error,send:A,approve:E,deny:F,tasks:D,agents:T,turnIds:$,filters:w,setFilters:C,state:S}};var t=r(d[0]),s=r(d[1]),n=r(d[2]),o=r(d[3]),u=r(d[4]),c=r(d[5]);async function l(t){const s=await(0,u.getItem)(`pushpals:cursor:${t}`);return s&&Number(s)||0}},1104,[21,1028,1105,1114,1106,1026]);
1122
1122
  __d(function(g,r,i,a,m,e,d){"use strict";async function t(t){const n=await r(d[1])(d[0],d.paths);return await n.getItem(t)}async function n(t,n){const o=await r(d[1])(d[0],d.paths);await o.setItem(t,n)}function o(t,n){const o=String(t??"").trim();return o?o.length<=n?o:o.slice(0,n):""}function c(t){switch(t){case"cli_monitor":return"CLI Monitor";case"web":return"Web Client";case"vscode":return"VS Code";case"cli":return"CLI";default:return t||"Client"}}function l(t){const n=o(t,48).toLowerCase();return n&&n.replace(/[^a-z0-9._-]+/g,"_")||"web"}function s(t,n){return`pushpals:client-id:${l(t)}:${o(n,128)||"dev"}`}function u(t){return"function"==typeof globalThis.crypto?.randomUUID?`${t}-${globalThis.crypto.randomUUID()}`:`${t}-${Date.now()}-${Math.random().toString(16).slice(2)}`}Object.defineProperty(e,'__esModule',{value:!0}),e.normalizeClientKind=l,e.buildClientIdentityStorageKey=s,e.defaultClientIdFactory=u,e.resolveClientRegistration=async function(f,p,w={}){const I=l(f?.kind),y=o(f?.clientId,128),C=w.read??t,b=w.write??n,h=w.createId??u;let $=y;if(!$){const t=s(I,p);$=o(await C(t),128),$||($=h(I),await b(t,$))}const _=o(f?.label,120)||c(I),v=o(f?.version,64),S=o(f?.platform,120),U=o(f?.repoRoot,400);return{clientId:$,kind:I,label:_,...v?{version:v}:{},...S?{platform:S}:{},...U?{repoRoot:U}:{}}}},1105,{"0":1106,"1":1112,"paths":{}});
1123
1123
  __d(function(g,r,i,a,m,e,d){"use strict";let t;Object.defineProperty(e,'__esModule',{value:!0}),e.getItem=async function(t){try{return window.localStorage?.getItem(t)??null}catch{return null}try{const n=await s();return n?await n.getItem(t)??null:null}catch{return null}},e.setItem=async function(t,n){try{window.localStorage?.setItem(t,n)}catch{}return},r(d[0]);let n=null,l=!1;async function s(){return void 0!==t?t:n||(n=(async()=>{try{const n=await r(d[2])(d[1],d.paths,"@react-native-async-storage/async-storage"),l=n.default??n;if(!l?.getItem||!l?.setItem)throw new Error("module loaded but getItem/setItem missing");return t=l,t}catch{return t=null,l||(l=!0,console.warn("[PushPals] @react-native-async-storage/async-storage is not available. Cursor persistence disabled on native. Install with: bun add @react-native-async-storage/async-storage")),null}finally{n=null}})(),n)}},1106,{"0":114,"1":1202,"2":1112,"paths":{"1202":"/_expo/static/js/web/index-ec13ec62e2b37ed3c5f6d324ef6784e1.js"}});
@@ -435,5 +435,5 @@ input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-web
435
435
  @keyframes r-1pzkwqh{0%{transform:translateY(100%);}100%{transform:translateY(0%);}}
436
436
  @keyframes r-imtty0{0%{opacity:0;}100%{opacity:1;}}
437
437
  @keyframes r-q67da2{0%{transform:translateX(-100%);}100%{transform:translateX(400%);}}
438
- @keyframes r-t2lo5v{0%{opacity:1;}100%{opacity:0;}}</style><script type="module">globalThis.__EXPO_ROUTER_HYDRATE__=true;</script><link rel="icon" href="/favicon.ico" /></head><body><div id="root"><div class="css-g5y9jx r-13awgt0"></div></div><script src="/_expo/static/js/web/entry-ff425ab85ad13c1920b8ee00abfae7dd.js" defer></script>
438
+ @keyframes r-t2lo5v{0%{opacity:1;}100%{opacity:0;}}</style><script type="module">globalThis.__EXPO_ROUTER_HYDRATE__=true;</script><link rel="icon" href="/favicon.ico" /></head><body><div id="root"><div class="css-g5y9jx r-13awgt0"></div></div><script src="/_expo/static/js/web/entry-e8aa7049f746aaa8f1e865615e248f21.js" defer></script>
439
439
  </body></html>
@@ -435,5 +435,5 @@ input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-web
435
435
  @keyframes r-1pzkwqh{0%{transform:translateY(100%);}100%{transform:translateY(0%);}}
436
436
  @keyframes r-imtty0{0%{opacity:0;}100%{opacity:1;}}
437
437
  @keyframes r-q67da2{0%{transform:translateX(-100%);}100%{transform:translateX(400%);}}
438
- @keyframes r-t2lo5v{0%{opacity:1;}100%{opacity:0;}}</style><script type="module">globalThis.__EXPO_ROUTER_HYDRATE__=true;</script><link rel="icon" href="/favicon.ico" /></head><body><div id="root"><div class="css-g5y9jx r-13awgt0"><!--$--><div style="position:absolute;left:0;right:0;top:0;bottom:0;pointer-events:none;visibility:hidden"></div><div class="css-g5y9jx r-13awgt0"><div class="css-g5y9jx r-13awgt0 r-1p0dtai r-1d2f490 r-u8s1d r-zchlnj r-ipm5af" style="background-color:rgba(242,242,242,1.00);display:flex"><div class="css-g5y9jx r-13awgt0"><div class="css-g5y9jx r-13awgt0"><!--$--><div class="css-g5y9jx r-13awgt0" style="background-color:rgba(236,242,245,1.00)"><div class="css-g5y9jx r-13awgt0"><div class="css-g5y9jx r-cpet4d r-u8s1d r-g7s1ez r-15zx4ds r-a4e7m4 r-j33s3c r-1ovo9ad" style="background-color:rgba(0,126,119,0.13)"></div><div class="css-g5y9jx r-cpet4d r-u8s1d r-g7s1ez r-5fjp4n r-9s5a0n r-1hy2ut r-9dcw1g" style="background-color:rgba(199,133,30,0.09)"></div><div class="css-g5y9jx r-cpet4d r-u8s1d r-g7s1ez r-1iuttuq r-pbsvq8 r-1b0pg27 r-1sxiqef" style="background-color:rgba(22,154,88,0.09)"></div><div class="css-g5y9jx r-150rngu r-eqz5dr r-16y2uox r-1wbh5a2 r-11yh6sk r-1rnoaur r-agouwx r-13awgt0"><div class="css-g5y9jx r-16y2uox r-2llsf r-kzbkwu"><div class="css-g5y9jx r-16uyjmq r-rs99b7 r-13awgt0 r-hv52eu r-ifefl9 r-1udh08x" style="background-color:rgba(247,250,252,1.00);border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);opacity:0;transform:translateY(18px)"><div class="css-g5y9jx r-1habvwh r-18u37iz r-1wtj0ep r-kzbkwu r-u9wvl5 r-131miar"><div class="css-g5y9jx r-13awgt0 r-j2kj52"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1q67n59 r-15zivkp r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">pushpals operations console</div><div dir="auto" class="css-146c3p1 r-1ra0lkn r-b88u0q r-zl2h9q" style="color:rgba(17,34,48,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Mission Control</div><div dir="auto" class="css-146c3p1 r-n6v787 r-hjklzo r-1cmskyw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Coordinate your edits with autonomous buddy execution across planning, jobs, and integration in one live board.</div><div dir="auto" class="css-146c3p1 r-1enofrn r-5fcqz0 r-kc8jnq" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Current repo:<!-- --> <span class="css-1jxf684 r-1enofrn" style="color:rgba(84,112,134,1.00);font-family:&#x27;IBM Plex Mono&#x27;, &#x27;JetBrains Mono&#x27;, monospace">unavailable</span></div><div dir="auto" class="css-146c3p1 r-1enofrn r-5fcqz0 r-14gqq1x" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Snapshot:<!-- --> <span class="css-1jxf684 r-1enofrn" style="color:rgba(17,34,48,1.00);font-family:&#x27;IBM Plex Mono&#x27;, &#x27;JetBrains Mono&#x27;, monospace">waiting for /system/status</span></div></div><div class="css-g5y9jx r-k200y r-1q9bdsx r-rs99b7 r-18u37iz r-1udh08x" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><button aria-label="Set theme mode to auto" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1yd117h r-1ubuhtd" style="background-color:rgba(217,244,241,1.00)" type="button"><div dir="auto" class="css-146c3p1 r-1enofrn r-1kfrs79 r-1ozqkpa" style="color:rgba(2,92,86,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">auto</div></button><button aria-label="Set theme mode to light" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1yd117h r-1ubuhtd" type="button"><div dir="auto" class="css-146c3p1 r-1enofrn r-1kfrs79 r-1ozqkpa" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">light</div></button><button aria-label="Set theme mode to dark" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1yd117h r-1ubuhtd" type="button"><div dir="auto" class="css-146c3p1 r-1enofrn r-1kfrs79 r-1ozqkpa" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">dark</div></button></div></div><div class="css-g5y9jx r-t23y2h r-rs99b7 r-15d164r r-bhtmuz r-ytbthy r-1ubuhtd" style="background-color:rgba(244,248,251,1.00);border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00)"><div class="css-g5y9jx r-150rngu r-18u37iz r-16y2uox r-1wbh5a2 r-lltvgl r-buy8e9 r-agouwx r-2eszeu"><div class="css-g5y9jx r-18u37iz"><div class="css-g5y9jx r-1awozwy r-18u37iz"><div class="css-g5y9jx r-1q9bdsx r-rs99b7 r-1s5swlz r-1ubuhtd r-13i4ljo" style="border-top-color:rgba(199,133,30,0.40);border-right-color:rgba(199,133,30,0.40);border-bottom-color:rgba(199,133,30,0.40);border-left-color:rgba(199,133,30,0.40);background-color:rgba(199,133,30,0.09)"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1gkfh8e r-b88u0q r-1dpkw9 r-tsynxw" style="color:rgba(199,133,30,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">1. You</div><div dir="auto" class="css-146c3p1 r-8akbws r-krxsd3 r-dnmrzs r-1qsk4np r-1udbk01 r-1enofrn r-1cwl3u0 r-14gqq1x" style="-webkit-line-clamp:2;color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Awaiting input</div></div><div class="css-g5y9jx r-109y4c4 r-8dgmk1 r-12ym1je" style="background-color:rgba(207,218,226,0.80)"></div></div><div class="css-g5y9jx r-1awozwy r-18u37iz"><div class="css-g5y9jx r-1q9bdsx r-rs99b7 r-1s5swlz r-1ubuhtd r-13i4ljo" style="border-top-color:rgba(0,126,119,0.40);border-right-color:rgba(0,126,119,0.40);border-bottom-color:rgba(0,126,119,0.40);border-left-color:rgba(0,126,119,0.40);background-color:rgba(0,126,119,0.09)"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1gkfh8e r-b88u0q r-1dpkw9 r-tsynxw" style="color:rgba(0,126,119,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">2. Session</div><div dir="auto" class="css-146c3p1 r-8akbws r-krxsd3 r-dnmrzs r-1qsk4np r-1udbk01 r-1enofrn r-1cwl3u0 r-14gqq1x" style="-webkit-line-clamp:2;color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Ready</div></div><div class="css-g5y9jx r-109y4c4 r-8dgmk1 r-12ym1je" style="background-color:rgba(207,218,226,0.80)"></div></div><div class="css-g5y9jx r-1awozwy r-18u37iz"><div class="css-g5y9jx r-1q9bdsx r-rs99b7 r-1s5swlz r-1ubuhtd r-13i4ljo" style="border-top-color:rgba(22,154,88,0.40);border-right-color:rgba(22,154,88,0.40);border-bottom-color:rgba(22,154,88,0.40);border-left-color:rgba(22,154,88,0.40);background-color:rgba(22,154,88,0.09)"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1gkfh8e r-b88u0q r-1dpkw9 r-tsynxw" style="color:rgba(22,154,88,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">3. RemoteBuddy</div><div dir="auto" class="css-146c3p1 r-8akbws r-krxsd3 r-dnmrzs r-1qsk4np r-1udbk01 r-1enofrn r-1cwl3u0 r-14gqq1x" style="-webkit-line-clamp:2;color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 pending, 0 claimed</div></div><div class="css-g5y9jx r-109y4c4 r-8dgmk1 r-12ym1je" style="background-color:rgba(207,218,226,0.80)"></div></div><div class="css-g5y9jx r-1awozwy r-18u37iz"><div class="css-g5y9jx r-1q9bdsx r-rs99b7 r-1s5swlz r-1ubuhtd r-13i4ljo" style="border-top-color:rgba(22,154,88,0.40);border-right-color:rgba(22,154,88,0.40);border-bottom-color:rgba(22,154,88,0.40);border-left-color:rgba(22,154,88,0.40);background-color:rgba(22,154,88,0.09)"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1gkfh8e r-b88u0q r-1dpkw9 r-tsynxw" style="color:rgba(22,154,88,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">4. WorkerPals</div><div dir="auto" class="css-146c3p1 r-8akbws r-krxsd3 r-dnmrzs r-1qsk4np r-1udbk01 r-1enofrn r-1cwl3u0 r-14gqq1x" style="-webkit-line-clamp:2;color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 online, 0 busy, 0 queued</div></div><div class="css-g5y9jx r-109y4c4 r-8dgmk1 r-12ym1je" style="background-color:rgba(207,218,226,0.80)"></div></div><div class="css-g5y9jx r-1awozwy r-18u37iz"><div class="css-g5y9jx r-1q9bdsx r-rs99b7 r-1s5swlz r-1ubuhtd r-13i4ljo" style="border-top-color:rgba(0,126,119,0.40);border-right-color:rgba(0,126,119,0.40);border-bottom-color:rgba(0,126,119,0.40);border-left-color:rgba(0,126,119,0.40);background-color:rgba(0,126,119,0.09)"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1gkfh8e r-b88u0q r-1dpkw9 r-tsynxw" style="color:rgba(0,126,119,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">5. SCM</div><div dir="auto" class="css-146c3p1 r-8akbws r-krxsd3 r-dnmrzs r-1qsk4np r-1udbk01 r-1enofrn r-1cwl3u0 r-14gqq1x" style="-webkit-line-clamp:2;color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 ready, 0 pending</div></div></div></div></div></div><div class="css-g5y9jx r-18u37iz r-1w6e6rj r-1mi0q7o r-u9wvl5"><div class="css-g5y9jx r-t23y2h r-rs99b7 r-16y2uox r-5oul0u r-1kb76zh r-bgnin r-ytbthy r-3o4zer" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1cm7zt9 r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Connection</div><div dir="auto" class="css-146c3p1 r-evnaw r-b88u0q r-19qrga8" style="color:rgba(214,69,83,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Disconnected</div><div dir="auto" class="css-146c3p1 r-1enofrn r-19qrga8" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 events</div></div><div class="css-g5y9jx r-t23y2h r-rs99b7 r-16y2uox r-5oul0u r-1kb76zh r-bgnin r-ytbthy r-3o4zer" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1cm7zt9 r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Pending Work</div><div dir="auto" class="css-146c3p1 r-evnaw r-b88u0q r-19qrga8" style="color:rgba(22,154,88,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0</div><div dir="auto" class="css-146c3p1 r-1enofrn r-19qrga8" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 requests | 0 jobs</div></div><div class="css-g5y9jx r-t23y2h r-rs99b7 r-16y2uox r-5oul0u r-1kb76zh r-bgnin r-ytbthy r-3o4zer" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1cm7zt9 r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Active Workers</div><div dir="auto" class="css-146c3p1 r-evnaw r-b88u0q r-19qrga8" style="color:rgba(0,126,119,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0</div><div dir="auto" class="css-146c3p1 r-1enofrn r-19qrga8" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 busy</div></div><div class="css-g5y9jx r-t23y2h r-rs99b7 r-16y2uox r-5oul0u r-1kb76zh r-bgnin r-ytbthy r-3o4zer" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1cm7zt9 r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Last Sync</div><div dir="auto" class="css-146c3p1 r-evnaw r-b88u0q r-19qrga8" style="color:rgba(0,126,119,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">--</div><div dir="auto" class="css-146c3p1 r-1enofrn r-19qrga8" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">waiting</div></div></div><div class="css-g5y9jx r-t23y2h r-rs99b7 r-18u37iz r-15d164r r-bhtmuz r-146eth8" style="background-color:rgba(244,248,251,1.00);border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00)"><button aria-label="Coordination tab" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1awozwy r-1dzdj1l r-rs99b7 r-13awgt0 r-1777fci r-11f147o r-1ubuhtd" style="background-color:rgba(0,126,119,1.00);border-top-color:rgba(0,126,119,1.00);border-right-color:rgba(0,126,119,1.00);border-bottom-color:rgba(0,126,119,1.00);border-left-color:rgba(0,126,119,1.00)" type="button"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1enofrn r-b88u0q" style="color:rgba(255,255,255,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Coordination<!-- --> (0)</div></button><button aria-label="Chat tab" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1awozwy r-42olwf r-1dzdj1l r-rs99b7 r-13awgt0 r-1777fci r-11f147o r-1ubuhtd" type="button"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1enofrn r-b88u0q" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Chat<!-- --> (0)</div></button><button aria-label="Requests tab" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1awozwy r-42olwf r-1dzdj1l r-rs99b7 r-13awgt0 r-1777fci r-11f147o r-1ubuhtd" type="button"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1enofrn r-b88u0q" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Requests<!-- --> (0)</div></button><button aria-label="Jobs &amp; Traces tab" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1awozwy r-42olwf r-1dzdj1l r-rs99b7 r-13awgt0 r-1777fci r-11f147o r-1ubuhtd" type="button"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1enofrn r-b88u0q" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Jobs &amp; Traces<!-- --> (0)</div></button><button aria-label="System tab" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1awozwy r-42olwf r-1dzdj1l r-rs99b7 r-13awgt0 r-1777fci r-11f147o r-1ubuhtd" type="button"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1enofrn r-b88u0q" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">System<!-- --> (0)</div></button><button aria-label="Config tab" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1awozwy r-42olwf r-1dzdj1l r-rs99b7 r-13awgt0 r-1777fci r-11f147o r-1ubuhtd" type="button"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1enofrn r-b88u0q" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Config</div></button></div><div class="css-g5y9jx r-13awgt0 r-ifefl9" style="opacity:1;transform:translateY(0px)"><div class="css-g5y9jx r-150rngu r-eqz5dr r-16y2uox r-1wbh5a2 r-11yh6sk r-1rnoaur r-agouwx r-13awgt0"><div class="css-g5y9jx r-1t2hasf r-u9wvl5"><div class="css-g5y9jx r-18u37iz r-1w6e6rj r-1mi0q7o"><div class="css-g5y9jx r-t23y2h r-rs99b7 r-16y2uox r-5oul0u r-1kb76zh r-bgnin r-ytbthy r-3o4zer" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1cm7zt9 r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Ready For Review</div><div dir="auto" class="css-146c3p1 r-evnaw r-b88u0q r-19qrga8" style="color:rgba(0,126,119,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0</div><div dir="auto" class="css-146c3p1 r-1enofrn r-19qrga8" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 processed completions</div></div><div class="css-g5y9jx r-t23y2h r-rs99b7 r-16y2uox r-5oul0u r-1kb76zh r-bgnin r-ytbthy r-3o4zer" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1cm7zt9 r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Active Handoffs</div><div dir="auto" class="css-146c3p1 r-evnaw r-b88u0q r-19qrga8" style="color:rgba(0,126,119,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0</div><div dir="auto" class="css-146c3p1 r-1enofrn r-19qrga8" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 running jobs</div></div><div class="css-g5y9jx r-t23y2h r-rs99b7 r-16y2uox r-5oul0u r-1kb76zh r-bgnin r-ytbthy r-3o4zer" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1cm7zt9 r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Awaiting Remote</div><div dir="auto" class="css-146c3p1 r-evnaw r-b88u0q r-19qrga8" style="color:rgba(22,154,88,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0</div><div dir="auto" class="css-146c3p1 r-1enofrn r-19qrga8" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 pending requests</div></div><div class="css-g5y9jx r-t23y2h r-rs99b7 r-16y2uox r-5oul0u r-1kb76zh r-bgnin r-ytbthy r-3o4zer" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1cm7zt9 r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Blocked</div><div dir="auto" class="css-146c3p1 r-evnaw r-b88u0q r-19qrga8" style="color:rgba(22,154,88,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0</div><div dir="auto" class="css-146c3p1 r-1enofrn r-19qrga8" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 failed jobs</div></div></div><div class="css-g5y9jx r-eqz5dr"><div class="css-g5y9jx r-1867qdf r-rs99b7 r-k3250r r-15d164r r-xyw6el" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(255,255,255,1.00)"><div class="css-g5y9jx r-1awozwy r-18u37iz r-1wtj0ep"><div dir="auto" class="css-146c3p1 r-ubezar r-b88u0q r-5oul0u" style="color:rgba(17,34,48,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Change Coordination Board</div><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1g94qm0" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0<!-- --> latest requests</div></div><div class="css-g5y9jx r-1habvwh r-1867qdf r-nsbfu8"><div dir="auto" class="css-146c3p1 r-1i10wst r-b88u0q r-15zivkp" style="color:rgba(17,34,48,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Nothing to coordinate yet</div><div dir="auto" class="css-146c3p1 r-n6v787 r-hjklzo" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Send a task from chat and this board will trace the full handoff from request to integration.</div></div></div><div class="css-g5y9jx r-1867qdf r-rs99b7 r-jprt8p r-15d164r r-11wrixw r-xyw6el" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(255,255,255,1.00)"><div dir="auto" class="css-146c3p1 r-ubezar r-b88u0q r-5oul0u" style="color:rgba(17,34,48,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Review Queue</div><div dir="auto" class="css-146c3p1 r-n6v787 r-hjklzo" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">No processed completions yet.</div><div dir="auto" class="css-146c3p1 r-ubezar r-b88u0q r-5oul0u" style="color:rgba(17,34,48,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif;margin-top:14px">Needs Attention</div><div dir="auto" class="css-146c3p1 r-n6v787 r-hjklzo" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">No failed coordination chains.</div></div></div></div></div></div></div></div></div></div></div><!--/$--></div></div></div></div><!--/$--></div></div><script src="/_expo/static/js/web/entry-ff425ab85ad13c1920b8ee00abfae7dd.js" defer></script>
438
+ @keyframes r-t2lo5v{0%{opacity:1;}100%{opacity:0;}}</style><script type="module">globalThis.__EXPO_ROUTER_HYDRATE__=true;</script><link rel="icon" href="/favicon.ico" /></head><body><div id="root"><div class="css-g5y9jx r-13awgt0"><!--$--><div style="position:absolute;left:0;right:0;top:0;bottom:0;pointer-events:none;visibility:hidden"></div><div class="css-g5y9jx r-13awgt0"><div class="css-g5y9jx r-13awgt0 r-1p0dtai r-1d2f490 r-u8s1d r-zchlnj r-ipm5af" style="background-color:rgba(242,242,242,1.00);display:flex"><div class="css-g5y9jx r-13awgt0"><div class="css-g5y9jx r-13awgt0"><!--$--><div class="css-g5y9jx r-13awgt0" style="background-color:rgba(236,242,245,1.00)"><div class="css-g5y9jx r-13awgt0"><div class="css-g5y9jx r-cpet4d r-u8s1d r-g7s1ez r-15zx4ds r-a4e7m4 r-j33s3c r-1ovo9ad" style="background-color:rgba(0,126,119,0.13)"></div><div class="css-g5y9jx r-cpet4d r-u8s1d r-g7s1ez r-5fjp4n r-9s5a0n r-1hy2ut r-9dcw1g" style="background-color:rgba(199,133,30,0.09)"></div><div class="css-g5y9jx r-cpet4d r-u8s1d r-g7s1ez r-1iuttuq r-pbsvq8 r-1b0pg27 r-1sxiqef" style="background-color:rgba(22,154,88,0.09)"></div><div class="css-g5y9jx r-150rngu r-eqz5dr r-16y2uox r-1wbh5a2 r-11yh6sk r-1rnoaur r-agouwx r-13awgt0"><div class="css-g5y9jx r-16y2uox r-2llsf r-kzbkwu"><div class="css-g5y9jx r-16uyjmq r-rs99b7 r-13awgt0 r-hv52eu r-ifefl9 r-1udh08x" style="background-color:rgba(247,250,252,1.00);border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);opacity:0;transform:translateY(18px)"><div class="css-g5y9jx r-1habvwh r-18u37iz r-1wtj0ep r-kzbkwu r-u9wvl5 r-131miar"><div class="css-g5y9jx r-13awgt0 r-j2kj52"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1q67n59 r-15zivkp r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">pushpals operations console</div><div dir="auto" class="css-146c3p1 r-1ra0lkn r-b88u0q r-zl2h9q" style="color:rgba(17,34,48,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Mission Control</div><div dir="auto" class="css-146c3p1 r-n6v787 r-hjklzo r-1cmskyw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Coordinate your edits with autonomous buddy execution across planning, jobs, and integration in one live board.</div><div dir="auto" class="css-146c3p1 r-1enofrn r-5fcqz0 r-kc8jnq" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Current repo:<!-- --> <span class="css-1jxf684 r-1enofrn" style="color:rgba(84,112,134,1.00);font-family:&#x27;IBM Plex Mono&#x27;, &#x27;JetBrains Mono&#x27;, monospace">unavailable</span></div><div dir="auto" class="css-146c3p1 r-1enofrn r-5fcqz0 r-14gqq1x" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Snapshot:<!-- --> <span class="css-1jxf684 r-1enofrn" style="color:rgba(17,34,48,1.00);font-family:&#x27;IBM Plex Mono&#x27;, &#x27;JetBrains Mono&#x27;, monospace">waiting for /system/status</span></div></div><div class="css-g5y9jx r-k200y r-1q9bdsx r-rs99b7 r-18u37iz r-1udh08x" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><button aria-label="Set theme mode to auto" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1yd117h r-1ubuhtd" style="background-color:rgba(217,244,241,1.00)" type="button"><div dir="auto" class="css-146c3p1 r-1enofrn r-1kfrs79 r-1ozqkpa" style="color:rgba(2,92,86,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">auto</div></button><button aria-label="Set theme mode to light" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1yd117h r-1ubuhtd" type="button"><div dir="auto" class="css-146c3p1 r-1enofrn r-1kfrs79 r-1ozqkpa" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">light</div></button><button aria-label="Set theme mode to dark" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1yd117h r-1ubuhtd" type="button"><div dir="auto" class="css-146c3p1 r-1enofrn r-1kfrs79 r-1ozqkpa" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">dark</div></button></div></div><div class="css-g5y9jx r-t23y2h r-rs99b7 r-15d164r r-bhtmuz r-ytbthy r-1ubuhtd" style="background-color:rgba(244,248,251,1.00);border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00)"><div class="css-g5y9jx r-150rngu r-18u37iz r-16y2uox r-1wbh5a2 r-lltvgl r-buy8e9 r-agouwx r-2eszeu"><div class="css-g5y9jx r-18u37iz"><div class="css-g5y9jx r-1awozwy r-18u37iz"><div class="css-g5y9jx r-1q9bdsx r-rs99b7 r-1s5swlz r-1ubuhtd r-13i4ljo" style="border-top-color:rgba(199,133,30,0.40);border-right-color:rgba(199,133,30,0.40);border-bottom-color:rgba(199,133,30,0.40);border-left-color:rgba(199,133,30,0.40);background-color:rgba(199,133,30,0.09)"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1gkfh8e r-b88u0q r-1dpkw9 r-tsynxw" style="color:rgba(199,133,30,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">1. You</div><div dir="auto" class="css-146c3p1 r-8akbws r-krxsd3 r-dnmrzs r-1qsk4np r-1udbk01 r-1enofrn r-1cwl3u0 r-14gqq1x" style="-webkit-line-clamp:2;color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Awaiting input</div></div><div class="css-g5y9jx r-109y4c4 r-8dgmk1 r-12ym1je" style="background-color:rgba(207,218,226,0.80)"></div></div><div class="css-g5y9jx r-1awozwy r-18u37iz"><div class="css-g5y9jx r-1q9bdsx r-rs99b7 r-1s5swlz r-1ubuhtd r-13i4ljo" style="border-top-color:rgba(0,126,119,0.40);border-right-color:rgba(0,126,119,0.40);border-bottom-color:rgba(0,126,119,0.40);border-left-color:rgba(0,126,119,0.40);background-color:rgba(0,126,119,0.09)"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1gkfh8e r-b88u0q r-1dpkw9 r-tsynxw" style="color:rgba(0,126,119,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">2. Session</div><div dir="auto" class="css-146c3p1 r-8akbws r-krxsd3 r-dnmrzs r-1qsk4np r-1udbk01 r-1enofrn r-1cwl3u0 r-14gqq1x" style="-webkit-line-clamp:2;color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Ready</div></div><div class="css-g5y9jx r-109y4c4 r-8dgmk1 r-12ym1je" style="background-color:rgba(207,218,226,0.80)"></div></div><div class="css-g5y9jx r-1awozwy r-18u37iz"><div class="css-g5y9jx r-1q9bdsx r-rs99b7 r-1s5swlz r-1ubuhtd r-13i4ljo" style="border-top-color:rgba(22,154,88,0.40);border-right-color:rgba(22,154,88,0.40);border-bottom-color:rgba(22,154,88,0.40);border-left-color:rgba(22,154,88,0.40);background-color:rgba(22,154,88,0.09)"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1gkfh8e r-b88u0q r-1dpkw9 r-tsynxw" style="color:rgba(22,154,88,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">3. RemoteBuddy</div><div dir="auto" class="css-146c3p1 r-8akbws r-krxsd3 r-dnmrzs r-1qsk4np r-1udbk01 r-1enofrn r-1cwl3u0 r-14gqq1x" style="-webkit-line-clamp:2;color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 pending, 0 claimed</div></div><div class="css-g5y9jx r-109y4c4 r-8dgmk1 r-12ym1je" style="background-color:rgba(207,218,226,0.80)"></div></div><div class="css-g5y9jx r-1awozwy r-18u37iz"><div class="css-g5y9jx r-1q9bdsx r-rs99b7 r-1s5swlz r-1ubuhtd r-13i4ljo" style="border-top-color:rgba(22,154,88,0.40);border-right-color:rgba(22,154,88,0.40);border-bottom-color:rgba(22,154,88,0.40);border-left-color:rgba(22,154,88,0.40);background-color:rgba(22,154,88,0.09)"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1gkfh8e r-b88u0q r-1dpkw9 r-tsynxw" style="color:rgba(22,154,88,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">4. WorkerPals</div><div dir="auto" class="css-146c3p1 r-8akbws r-krxsd3 r-dnmrzs r-1qsk4np r-1udbk01 r-1enofrn r-1cwl3u0 r-14gqq1x" style="-webkit-line-clamp:2;color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 online, 0 busy, 0 queued</div></div><div class="css-g5y9jx r-109y4c4 r-8dgmk1 r-12ym1je" style="background-color:rgba(207,218,226,0.80)"></div></div><div class="css-g5y9jx r-1awozwy r-18u37iz"><div class="css-g5y9jx r-1q9bdsx r-rs99b7 r-1s5swlz r-1ubuhtd r-13i4ljo" style="border-top-color:rgba(0,126,119,0.40);border-right-color:rgba(0,126,119,0.40);border-bottom-color:rgba(0,126,119,0.40);border-left-color:rgba(0,126,119,0.40);background-color:rgba(0,126,119,0.09)"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1gkfh8e r-b88u0q r-1dpkw9 r-tsynxw" style="color:rgba(0,126,119,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">5. SCM</div><div dir="auto" class="css-146c3p1 r-8akbws r-krxsd3 r-dnmrzs r-1qsk4np r-1udbk01 r-1enofrn r-1cwl3u0 r-14gqq1x" style="-webkit-line-clamp:2;color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 ready, 0 pending</div></div></div></div></div></div><div class="css-g5y9jx r-18u37iz r-1w6e6rj r-1mi0q7o r-u9wvl5"><div class="css-g5y9jx r-t23y2h r-rs99b7 r-16y2uox r-5oul0u r-1kb76zh r-bgnin r-ytbthy r-3o4zer" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1cm7zt9 r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Connection</div><div dir="auto" class="css-146c3p1 r-evnaw r-b88u0q r-19qrga8" style="color:rgba(214,69,83,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Disconnected</div><div dir="auto" class="css-146c3p1 r-1enofrn r-19qrga8" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 events</div></div><div class="css-g5y9jx r-t23y2h r-rs99b7 r-16y2uox r-5oul0u r-1kb76zh r-bgnin r-ytbthy r-3o4zer" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1cm7zt9 r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Pending Work</div><div dir="auto" class="css-146c3p1 r-evnaw r-b88u0q r-19qrga8" style="color:rgba(22,154,88,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0</div><div dir="auto" class="css-146c3p1 r-1enofrn r-19qrga8" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 requests | 0 jobs</div></div><div class="css-g5y9jx r-t23y2h r-rs99b7 r-16y2uox r-5oul0u r-1kb76zh r-bgnin r-ytbthy r-3o4zer" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1cm7zt9 r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Active Workers</div><div dir="auto" class="css-146c3p1 r-evnaw r-b88u0q r-19qrga8" style="color:rgba(0,126,119,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0</div><div dir="auto" class="css-146c3p1 r-1enofrn r-19qrga8" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 busy</div></div><div class="css-g5y9jx r-t23y2h r-rs99b7 r-16y2uox r-5oul0u r-1kb76zh r-bgnin r-ytbthy r-3o4zer" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1cm7zt9 r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Last Sync</div><div dir="auto" class="css-146c3p1 r-evnaw r-b88u0q r-19qrga8" style="color:rgba(0,126,119,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">--</div><div dir="auto" class="css-146c3p1 r-1enofrn r-19qrga8" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">waiting</div></div></div><div class="css-g5y9jx r-t23y2h r-rs99b7 r-18u37iz r-15d164r r-bhtmuz r-146eth8" style="background-color:rgba(244,248,251,1.00);border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00)"><button aria-label="Coordination tab" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1awozwy r-1dzdj1l r-rs99b7 r-13awgt0 r-1777fci r-11f147o r-1ubuhtd" style="background-color:rgba(0,126,119,1.00);border-top-color:rgba(0,126,119,1.00);border-right-color:rgba(0,126,119,1.00);border-bottom-color:rgba(0,126,119,1.00);border-left-color:rgba(0,126,119,1.00)" type="button"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1enofrn r-b88u0q" style="color:rgba(255,255,255,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Coordination<!-- --> (0)</div></button><button aria-label="Chat tab" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1awozwy r-42olwf r-1dzdj1l r-rs99b7 r-13awgt0 r-1777fci r-11f147o r-1ubuhtd" type="button"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1enofrn r-b88u0q" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Chat<!-- --> (0)</div></button><button aria-label="Requests tab" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1awozwy r-42olwf r-1dzdj1l r-rs99b7 r-13awgt0 r-1777fci r-11f147o r-1ubuhtd" type="button"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1enofrn r-b88u0q" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Requests<!-- --> (0)</div></button><button aria-label="Jobs &amp; Traces tab" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1awozwy r-42olwf r-1dzdj1l r-rs99b7 r-13awgt0 r-1777fci r-11f147o r-1ubuhtd" type="button"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1enofrn r-b88u0q" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Jobs &amp; Traces<!-- --> (0)</div></button><button aria-label="System tab" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1awozwy r-42olwf r-1dzdj1l r-rs99b7 r-13awgt0 r-1777fci r-11f147o r-1ubuhtd" type="button"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1enofrn r-b88u0q" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">System<!-- --> (0)</div></button><button aria-label="Config tab" role="button" tabindex="0" class="css-g5y9jx r-1loqt21 r-1otgn73 r-1awozwy r-42olwf r-1dzdj1l r-rs99b7 r-13awgt0 r-1777fci r-11f147o r-1ubuhtd" type="button"><div dir="auto" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1enofrn r-b88u0q" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Config</div></button></div><div class="css-g5y9jx r-13awgt0 r-ifefl9" style="opacity:1;transform:translateY(0px)"><div class="css-g5y9jx r-150rngu r-eqz5dr r-16y2uox r-1wbh5a2 r-11yh6sk r-1rnoaur r-agouwx r-13awgt0"><div class="css-g5y9jx r-1t2hasf r-u9wvl5"><div class="css-g5y9jx r-18u37iz r-1w6e6rj r-1mi0q7o"><div class="css-g5y9jx r-t23y2h r-rs99b7 r-16y2uox r-5oul0u r-1kb76zh r-bgnin r-ytbthy r-3o4zer" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1cm7zt9 r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Ready For Review</div><div dir="auto" class="css-146c3p1 r-evnaw r-b88u0q r-19qrga8" style="color:rgba(0,126,119,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0</div><div dir="auto" class="css-146c3p1 r-1enofrn r-19qrga8" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 processed completions</div></div><div class="css-g5y9jx r-t23y2h r-rs99b7 r-16y2uox r-5oul0u r-1kb76zh r-bgnin r-ytbthy r-3o4zer" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1cm7zt9 r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Active Handoffs</div><div dir="auto" class="css-146c3p1 r-evnaw r-b88u0q r-19qrga8" style="color:rgba(0,126,119,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0</div><div dir="auto" class="css-146c3p1 r-1enofrn r-19qrga8" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 running jobs</div></div><div class="css-g5y9jx r-t23y2h r-rs99b7 r-16y2uox r-5oul0u r-1kb76zh r-bgnin r-ytbthy r-3o4zer" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1cm7zt9 r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Awaiting Remote</div><div dir="auto" class="css-146c3p1 r-evnaw r-b88u0q r-19qrga8" style="color:rgba(22,154,88,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0</div><div dir="auto" class="css-146c3p1 r-1enofrn r-19qrga8" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 pending requests</div></div><div class="css-g5y9jx r-t23y2h r-rs99b7 r-16y2uox r-5oul0u r-1kb76zh r-bgnin r-ytbthy r-3o4zer" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(244,248,251,1.00)"><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1cm7zt9 r-tsynxw" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Blocked</div><div dir="auto" class="css-146c3p1 r-evnaw r-b88u0q r-19qrga8" style="color:rgba(22,154,88,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0</div><div dir="auto" class="css-146c3p1 r-1enofrn r-19qrga8" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0 failed jobs</div></div></div><div class="css-g5y9jx r-eqz5dr"><div class="css-g5y9jx r-1867qdf r-rs99b7 r-k3250r r-15d164r r-xyw6el" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(255,255,255,1.00)"><div class="css-g5y9jx r-1awozwy r-18u37iz r-1wtj0ep"><div dir="auto" class="css-146c3p1 r-ubezar r-b88u0q r-5oul0u" style="color:rgba(17,34,48,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Change Coordination Board</div><div dir="auto" class="css-146c3p1 r-1gkfh8e r-1g94qm0" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">0<!-- --> latest requests</div></div><div class="css-g5y9jx r-1habvwh r-1867qdf r-nsbfu8"><div dir="auto" class="css-146c3p1 r-1i10wst r-b88u0q r-15zivkp" style="color:rgba(17,34,48,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Nothing to coordinate yet</div><div dir="auto" class="css-146c3p1 r-n6v787 r-hjklzo" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Send a task from chat and this board will trace the full handoff from request to integration.</div></div></div><div class="css-g5y9jx r-1867qdf r-rs99b7 r-jprt8p r-15d164r r-11wrixw r-xyw6el" style="border-top-color:rgba(207,218,226,1.00);border-right-color:rgba(207,218,226,1.00);border-bottom-color:rgba(207,218,226,1.00);border-left-color:rgba(207,218,226,1.00);background-color:rgba(255,255,255,1.00)"><div dir="auto" class="css-146c3p1 r-ubezar r-b88u0q r-5oul0u" style="color:rgba(17,34,48,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">Review Queue</div><div dir="auto" class="css-146c3p1 r-n6v787 r-hjklzo" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">No processed completions yet.</div><div dir="auto" class="css-146c3p1 r-ubezar r-b88u0q r-5oul0u" style="color:rgba(17,34,48,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif;margin-top:14px">Needs Attention</div><div dir="auto" class="css-146c3p1 r-n6v787 r-hjklzo" style="color:rgba(84,112,134,1.00);font-family:&#x27;Space Grotesk&#x27;, &#x27;Avenir Next&#x27;, &#x27;Trebuchet MS&#x27;, sans-serif">No failed coordination chains.</div></div></div></div></div></div></div></div></div></div></div><!--/$--></div></div></div></div><!--/$--></div></div><script src="/_expo/static/js/web/entry-e8aa7049f746aaa8f1e865615e248f21.js" defer></script>
439
439
  </body></html>
@@ -435,5 +435,5 @@ input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-web
435
435
  @keyframes r-1pzkwqh{0%{transform:translateY(100%);}100%{transform:translateY(0%);}}
436
436
  @keyframes r-imtty0{0%{opacity:0;}100%{opacity:1;}}
437
437
  @keyframes r-q67da2{0%{transform:translateX(-100%);}100%{transform:translateX(400%);}}
438
- @keyframes r-t2lo5v{0%{opacity:1;}100%{opacity:0;}}</style><script type="module">globalThis.__EXPO_ROUTER_HYDRATE__=true;</script><link rel="icon" href="/favicon.ico" /></head><body><div id="root"><div class="css-g5y9jx r-13awgt0"><!--$--><div style="position:absolute;left:0;right:0;top:0;bottom:0;pointer-events:none;visibility:hidden"></div><div class="css-g5y9jx r-13awgt0"><div class="css-g5y9jx r-13awgt0 r-1p0dtai r-1d2f490 r-u8s1d r-zchlnj r-ipm5af" style="background-color:rgba(242,242,242,1.00);display:flex"><div class="css-g5y9jx r-184en5c r-12vffkv"><div class="css-g5y9jx r-12vffkv" style="height:64px"><div class="css-g5y9jx r-1p0dtai r-1d2f490 r-u8s1d r-zchlnj r-ipm5af r-12vffkv"><div class="css-g5y9jx r-qklmqi r-13awgt0 r-105ug2t" style="background-color:rgba(255,255,255,1.00);border-bottom-color:rgba(216,216,216,1.00)"></div></div><div class="css-g5y9jx r-633pao" style="height:0px"></div><div class="css-g5y9jx r-1oszu61 r-13awgt0 r-18u37iz r-12vffkv"><div class="css-g5y9jx r-1awozwy r-18u37iz r-1h0z5md r-12vffkv" style="margin-left:0px"></div><div class="css-g5y9jx r-1777fci r-12vffkv" style="max-width:-32px;margin-right:16px;margin-left:16px"><h1 dir="auto" aria-level="1" role="heading" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1i10wst" style="color:rgba(28,28,30,1.00);font-family:system-ui, &quot;Segoe UI&quot;, Roboto, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;font-weight:500">Modal</h1></div><div class="css-g5y9jx r-1awozwy r-18u37iz r-17s6mgv r-1iusvr4 r-16y2uox r-12vffkv" style="margin-right:0px"></div></div></div></div><div class="css-g5y9jx r-13awgt0"><div class="css-g5y9jx r-13awgt0"><!--$--><div class="css-g5y9jx r-1awozwy r-13awgt0 r-1777fci r-1pcd2l5" style="background-color:rgba(255,255,255,1.00)"><div dir="auto" class="css-146c3p1 r-1ui5ee8 r-vw2c0b r-37tt59" style="color:rgba(17,24,28,1.00)">This is a modal</div><a href="/" dir="auto" role="link" class="css-146c3p1 r-19h5ruw r-1d7mnkm r-1loqt21"><span class="css-1jxf684 r-1v78gzs r-ubezar r-17rnw9f">Go to home screen</span></a></div><!--/$--></div></div></div></div><!--/$--></div></div><script src="/_expo/static/js/web/entry-ff425ab85ad13c1920b8ee00abfae7dd.js" defer></script>
438
+ @keyframes r-t2lo5v{0%{opacity:1;}100%{opacity:0;}}</style><script type="module">globalThis.__EXPO_ROUTER_HYDRATE__=true;</script><link rel="icon" href="/favicon.ico" /></head><body><div id="root"><div class="css-g5y9jx r-13awgt0"><!--$--><div style="position:absolute;left:0;right:0;top:0;bottom:0;pointer-events:none;visibility:hidden"></div><div class="css-g5y9jx r-13awgt0"><div class="css-g5y9jx r-13awgt0 r-1p0dtai r-1d2f490 r-u8s1d r-zchlnj r-ipm5af" style="background-color:rgba(242,242,242,1.00);display:flex"><div class="css-g5y9jx r-184en5c r-12vffkv"><div class="css-g5y9jx r-12vffkv" style="height:64px"><div class="css-g5y9jx r-1p0dtai r-1d2f490 r-u8s1d r-zchlnj r-ipm5af r-12vffkv"><div class="css-g5y9jx r-qklmqi r-13awgt0 r-105ug2t" style="background-color:rgba(255,255,255,1.00);border-bottom-color:rgba(216,216,216,1.00)"></div></div><div class="css-g5y9jx r-633pao" style="height:0px"></div><div class="css-g5y9jx r-1oszu61 r-13awgt0 r-18u37iz r-12vffkv"><div class="css-g5y9jx r-1awozwy r-18u37iz r-1h0z5md r-12vffkv" style="margin-left:0px"></div><div class="css-g5y9jx r-1777fci r-12vffkv" style="max-width:-32px;margin-right:16px;margin-left:16px"><h1 dir="auto" aria-level="1" role="heading" class="css-146c3p1 r-dnmrzs r-1udh08x r-1udbk01 r-3s2u2q r-1iln25a r-1i10wst" style="color:rgba(28,28,30,1.00);font-family:system-ui, &quot;Segoe UI&quot;, Roboto, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;;font-weight:500">Modal</h1></div><div class="css-g5y9jx r-1awozwy r-18u37iz r-17s6mgv r-1iusvr4 r-16y2uox r-12vffkv" style="margin-right:0px"></div></div></div></div><div class="css-g5y9jx r-13awgt0"><div class="css-g5y9jx r-13awgt0"><!--$--><div class="css-g5y9jx r-1awozwy r-13awgt0 r-1777fci r-1pcd2l5" style="background-color:rgba(255,255,255,1.00)"><div dir="auto" class="css-146c3p1 r-1ui5ee8 r-vw2c0b r-37tt59" style="color:rgba(17,24,28,1.00)">This is a modal</div><a href="/" dir="auto" role="link" class="css-146c3p1 r-19h5ruw r-1d7mnkm r-1loqt21"><span class="css-1jxf684 r-1v78gzs r-ubezar r-17rnw9f">Go to home screen</span></a></div><!--/$--></div></div></div></div><!--/$--></div></div><script src="/_expo/static/js/web/entry-e8aa7049f746aaa8f1e865615e248f21.js" defer></script>
439
439
  </body></html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushpalsdev/cli",
3
- "version": "1.1.10",
3
+ "version": "1.1.12",
4
4
  "description": "PushPals terminal CLI for LocalBuddy -> RemoteBuddy orchestration",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -51,7 +51,7 @@ workerpal_heartbeat_ms = 0
51
51
  workerpal_labels = []
52
52
  execution_budget_interactive_ms = 600000
53
53
  execution_budget_normal_ms = 1500000
54
- execution_budget_background_ms = 1800000
54
+ execution_budget_background_ms = 1200000
55
55
  finalization_budget_ms = 120000
56
56
  crash_restart_enabled = true
57
57
  crash_restart_max_restarts = 3
@@ -515,7 +515,8 @@
515
515
  "stream": { "type": "string", "enum": ["stdout", "stderr"] },
516
516
  "seq": { "type": "integer", "minimum": 1 },
517
517
  "line": { "type": "string" },
518
- "ts": { "type": "string" }
518
+ "ts": { "type": "string" },
519
+ "phase": { "type": ["string", "null"] }
519
520
  },
520
521
  "additionalProperties": false
521
522
  }
@@ -1306,7 +1306,7 @@ function loadPushPalsConfig(options = {}) {
1306
1306
  workerpalLabels: firstNonEmpty(process.env.REMOTEBUDDY_WORKERPAL_LABELS) ? firstNonEmpty(process.env.REMOTEBUDDY_WORKERPAL_LABELS).split(",").map((value) => value.trim()).filter(Boolean) : asStringArray(remoteNode.workerpal_labels),
1307
1307
  executionBudgetInteractiveMs: Math.max(60000, asInt(parseIntEnv("REMOTEBUDDY_EXECUTION_BUDGET_INTERACTIVE_MS") ?? remoteNode.execution_budget_interactive_ms, 300000)),
1308
1308
  executionBudgetNormalMs: Math.max(120000, asInt(parseIntEnv("REMOTEBUDDY_EXECUTION_BUDGET_NORMAL_MS") ?? remoteNode.execution_budget_normal_ms, 900000)),
1309
- executionBudgetBackgroundMs: Math.max(180000, asInt(parseIntEnv("REMOTEBUDDY_EXECUTION_BUDGET_BACKGROUND_MS") ?? remoteNode.execution_budget_background_ms, 1800000)),
1309
+ executionBudgetBackgroundMs: Math.max(180000, asInt(parseIntEnv("REMOTEBUDDY_EXECUTION_BUDGET_BACKGROUND_MS") ?? remoteNode.execution_budget_background_ms, 1200000)),
1310
1310
  finalizationBudgetMs: Math.max(30000, asInt(parseIntEnv("REMOTEBUDDY_FINALIZATION_BUDGET_MS") ?? remoteNode.finalization_budget_ms, 120000)),
1311
1311
  crashRestartEnabled: parseBoolEnv("REMOTEBUDDY_CRASH_RESTART_ENABLED") ?? asBoolean(remoteNode.crash_restart_enabled, true),
1312
1312
  crashRestartMaxRestarts: Math.max(0, asInt(parseIntEnv("REMOTEBUDDY_CRASH_RESTART_MAX_RESTARTS") ?? remoteNode.crash_restart_max_restarts, 3)),
@@ -1432,10 +1432,15 @@ def _merge_usage_records(first: Any, second: Any) -> Dict[str, Any]:
1432
1432
  return merged
1433
1433
 
1434
1434
 
1435
+ def _is_publishable_changed_path(path: str) -> bool:
1436
+ normalized = str(path or "").replace("\\", "/").lower()
1437
+ return not re.search(r"(^|/)(outputs|node_modules|\.worktrees|\.codex|dist|build|coverage)(/|$)", normalized)
1438
+
1439
+
1435
1440
  def _codex_changed_paths(repo: str, baseline_snapshot: List[str]) -> Tuple[List[str], List[str], List[str]]:
1436
1441
  changed_paths = summarize_git_changes(repo)
1437
1442
  delta = [p for p in changed_paths if p not in baseline_snapshot]
1438
- effective = delta if delta else changed_paths
1443
+ effective = [p for p in (delta if delta else changed_paths) if _is_publishable_changed_path(p)]
1439
1444
  return changed_paths, delta, effective
1440
1445
 
1441
1446
 
@@ -32,6 +32,7 @@ from openai_codex_executor import (
32
32
  _resolve_reasoning_effort,
33
33
  _build_instruction,
34
34
  _collect_disallowed_shell_wrapper_rejections,
35
+ _codex_changed_paths,
35
36
  _detect_codex_workaround_signal,
36
37
  _extract_usage_counts,
37
38
  _load_prompt_template,
@@ -298,6 +299,8 @@ class OpenAICodexRuntimeConfigTests(unittest.TestCase):
298
299
  task = parse_task_execute_payload(["executor", encoded], logger=Logger("[test]"))
299
300
  guidance = "\n".join(task.supplemental_guidance)
300
301
 
302
+ self.assertIn("Worker speed/convergence contract", guidance)
303
+ self.assertIn("roughly 20 minutes", guidance)
301
304
  self.assertIn("Task planning contract from PushPals", guidance)
302
305
  self.assertIn("Worker phase contract", guidance)
303
306
  self.assertIn("Write globs are relevance hints, not hard limits", guidance)
@@ -305,6 +308,42 @@ class OpenAICodexRuntimeConfigTests(unittest.TestCase):
305
308
  self.assertIn("Home shell startup is assertable", guidance)
306
309
  self.assertIn("bun run web:e2e", guidance)
307
310
 
311
+ def test_parse_payload_prefers_helper_tests_for_visual_derivation_tasks(self) -> None:
312
+ with tempfile.TemporaryDirectory(prefix="pushpals-visual-guidance-") as temp_dir:
313
+ repo = Path(temp_dir) / "repo"
314
+ repo.mkdir(parents=True, exist_ok=True)
315
+ payload = {
316
+ "kind": "task.execute",
317
+ "repo": str(repo),
318
+ "params": {
319
+ "instruction": (
320
+ "Improve battlefield readability by making planet ownership rings, "
321
+ "projectile trails, and danger cues clearer."
322
+ ),
323
+ "schemaVersion": 2,
324
+ "planning": {
325
+ "intent": "code_change",
326
+ "riskLevel": "medium",
327
+ "queuePriority": "normal",
328
+ "queueWaitBudgetMs": 90_000,
329
+ "executionBudgetMs": 1_800_000,
330
+ "finalizationBudgetMs": 120_000,
331
+ "scope": {"readAnywhere": True, "writeAllowed": True},
332
+ "targetPaths": ["app/game.tsx"],
333
+ "acceptanceCriteria": ["Projectile and ownership readability improve"],
334
+ "validationSteps": ["bun test app/__tests__/battlefieldReadability.test.ts"],
335
+ },
336
+ },
337
+ }
338
+ encoded = base64.b64encode(json.dumps(payload).encode("utf-8")).decode("ascii")
339
+
340
+ task = parse_task_execute_payload(["executor", encoded], logger=Logger("[test]"))
341
+ guidance = "\n".join(task.supplemental_guidance)
342
+
343
+ self.assertIn("Visual/rendering task rule", guidance)
344
+ self.assertIn("prefer pure helper/state/style-prop tests", guidance)
345
+ self.assertIn("full React Native/component render regression", guidance)
346
+
308
347
  def test_detects_codex_workaround_signals(self) -> None:
309
348
  signal = _detect_codex_workaround_signal(
310
349
  "Adapting test to avoid external Codex calls because Codex CLI isn't available in this environment.",
@@ -571,6 +610,45 @@ class OpenAICodexRuntimeConfigTests(unittest.TestCase):
571
610
  self.assertIn("src/", str(result.get("stdout") or ""))
572
611
  self.assertNotIn("Recovered after Codex attempts", str(result.get("stdout") or ""))
573
612
 
613
+ def test_codex_changed_paths_filters_dependency_artifacts_from_publishable_delta(self) -> None:
614
+ with tempfile.TemporaryDirectory(prefix="pushpals-codex-artifact-delta-") as temp_dir:
615
+ repo = Path(temp_dir) / "repo"
616
+ repo.mkdir(parents=True, exist_ok=True)
617
+ (repo / "README.md").write_text("# artifact delta test\n", encoding="utf-8")
618
+ subprocess.run(["git", "init"], cwd=repo, check=True, capture_output=True, text=True)
619
+ subprocess.run(
620
+ ["git", "config", "user.name", "PushPals Test"],
621
+ cwd=repo,
622
+ check=True,
623
+ capture_output=True,
624
+ text=True,
625
+ )
626
+ subprocess.run(
627
+ ["git", "config", "user.email", "pushpals-tests@example.com"],
628
+ cwd=repo,
629
+ check=True,
630
+ capture_output=True,
631
+ text=True,
632
+ )
633
+ subprocess.run(["git", "add", "README.md"], cwd=repo, check=True, capture_output=True, text=True)
634
+ subprocess.run(
635
+ ["git", "commit", "-m", "chore: seed artifact test"],
636
+ cwd=repo,
637
+ check=True,
638
+ capture_output=True,
639
+ text=True,
640
+ )
641
+
642
+ (repo / "node_modules").mkdir()
643
+ (repo / "node_modules" / "linked.txt").write_text("artifact\n", encoding="utf-8")
644
+ (repo / "outputs").mkdir()
645
+ (repo / "outputs" / "runtime.log").write_text("artifact\n", encoding="utf-8")
646
+ changed_paths, delta, effective = _codex_changed_paths(str(repo), [])
647
+
648
+ self.assertGreaterEqual(len(changed_paths), 2)
649
+ self.assertGreaterEqual(len(delta), 2)
650
+ self.assertEqual(effective, [])
651
+
574
652
  def test_run_codex_task_escalates_wrapper_recovery_and_recovers(self) -> None:
575
653
  with tempfile.TemporaryDirectory(prefix="pushpals-codex-wrapper-recovery-") as temp_dir:
576
654
  repo = Path(temp_dir) / "repo"
@@ -63,6 +63,5 @@ export const OPENAI_CODEX_BACKEND: DockerBackendSpec = {
63
63
  scriptPath: resolve(import.meta.dir, "openai_codex", "openai_codex_executor.py"),
64
64
  pythonConfigKey: "openaiCodexPython",
65
65
  timeoutConfigKey: "openaiCodexTimeoutMs",
66
- capTimeoutToExecutionBudget: false,
67
66
  }),
68
67
  };
@@ -738,6 +738,72 @@ def _append_list_guidance(lines: List[str], label: str, values: List[str]) -> No
738
738
  lines.append(f" - {value}")
739
739
 
740
740
 
741
+ def _joined_task_text(params: Dict[str, Any]) -> str:
742
+ pieces: List[str] = []
743
+
744
+ def collect(value: Any) -> None:
745
+ if isinstance(value, str):
746
+ pieces.append(value)
747
+ elif isinstance(value, list):
748
+ for item in value:
749
+ collect(item)
750
+ elif isinstance(value, dict):
751
+ for item in value.values():
752
+ collect(item)
753
+
754
+ collect(params.get("instruction"))
755
+ collect(params.get("plannerWorkerInstruction"))
756
+ collect(params.get("qualityRevisionHint"))
757
+ planning = params.get("planning")
758
+ if isinstance(planning, dict):
759
+ collect(planning.get("targetPaths"))
760
+ collect(planning.get("acceptanceCriteria"))
761
+ collect(planning.get("validationSteps"))
762
+ collect(planning.get("requiredValidationSteps"))
763
+ collect(planning.get("discovery"))
764
+ return "\n".join(pieces).lower()
765
+
766
+
767
+ def _looks_like_visual_derivation_task(params: Dict[str, Any]) -> bool:
768
+ text = _joined_task_text(params)
769
+ visual_markers = (
770
+ "visual",
771
+ "readability",
772
+ "battlefield",
773
+ "render",
774
+ "rendering",
775
+ "projectile",
776
+ "planet",
777
+ "ship",
778
+ "ring",
779
+ "danger",
780
+ "threat",
781
+ "ownership",
782
+ "dense action",
783
+ "ui surface",
784
+ "style",
785
+ "styles",
786
+ )
787
+ return any(marker in text for marker in visual_markers)
788
+
789
+
790
+ def _build_efficiency_guidance(params: Dict[str, Any]) -> str:
791
+ lines: List[str] = [
792
+ "Worker speed/convergence contract from PushPals:",
793
+ "- Target useful completion in roughly 20 minutes for small or medium repo tasks; optimize for the smallest coherent patch over exhaustive exploration.",
794
+ "- Phase soft budgets: discovery <= 5m, editing <= 10m, focused validation <= 5m, final diff review <= 2m. If a phase runs long, narrow scope rather than expanding the harness.",
795
+ "- Test-harness soft budget: if setting up a focused test requires multiple new shared mocks, broad React Native shims, or repeated import fixes, stop building that harness and switch to smaller pure helper/state coverage.",
796
+ ]
797
+ if _looks_like_visual_derivation_task(params):
798
+ lines.extend(
799
+ [
800
+ "- Visual/rendering task rule: prefer pure helper/state/style-prop tests for derived visual cues. Use a full React Native/component render regression only if the repo already has a stable harness for that exact surface.",
801
+ "- Full-surface React Native tests are a last resort for visual derivation work; do not spend the job constructing broad mocks just to assert pixels or nested component trees.",
802
+ ]
803
+ )
804
+ return "\n".join(lines)
805
+
806
+
741
807
  def _build_planning_guidance(params: Dict[str, Any]) -> str:
742
808
  planning = params.get("planning")
743
809
  if not isinstance(planning, dict):
@@ -768,6 +834,9 @@ def _build_planning_guidance(params: Dict[str, Any]) -> str:
768
834
  " - full validation: let PushPals ValidationGate own long required/browser checks unless one local confirmation is explicitly useful."
769
835
  )
770
836
  lines.append(" - final diff review: remove unrelated churn before returning.")
837
+ lines.append(
838
+ "- Phase soft budget: aim for discovery <= 5m, editing <= 10m, focused validation <= 5m, final diff review <= 2m; if test harness setup starts consuming the budget, reduce to simpler helper/state coverage."
839
+ )
771
840
 
772
841
  scope = planning.get("scope")
773
842
  if isinstance(scope, dict):
@@ -869,6 +938,7 @@ def parse_task_execute_payload(
869
938
  quality_revision_hint = str(params.get("qualityRevisionHint") or "").strip()
870
939
 
871
940
  supplemental_guidance: List[str] = []
941
+ supplemental_guidance.append(_build_efficiency_guidance(params))
872
942
  planning_guidance = _build_planning_guidance(params)
873
943
  if planning_guidance:
874
944
  supplemental_guidance.append(planning_guidance)
@@ -136,6 +136,29 @@ export function resolveGenericPythonExecutorTimeoutMs(params: {
136
136
  return configuredTimeoutMs;
137
137
  }
138
138
 
139
+ function toSnakeConfigKey(key: string): string {
140
+ return key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
141
+ }
142
+
143
+ function formatGenericPythonExecutorTimeoutDetail(
144
+ config: GenericPythonExecutorConfig,
145
+ configuredTimeoutMs: number,
146
+ executionBudgetMs: number | null,
147
+ timeoutMs: number,
148
+ ): string {
149
+ const configPath = `workerpals.${toSnakeConfigKey(config.timeoutConfigKey)}`;
150
+ if (executionBudgetMs == null) {
151
+ return `${configPath}=${configuredTimeoutMs}ms`;
152
+ }
153
+ if (config.capTimeoutToExecutionBudget === false) {
154
+ return `${configPath}=${configuredTimeoutMs}ms; planning executionBudgetMs=${executionBudgetMs}ms ignored by backend opt-out`;
155
+ }
156
+ if (timeoutMs < configuredTimeoutMs) {
157
+ return `${configPath}=${configuredTimeoutMs}ms capped by planning executionBudgetMs=${executionBudgetMs}ms`;
158
+ }
159
+ return `${configPath}=${configuredTimeoutMs}ms within planning executionBudgetMs=${executionBudgetMs}ms`;
160
+ }
161
+
139
162
  export function createGenericPythonExecutor(
140
163
  config: GenericPythonExecutorConfig,
141
164
  ): BackendTaskExecutor {
@@ -172,6 +195,12 @@ export function createGenericPythonExecutor(
172
195
  executionBudgetMs,
173
196
  capTimeoutToExecutionBudget: config.capTimeoutToExecutionBudget,
174
197
  });
198
+ const timeoutDetail = formatGenericPythonExecutorTimeoutDetail(
199
+ config,
200
+ configuredTimeoutMs,
201
+ executionBudgetMs,
202
+ timeoutMs,
203
+ );
175
204
  const payloadBase64 = Buffer.from(
176
205
  JSON.stringify({
177
206
  kind,
@@ -184,7 +213,7 @@ export function createGenericPythonExecutor(
184
213
 
185
214
  onLog?.(
186
215
  "stdout",
187
- `[${backendLabel}Executor] Spawning ${backendName} executor (timeout=${timeoutMs}ms)`,
216
+ `[${backendLabel}Executor] Spawning ${backendName} executor (timeout=${timeoutMs}ms; ${timeoutDetail})`,
188
217
  );
189
218
 
190
219
  try {
@@ -207,6 +236,7 @@ export function createGenericPythonExecutor(
207
236
  });
208
237
 
209
238
  let timedOut = false;
239
+ let hardKillTimer: ReturnType<typeof setTimeout> | null = null;
210
240
  const timeoutTimer = setTimeout(() => {
211
241
  timedOut = true;
212
242
  onLog?.(
@@ -214,6 +244,13 @@ export function createGenericPythonExecutor(
214
244
  `[${backendLabel}Executor] Timeout reached after ${timeoutMs}ms; terminating process.`,
215
245
  );
216
246
  proc.kill();
247
+ hardKillTimer = setTimeout(() => {
248
+ onLog?.(
249
+ "stdout",
250
+ `[${backendLabel}Executor] Process did not exit after graceful timeout termination; forcing kill.`,
251
+ );
252
+ proc.kill("SIGKILL");
253
+ }, 5_000);
217
254
  }, timeoutMs);
218
255
 
219
256
  const progressIntervalMs = 15_000;
@@ -246,6 +283,7 @@ export function createGenericPythonExecutor(
246
283
  ]);
247
284
 
248
285
  clearTimeout(timeoutTimer);
286
+ if (hardKillTimer) clearTimeout(hardKillTimer);
249
287
  clearInterval(progressTimer);
250
288
 
251
289
  const stdout = rawStdout ?? "";
@@ -43,10 +43,10 @@ const WORKERPAL_SANDBOX_COMPONENT_LABEL = "pushpals.component=workerpals-sandbox
43
43
  const DOCKER_IMAGE_INSPECT_TIMEOUT_MS = 15_000;
44
44
  const DOCKER_IMAGE_BUILD_TIMEOUT_MS = 10 * 60_000;
45
45
  const DOCKER_IMAGE_PULL_TIMEOUT_MS = 10 * 60_000;
46
- const BROWSER_VALIDATION_JOB_REPAIR_ATTEMPTS = 8;
47
- const BROWSER_VALIDATION_JOB_OVERHEAD_MS = 15 * 60_000;
48
- const BROWSER_VALIDATION_JOB_MIN_TIMEOUT_MS = 4 * 60 * 60_000;
49
- const BROWSER_VALIDATION_JOB_MAX_TIMEOUT_MS = 8 * 60 * 60_000;
46
+ const BROWSER_VALIDATION_JOB_REPAIR_ATTEMPTS = 3;
47
+ const BROWSER_VALIDATION_JOB_OVERHEAD_MS = 5 * 60_000;
48
+ const BROWSER_VALIDATION_JOB_MIN_TIMEOUT_MS = 20 * 60_000;
49
+ const BROWSER_VALIDATION_JOB_MAX_TIMEOUT_MS = 45 * 60_000;
50
50
 
51
51
  function parseClampedInt(value: unknown, defaultValue: number, min: number, max: number): number {
52
52
  const parsed =
@@ -303,7 +303,7 @@ export function resolveDockerJobTimeoutMs(
303
303
  if (!hasBrowserValidationCommand(job)) return baseTimeoutMs;
304
304
 
305
305
  const planning = maybeRecord(job.params.planning);
306
- const executionBudgetMs = readPositiveNumber(planning?.executionBudgetMs) ?? 1_800_000;
306
+ const executionBudgetMs = readPositiveNumber(planning?.executionBudgetMs) ?? 1_200_000;
307
307
  const finalizationBudgetMs = readPositiveNumber(planning?.finalizationBudgetMs) ?? 120_000;
308
308
  const attempts = BROWSER_VALIDATION_JOB_REPAIR_ATTEMPTS + 1; // initial attempt plus repairs
309
309
  const estimatedTimeoutMs =
@@ -312,7 +312,7 @@ export function resolveDockerJobTimeoutMs(
312
312
  BROWSER_VALIDATION_JOB_MAX_TIMEOUT_MS,
313
313
  Math.max(BROWSER_VALIDATION_JOB_MIN_TIMEOUT_MS, estimatedTimeoutMs),
314
314
  );
315
- return Math.max(baseTimeoutMs, boundedTimeoutMs);
315
+ return Math.max(Math.min(baseTimeoutMs, boundedTimeoutMs), BROWSER_VALIDATION_JOB_MIN_TIMEOUT_MS);
316
316
  }
317
317
 
318
318
  export class DockerExecutor {
@@ -1221,7 +1221,8 @@ export class DockerExecutor {
1221
1221
  });
1222
1222
  const timeoutMs = resolveDockerJobTimeoutMs(this.options.timeoutMs, job);
1223
1223
  if (timeoutMs !== this.options.timeoutMs) {
1224
- const note = `[DockerExecutor] Extended job timeout for browser validation convergence: ${timeoutMs}ms (configured ${this.options.timeoutMs}ms).`;
1224
+ const verb = timeoutMs > this.options.timeoutMs ? "Extended" : "Capped";
1225
+ const note = `[DockerExecutor] ${verb} job timeout for browser validation convergence: ${timeoutMs}ms (configured ${this.options.timeoutMs}ms).`;
1225
1226
  console.log(note);
1226
1227
  onLog?.("stdout", note);
1227
1228
  }
@@ -1246,7 +1247,7 @@ export class DockerExecutor {
1246
1247
  const timer = setTimeout(() => {
1247
1248
  timedOutByDocker = true;
1248
1249
  const elapsedMs = Math.max(1, Date.now() - startedAtMs);
1249
- const timeoutMsg = `[DockerExecutor] Job timeout in warm container after ${elapsedMs}ms (limit ${this.options.timeoutMs}ms): ${this.warmContainerName}`;
1250
+ const timeoutMsg = `[DockerExecutor] Job timeout in warm container after ${elapsedMs}ms (limit ${timeoutMs}ms): ${this.warmContainerName}`;
1250
1251
  console.log(timeoutMsg);
1251
1252
  onLog?.("stderr", timeoutMsg);
1252
1253
  try {
@@ -176,7 +176,7 @@ export interface QualityGatePolicy {
176
176
  criticMinScore: number;
177
177
  }
178
178
 
179
- const BROWSER_VALIDATION_MAX_AUTO_REVISIONS = 8;
179
+ const BROWSER_VALIDATION_MAX_AUTO_REVISIONS = 3;
180
180
 
181
181
  export function qualityRevisionLoopUpperBound(policy: {
182
182
  maxAutoRevisions: number;
@@ -378,6 +378,97 @@ function buildDiffBudgetWarning(
378
378
  .join(", ")}${meaningfulChangedPaths.length > 12 ? ", ..." : ""}`;
379
379
  }
380
380
 
381
+ function isNonPublishableArtifactPath(path: string): boolean {
382
+ return /(^|\/)(outputs|node_modules|\.worktrees|\.codex|dist|build|coverage)(\/|$)/i.test(
383
+ path.replace(/\\/g, "/"),
384
+ );
385
+ }
386
+
387
+ export function publishableChangedPaths(changedPaths: string[]): string[] {
388
+ return changedPaths.filter((path) => !isNonPublishableArtifactPath(path));
389
+ }
390
+
391
+ function collectPlanningText(planning: TaskExecutePlanning): string {
392
+ return [
393
+ planning.intent,
394
+ planning.riskLevel,
395
+ ...(planning.targetPaths ?? []),
396
+ ...(planning.acceptanceCriteria ?? []),
397
+ ...(planning.validationSteps ?? []),
398
+ ...(planning.requiredValidationSteps ?? []),
399
+ ...(planning.discovery?.keywords ?? []),
400
+ ...(planning.discovery?.likelyDirs ?? []),
401
+ ...(planning.discovery?.ripgrepQueries ?? []),
402
+ ]
403
+ .map((part) => String(part ?? ""))
404
+ .join("\n")
405
+ .toLowerCase();
406
+ }
407
+
408
+ function planningLooksLikeVisualDerivationTask(planning: TaskExecutePlanning): boolean {
409
+ const text = collectPlanningText(planning);
410
+ return /\b(visual|readability|battlefield|render(?:ing)?|projectile|planet|ship|ring|danger|threat|ownership|dense action|style|ui surface)\b/i.test(
411
+ text,
412
+ );
413
+ }
414
+
415
+ function buildTestHarnessConvergenceWarning(
416
+ planning: TaskExecutePlanning,
417
+ issues: string[],
418
+ validationRuns: ValidationExecutionResult[],
419
+ ): string | null {
420
+ const combined = [
421
+ ...issues,
422
+ ...validationRuns.flatMap((run) => [run.command, run.stdout, run.stderr]),
423
+ ]
424
+ .map((part) => String(part ?? ""))
425
+ .join("\n");
426
+ const hasMockImportFailure =
427
+ /\bCannot find module\b|\bdoes not provide an export\b|\bno exported member\b|\bimport error\b|\bundefined is not a function\b/i.test(
428
+ combined,
429
+ ) &&
430
+ /\b(react[- ]native|reactNativeMock|Animated\.View|expo-secure-store|SettingsContext|skin validator|mock|test helper|__mocks__)\b/i.test(
431
+ combined,
432
+ );
433
+ if (!hasMockImportFailure) return null;
434
+ const visualPrefix = planningLooksLikeVisualDerivationTask(planning)
435
+ ? " For this visual/rendering task, prefer pure helper/state/style-prop tests over a full React Native surface render."
436
+ : "";
437
+ return (
438
+ "Test harness convergence warning: validation is failing in mock/import setup rather than product behavior." +
439
+ visualPrefix +
440
+ " Do not keep expanding broad shared mocks to rescue an over-scoped component render test. If the repo does not already have stable React Native render-test infrastructure for this surface, replace the full-surface regression with smaller deterministic helper/state coverage and one focused assertion on the behavior-owning API."
441
+ );
442
+ }
443
+
444
+ function buildBroadSharedMockWarning(
445
+ planning: TaskExecutePlanning,
446
+ changedPaths: string[],
447
+ ): string | null {
448
+ const meaningfulChangedPaths = changedPaths.filter(
449
+ (path) => !/(^|\/)(outputs|node_modules|\.worktrees|dist|build|coverage)(\/|$)/i.test(path),
450
+ );
451
+ const broadMockPaths = meaningfulChangedPaths.filter((path) =>
452
+ /(^|\/)(__mocks__|tests\/.*mock|test.*mock|reactNativeMock|setupTests?|jest\.|vitest\.|mock)(\.|\/|$)/i.test(
453
+ path,
454
+ ),
455
+ );
456
+ if (broadMockPaths.length === 0) return null;
457
+ const smallTask =
458
+ planning.riskLevel !== "high" &&
459
+ ((planning.targetPaths?.length ?? 0) <= 2 || planning.acceptanceCriteria.length <= 3);
460
+ if (!smallTask && !planningLooksLikeVisualDerivationTask(planning)) return null;
461
+ const explicitlyRequested = /mock|test harness|react native test|component render/i.test(
462
+ collectPlanningText(planning),
463
+ );
464
+ if (explicitlyRequested) return null;
465
+ return `Broad mock warning: this focused task now changes shared mock/test-harness file(s): ${broadMockPaths
466
+ .slice(0, 6)
467
+ .join(", ")}${
468
+ broadMockPaths.length > 6 ? ", ..." : ""
469
+ }. Before continuing, prefer behavior-owned helper/state tests or existing stable render-test infrastructure; do not add broad React Native mocks for a small visual/control change unless the task explicitly requires harness repair.`;
470
+ }
471
+
381
472
  const TEST_ASSERTION_BALANCE_ISSUE =
382
473
  "Changed test files do not show both positive and negative assertion coverage (expected both).";
383
474
 
@@ -3527,6 +3618,22 @@ export function buildQualityRevisionHint(
3527
3618
  );
3528
3619
  const diffBudgetWarning = buildDiffBudgetWarning(planning, changedPaths, focusedBrowserRepair);
3529
3620
  if (diffBudgetWarning) lines.push(diffBudgetWarning);
3621
+ const broadSharedMockWarning = buildBroadSharedMockWarning(planning, changedPaths);
3622
+ if (broadSharedMockWarning) lines.push(broadSharedMockWarning);
3623
+ const testHarnessConvergenceWarning = buildTestHarnessConvergenceWarning(
3624
+ planning,
3625
+ issues,
3626
+ validationRuns,
3627
+ );
3628
+ if (testHarnessConvergenceWarning) lines.push(testHarnessConvergenceWarning);
3629
+ if (planningLooksLikeVisualDerivationTask(planning)) {
3630
+ lines.push(
3631
+ "Visual derivation testing rule: prefer pure helper/state/style-prop tests for planet/projectile/ownership/readability cues. Only add a full React Native render regression when this repo already has a stable harness for that exact surface; otherwise keep render-visible behavior covered through the derived inputs that drive it.",
3632
+ );
3633
+ }
3634
+ lines.push(
3635
+ "Phase soft-budget reminder: if discovery, test-harness setup, or validation repair is running long, reduce the approach before spending more time. Small/medium tasks should converge toward a useful patch within roughly 20 minutes.",
3636
+ );
3530
3637
  const validationAlreadyPassed =
3531
3638
  validationRuns.length > 0 && validationRuns.every((run) => run.ok);
3532
3639
  if (validationAlreadyPassed && !focusedBrowserRepair) {
@@ -6645,6 +6752,53 @@ export async function executeJob(
6645
6752
  };
6646
6753
  }
6647
6754
 
6755
+ const preQualityStatus = await git(repo, ["status", "--porcelain"]);
6756
+ const preQualityChangedPaths = preQualityStatus.ok
6757
+ ? parseChangedPathsFromStatus(preQualityStatus.stdout)
6758
+ : [];
6759
+ const preQualityPublishablePaths = publishableChangedPaths(preQualityChangedPaths);
6760
+ const executorText = `${result.summary ?? ""}\n${result.stdout ?? ""}\n${result.stderr ?? ""}`;
6761
+ const shellWrapperReturn =
6762
+ /shell-wrapper command rejections|command-router shell-wrapper|command policy rejection/i.test(
6763
+ executorText,
6764
+ );
6765
+ if (preQualityChangedPaths.length > 0 && preQualityPublishablePaths.length === 0) {
6766
+ const detail = `Executor changed only non-publishable dependency/runtime artifact path(s): ${preQualityChangedPaths
6767
+ .slice(0, 12)
6768
+ .join(", ")}${preQualityChangedPaths.length > 12 ? ", ..." : ""}.`;
6769
+ onLog?.(
6770
+ "stderr",
6771
+ `[QualityGate] ${detail} Skipping ValidationGate/CriticGate because there is no PR-worthy patch to validate.`,
6772
+ );
6773
+ return {
6774
+ ok: false,
6775
+ summary: "Executor produced no publishable code changes",
6776
+ stdout: result.stdout,
6777
+ stderr: [result.stderr ?? "", detail].filter(Boolean).join("\n"),
6778
+ exitCode: 4,
6779
+ };
6780
+ }
6781
+ if (
6782
+ preQualityPublishablePaths.length === 0 &&
6783
+ (qualityGatePolicy.mode === "review_fix" || shellWrapperReturn)
6784
+ ) {
6785
+ const reason =
6786
+ qualityGatePolicy.mode === "review_fix"
6787
+ ? "Review-fix executor returned without publishable code changes."
6788
+ : "Codex hit shell-wrapper command rejections without leaving a publishable patch.";
6789
+ onLog?.(
6790
+ "stderr",
6791
+ `[QualityGate] ${reason} Skipping ValidationGate/CriticGate and failing fast.`,
6792
+ );
6793
+ return {
6794
+ ok: false,
6795
+ summary: reason,
6796
+ stdout: result.stdout,
6797
+ stderr: [result.stderr ?? "", reason].filter(Boolean).join("\n"),
6798
+ exitCode: 4,
6799
+ };
6800
+ }
6801
+
6648
6802
  const quality = await runDeterministicQualityGate(
6649
6803
  repo,
6650
6804
  attemptParams,
@@ -342,6 +342,70 @@ function isNoisyProgressLine(line: string): boolean {
342
342
  return /^(📦 Installing \[\d+\/\d+\]|🔍 Resolving\.\.\.|🔒 Saving lockfile\.\.\.)$/.test(line);
343
343
  }
344
344
 
345
+ type WorkerJobPhase =
346
+ | "discovering"
347
+ | "editing"
348
+ | "test harness repair"
349
+ | "focused validation"
350
+ | "full validation"
351
+ | "final diff review"
352
+ | "publishing"
353
+ | "quality revision";
354
+
355
+ function inferWorkerJobPhaseFromLogLine(line: string): WorkerJobPhase | null {
356
+ const text = String(line ?? "").trim();
357
+ if (!text) return null;
358
+ if (/Quality gate requested revision|Quality revision required|revision guidance/i.test(text)) {
359
+ return "quality revision";
360
+ }
361
+ if (
362
+ /test harness|React Native package|reactNativeMock|mock helper|mock was missing|expo-secure-store|import error|Cannot find module|does not provide an export|no exported member|Animated\.View|SettingsContext|skin validator/i.test(
363
+ text,
364
+ )
365
+ ) {
366
+ return "test harness repair";
367
+ }
368
+ if (
369
+ /focused validation|focused checks|targeted test|focused test|new regression|focused regression|fast checks|rerunning .*regression|node --check/i.test(
370
+ text,
371
+ )
372
+ ) {
373
+ return "focused validation";
374
+ }
375
+ if (
376
+ /ValidationGate|required validation|full .*test suite|whole Bun test|repo-level|bun test\b|bunx? tsc|typecheck|type check|bun run lint|web:e2e|browser smoke/i.test(
377
+ text,
378
+ )
379
+ ) {
380
+ return "full validation";
381
+ }
382
+ if (/creating commit|Publish blocked|publish-blocked|completion ref|enqueueCompletion/i.test(text)) {
383
+ return "publishing";
384
+ }
385
+ if (
386
+ /final diff|diff review|git diff|git status|whitespace|line-ending|line ending|pruning|remove unrelated|remaining diff|changed files/i.test(
387
+ text,
388
+ )
389
+ ) {
390
+ return "final diff review";
391
+ }
392
+ if (
393
+ /editing|patch|implemented|adding|fixing|updating|wiring|in place|changes are in place|making .*change|tightening|restore|normalizing/i.test(
394
+ text,
395
+ )
396
+ ) {
397
+ return "editing";
398
+ }
399
+ if (
400
+ /read|inspect|checking|locating|opening|artifact|screenshot|README|context|discover|search|rg |current checkout|worktree/i.test(
401
+ text,
402
+ )
403
+ ) {
404
+ return "discovering";
405
+ }
406
+ return null;
407
+ }
408
+
345
409
  export function shouldEmitDirectSessionJobEvent(options: {
346
410
  ok: boolean;
347
411
  statusPersistedToServer: boolean;
@@ -1352,6 +1416,7 @@ async function workerLoop(
1352
1416
  let lastCleanLog = "";
1353
1417
  let lastCleanLogAt = 0;
1354
1418
  let lastForwardedJobLogAt = Date.now();
1419
+ let currentJobPhase: WorkerJobPhase | null = null;
1355
1420
 
1356
1421
  const emitJobLog = job.sessionId
1357
1422
  ? (stream: "stdout" | "stderr", line: string): boolean => {
@@ -1367,6 +1432,7 @@ async function workerLoop(
1367
1432
  lastCleanLog = cleaned;
1368
1433
  lastCleanLogAt = now;
1369
1434
  lastForwardedJobLogAt = now;
1435
+ currentJobPhase = inferWorkerJobPhaseFromLogLine(cleaned) ?? currentJobPhase;
1370
1436
  const logTs = new Date(now).toISOString();
1371
1437
 
1372
1438
  const seq = stream === "stdout" ? ++stdoutSeq : ++stderrSeq;
@@ -1374,7 +1440,14 @@ async function workerLoop(
1374
1440
  job.sessionId,
1375
1441
  {
1376
1442
  type: "job_log",
1377
- payload: { jobId: job.id, stream, seq, line: cleaned, ts: logTs },
1443
+ payload: {
1444
+ jobId: job.id,
1445
+ stream,
1446
+ seq,
1447
+ line: cleaned,
1448
+ ts: logTs,
1449
+ phase: currentJobPhase,
1450
+ },
1378
1451
  from: `worker:${opts.workerId}`,
1379
1452
  },
1380
1453
  { droppable: true },
@@ -1409,9 +1482,9 @@ async function workerLoop(
1409
1482
  "stdout",
1410
1483
  `[WorkerPals] Job ${job.id} still running after ${formatDurationMs(
1411
1484
  now - jobClaimedAtMs,
1412
- )} (kind=${job.kind}, worker=${opts.workerId}, quiet_for=${formatDurationMs(
1413
- quietForMs,
1414
- )}).`,
1485
+ )} (kind=${job.kind}, worker=${opts.workerId}, phase=${
1486
+ currentJobPhase ?? "unknown"
1487
+ }, quiet_for=${formatDurationMs(quietForMs)}).`,
1415
1488
  );
1416
1489
  }, jobProgressLogEveryMs)
1417
1490
  : null;
@@ -51,7 +51,7 @@ workerpal_heartbeat_ms = 0
51
51
  workerpal_labels = []
52
52
  execution_budget_interactive_ms = 600000
53
53
  execution_budget_normal_ms = 1500000
54
- execution_budget_background_ms = 1800000
54
+ execution_budget_background_ms = 1200000
55
55
  finalization_budget_ms = 120000
56
56
  crash_restart_enabled = true
57
57
  crash_restart_max_restarts = 3
@@ -515,7 +515,8 @@
515
515
  "stream": { "type": "string", "enum": ["stdout", "stderr"] },
516
516
  "seq": { "type": "integer", "minimum": 1 },
517
517
  "line": { "type": "string" },
518
- "ts": { "type": "string" }
518
+ "ts": { "type": "string" },
519
+ "phase": { "type": ["string", "null"] }
519
520
  },
520
521
  "additionalProperties": false
521
522
  }
@@ -125,6 +125,7 @@ export interface EventTypePayloadMap {
125
125
  seq: number;
126
126
  line: string;
127
127
  ts?: string;
128
+ phase?: string | null;
128
129
  };
129
130
 
130
131
  /** System heartbeat / status beacon */
@@ -1619,7 +1619,7 @@ export function loadPushPalsConfig(options: LoadOptions = {}): PushPalsConfig {
1619
1619
  asInt(
1620
1620
  parseIntEnv("REMOTEBUDDY_EXECUTION_BUDGET_BACKGROUND_MS") ??
1621
1621
  remoteNode.execution_budget_background_ms,
1622
- 1_800_000,
1622
+ 1_200_000,
1623
1623
  ),
1624
1624
  ),
1625
1625
  finalizationBudgetMs: Math.max(
@@ -515,7 +515,8 @@
515
515
  "stream": { "type": "string", "enum": ["stdout", "stderr"] },
516
516
  "seq": { "type": "integer", "minimum": 1 },
517
517
  "line": { "type": "string" },
518
- "ts": { "type": "string" }
518
+ "ts": { "type": "string" },
519
+ "phase": { "type": ["string", "null"] }
519
520
  },
520
521
  "additionalProperties": false
521
522
  }