newmark-agent 0.5.3 → 0.5.7

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.
@@ -220,6 +220,10 @@
220
220
  <symbol id="minus" viewBox="0 0 24 24">
221
221
  <path d="M5 12h14" />
222
222
  </symbol>
223
+ <symbol id="mouse" viewBox="0 0 24 24">
224
+ <rect x="5" y="2" width="14" height="20" rx="7" />
225
+ <path d="M12 6v4" />
226
+ </symbol>
223
227
  <symbol id="move" viewBox="0 0 24 24">
224
228
  <path d="M12 2v20" />
225
229
  <path d="m15 19-3 3-3-3" />
@@ -328674,7 +328674,7 @@ function providerStreamTimeoutError(timeoutMs) {
328674
328674
  error.message = `Stream read timeout after ${timeoutMs}ms`;
328675
328675
  return error;
328676
328676
  }
328677
- async function readProviderStreamChunk(reader, signal, timeoutMs = 3e4) {
328677
+ async function readProviderStreamChunk(reader, signal, timeoutMs = 0) {
328678
328678
  if (signal.aborted) throw providerAbortError(signal);
328679
328679
  let timer;
328680
328680
  let onAbort;
@@ -328682,9 +328682,9 @@ async function readProviderStreamChunk(reader, signal, timeoutMs = 3e4) {
328682
328682
  onAbort = () => reject(providerAbortError(signal));
328683
328683
  signal.addEventListener("abort", onAbort, { once: true });
328684
328684
  });
328685
- const timeoutPromise = new Promise((_3, reject) => {
328685
+ const timeoutPromise = timeoutMs > 0 ? new Promise((_3, reject) => {
328686
328686
  timer = setTimeout(() => reject(providerStreamTimeoutError(timeoutMs)), timeoutMs);
328687
- });
328687
+ }) : new Promise(() => void 0);
328688
328688
  try {
328689
328689
  return await Promise.race([reader.read(), abortPromise, timeoutPromise]);
328690
328690
  } catch (error) {
@@ -336937,6 +336937,10 @@ var ToolExecutor = class {
336937
336937
  async webSearch(query) {
336938
336938
  return this.wsearch(query);
336939
336939
  }
336940
+ /** OCR entry point for the runtime's final visual fallback. */
336941
+ async finalVisualFallbackOcr(dataUrl, signal) {
336942
+ return await this.localOcr.recognizeDataUrl(dataUrl, signal, "sparse-ui");
336943
+ }
336940
336944
  setHostProfile(profile) {
336941
336945
  this.hostProfile = { ...profile };
336942
336946
  }
@@ -340850,9 +340854,20 @@ async function runAgentKernel(agent) {
340850
340854
  try {
340851
340855
  const linkedPlanRevisionBeforeRun = agent.getLinkedPlan().revision;
340852
340856
  const modelBeforeKernelRun = agent.model;
340853
- let lastTurn = await runWithCompressionResume([], false);
340857
+ const preflightVisualFallback = !agent.activeModelConfig()?.vision ? await agent.finalVisualFallback("vision input not supported by the selected model", processSignal) : null;
340858
+ let lastTurn = preflightVisualFallback ? { text: preflightVisualFallback, stopReason: "stop", errorMessage: "" } : await runWithCompressionResume([], false);
340859
+ if (preflightVisualFallback) {
340860
+ tokens.push({ type: "text", text: preflightVisualFallback });
340861
+ agent.recordWorkStatus("Final visual fallback used: local mini OCR plus conservative text correction.");
340862
+ }
340854
340863
  if (modelBeforeKernelRun && modelBeforeKernelRun !== agent.model && !tokens.some((t3) => t3.text?.includes("[Model fallback]"))) {
340855
- tokens.unshift({ type: "text", text: `[Model fallback] ${modelBeforeKernelRun} unavailable; switched to ${agent.model}.` });
340864
+ const notice = `[Model fallback] ${modelBeforeKernelRun} unavailable; switched to ${agent.model}.`;
340865
+ tokens.unshift({ type: "text", text: notice });
340866
+ agent.emitWorkEvent({
340867
+ type: "status",
340868
+ content: notice,
340869
+ fallback: { from: modelBeforeKernelRun, to: agent.model, providerId: agent.activeDeployment()?.providerId }
340870
+ });
340856
340871
  }
340857
340872
  let emptyResponseRetries = 0;
340858
340873
  while (providerTurnIsEmpty(lastTurn) && emptyResponseRetries < 2) {
@@ -340873,6 +340888,11 @@ async function runAgentKernel(agent) {
340873
340888
  const notice = routeTransitionNotice(agent, previous);
340874
340889
  tokens.push({ type: "text", text: notice });
340875
340890
  agent.recordWorkStatus(notice);
340891
+ agent.emitWorkEvent({
340892
+ type: "status",
340893
+ content: notice,
340894
+ fallback: { from: previous, to: agent.model, providerId: agent.activeDeployment()?.providerId }
340895
+ });
340876
340896
  kernel2.state.model = toKernelModel(agent);
340877
340897
  const fallbackToolSurface = refreshToolSurface(true);
340878
340898
  kernel2.state.systemPrompt = [agent.buildSystemPrompt(), fallbackToolSurface.systemPromptNotice].filter(Boolean).join("\n\n");
@@ -340880,6 +340900,14 @@ async function runAgentKernel(agent) {
340880
340900
  await agent.waitForPlannedRouteRetry();
340881
340901
  lastTurn = await runWithCompressionResume([], false);
340882
340902
  }
340903
+ if (kernelTurnFailed(agent, lastTurn)) {
340904
+ const visualFallback = await agent.finalVisualFallback(lastTurn.errorMessage || lastTurn.text, processSignal);
340905
+ if (visualFallback) {
340906
+ tokens.push({ type: "text", text: visualFallback });
340907
+ agent.recordWorkStatus("Final visual fallback used: local mini OCR plus conservative text correction.");
340908
+ lastTurn = { ...lastTurn, text: visualFallback, errorMessage: "", stopReason: "stop" };
340909
+ }
340910
+ }
340883
340911
  if (kernelTurnFailed(agent, lastTurn)) {
340884
340912
  throw new ProviderRunError(normalizePublicProviderError(lastTurn.errorMessage || lastTurn.text, [agent.activeModelConfig()?.api_key]));
340885
340913
  }
@@ -343289,14 +343317,16 @@ var AutoRouter = class {
343289
343317
  retryDelayMs
343290
343318
  });
343291
343319
  }
343320
+ if (failure.allowModelFallback === false) return attempts.slice(0, remainingAttempts);
343292
343321
  const selection = decision.requestedSelection;
343293
343322
  if (selection.kind === "fixed") return attempts.slice(0, remainingAttempts);
343294
343323
  const scope = selection.kind === "auto" ? selection.scope : { kind: "provider", providerId: current.providerId };
343295
343324
  const subset = selection.kind === "auto" ? selection.subset : void 0;
343296
343325
  const currentGroup = current.logicalModelGroupId;
343326
+ const currentProviderId = current.providerId;
343297
343327
  const now2 = this.now();
343298
343328
  const attemptedDeployments = decision.attempts.map((attempt) => attempt.deployment);
343299
- const eligible = candidates.filter((candidate) => candidate.enabled && inScope(candidate.deployment, scope) && inSubset(candidate.deployment, subset) && !sameDeployment(candidate.deployment, current) && !attemptedDeployments.some((attempted) => sameDeployment(candidate.deployment, attempted)) && validationEligible(candidate, now2).length === 0 && this.passedInitialHardFilters(decision, candidate) && this.circuitState(candidate.deployment, now2, false) !== "open");
343329
+ const eligible = candidates.filter((candidate) => candidate.enabled && candidate.deployment.providerId === currentProviderId && inScope(candidate.deployment, scope) && inSubset(candidate.deployment, subset) && !sameDeployment(candidate.deployment, current) && !attemptedDeployments.some((attempted) => sameDeployment(candidate.deployment, attempted)) && validationEligible(candidate, now2).length === 0 && this.passedInitialHardFilters(decision, candidate) && this.circuitState(candidate.deployment, now2, false) !== "open");
343300
343330
  const equivalent = currentGroup ? eligible.find((candidate) => candidate.deployment.logicalModelGroupId === currentGroup && !candidate.fallbackOnly) : void 0;
343301
343331
  const fallback = eligible.find((candidate) => candidate.fallbackOnly);
343302
343332
  const rankedAlternates = decision.rankedCandidates.map((ranked) => eligible.find((candidate) => sameDeployment(candidate.deployment, ranked.deployment))).filter((candidate) => !!candidate && candidate !== equivalent && candidate !== fallback && !candidate.fallbackOnly);
@@ -346734,7 +346764,8 @@ ${String(event.toolArgs || "")}`;
346734
346764
  sequence,
346735
346765
  status: input2.status,
346736
346766
  guide: !isToolEvent && input2.guide ? this.normalizeGuideReceipt(input2.guide) : void 0,
346737
- displayImage: isToolEvent ? this.hydrateDisplayImage(input2.displayImage) : void 0
346767
+ displayImage: isToolEvent ? this.hydrateDisplayImage(input2.displayImage) : void 0,
346768
+ fallback: input2.fallback
346738
346769
  };
346739
346770
  if (activeRun && this.isPersistablePublicWorkEvent(event)) {
346740
346771
  activeRun.sequence = Number(sequence || activeRun.sequence + 1);
@@ -349653,9 +349684,15 @@ ${summary}`, segment, "local-summarize", true);
349653
349684
  }
349654
349685
  compressionBuildBlockStart(messages) {
349655
349686
  const activeRunId = this.currentWorkRunId();
349656
- if (!activeRunId) return 0;
349657
- const index = messages.findIndex((message) => String(message.run_id || message.runId || "") === activeRunId);
349658
- return index >= 0 ? index : 0;
349687
+ if (activeRunId) {
349688
+ const index = messages.findIndex((message) => String(message.run_id || message.runId || "") === activeRunId);
349689
+ if (index >= 0) return index;
349690
+ }
349691
+ let lastRunBoundary = -1;
349692
+ for (let index = 0; index < messages.length; index += 1) {
349693
+ if (String(messages[index]?.run_id || messages[index]?.runId || "")) lastRunBoundary = index + 1;
349694
+ }
349695
+ return lastRunBoundary >= 0 ? lastRunBoundary : messages.length;
349659
349696
  }
349660
349697
  recentContextSuffix(messages, maxMessages, tokenBudget) {
349661
349698
  if (!messages.length) return [];
@@ -350584,17 +350621,12 @@ ${msg.content}
350584
350621
  currentAttempt.sideEffectBoundary = this.routeSideEffectCommitted;
350585
350622
  if (this.routeAttemptStartedAt > 0) currentAttempt.durationMs = Math.max(0, Date.now() - this.routeAttemptStartedAt);
350586
350623
  }
350587
- if (!fallbackEnabled) {
350588
- this.lastRouteDecision.finalStatus = "failed";
350589
- this.routeAttemptStartedAt = 0;
350590
- this.persistRouteDecision(this.lastRouteDecision);
350591
- return null;
350592
- }
350593
350624
  if (!this.pendingAutoAttempts.length) {
350594
350625
  this.pendingAutoAttempts = this.autoRouter.planAttempts(this.lastRouteDecision, this.autoRouteCandidates(), {
350595
350626
  error: failure,
350596
350627
  streamCommitted: this.routeStreamCommitted,
350597
- sideEffectCommitted: this.routeSideEffectCommitted
350628
+ sideEffectCommitted: this.routeSideEffectCommitted,
350629
+ allowModelFallback: fallbackEnabled
350598
350630
  });
350599
350631
  }
350600
350632
  const next2 = this.pendingAutoAttempts.shift();
@@ -350629,7 +350661,6 @@ ${msg.content}
350629
350661
  if (!next?.name) return null;
350630
350662
  this.model = next.name;
350631
350663
  this.fixedDeployment = this.deploymentRef(next);
350632
- if (next.provider) this.config.set("models", "auto_switch_anchor_provider", next.provider);
350633
350664
  return current;
350634
350665
  }
350635
350666
  isLlmErrorText(text) {
@@ -350637,12 +350668,10 @@ ${msg.content}
350637
350668
  }
350638
350669
  scopedSwitchModels(currentModelName) {
350639
350670
  const all = this.config.allModels();
350640
- if (this.config.autoSwitchScope() !== "provider") return all;
350641
- const current = currentModelName === "auto" ? void 0 : this.config.findModel(currentModelName);
350642
- const providerId = current?.provider_id || this.config.autoSwitchAnchorProvider() || this.config.findModel(this.config.getStr("models", "default_model"))?.provider_id || all[0]?.provider_id || "";
350643
- if (!providerId) return all;
350644
- const provider = this.config.findProvider(providerId);
350645
- return all.filter((m2) => m2.provider_id === (provider?.id || providerId));
350671
+ const current = currentModelName === "auto" ? this.activeModelConfig() : this.config.findModel(currentModelName);
350672
+ const providerId = current?.provider_id || this.fixedDeployment?.providerId || (currentModelName !== "auto" ? this.activeDeployment()?.providerId : void 0);
350673
+ if (!providerId) return [];
350674
+ return all.filter((m2) => m2.provider_id === providerId);
350646
350675
  }
350647
350676
  async validateModels(selectedNames, options = {}) {
350648
350677
  if (this.modelValidationPromise) return this.modelValidationPromise;
@@ -350824,6 +350853,60 @@ ${msg.content}
350824
350853
  };
350825
350854
  return results;
350826
350855
  }
350856
+ /**
350857
+ * Final visual safety net: OCR each submitted image and ask a text-only
350858
+ * request to conservatively repair the OCR. This is intentionally callable
350859
+ * only after a visual-input refusal and after same-provider vision routing
350860
+ * has been exhausted; the original image is never sent again.
350861
+ */
350862
+ async finalVisualFallback(errorText, signal) {
350863
+ if (!/(?:vision|image|multimodal|image_url|input_image).*(?:not supported|unsupported|拒绝|不支持|failed|failure|invalid)|(?:not supported|unsupported|拒绝|不支持).*(?:vision|image|multimodal|image_url|input_image)/i.test(String(errorText || ""))) return null;
350864
+ const current = this.activeModelConfig();
350865
+ if (!current) return null;
350866
+ const alternateVision = this.config.allModels().some(
350867
+ (model) => model.enabled !== false && model.provider_id === current.provider_id && model.name !== current.name && !!model.vision && !!model.api_key && !!model.provider_url && !["unavailable", "auth_error", "invalid_config"].includes(String(model.evaluation?.status || model.validation?.status || "").toLowerCase())
350868
+ );
350869
+ if (alternateVision) return null;
350870
+ const latest = [...this.history].reverse().find((item) => item?.role === "user");
350871
+ const parts = latest?.content && Array.isArray(latest.content) ? latest.content : [];
350872
+ const images = parts.map((part) => {
350873
+ const image = part.image_url;
350874
+ return image && typeof image === "object" ? String(image.url || "") : "";
350875
+ }).filter((value) => /^data:image\/(?:png|jpeg);base64,/i.test(value)).slice(0, 4);
350876
+ if (!images.length) return null;
350877
+ const ocr = [];
350878
+ for (const [index, image] of images.entries()) {
350879
+ try {
350880
+ const result = await this.tools.finalVisualFallbackOcr(image, signal);
350881
+ if (result.ok && result.text.trim()) ocr.push({ index: index + 1, text: result.text.slice(0, 5e4), confidence: result.confidence });
350882
+ } catch {
350883
+ }
350884
+ }
350885
+ if (!ocr.length) return JSON.stringify({ ok: false, fallback: "mini_ocr_llm", error: "Local OCR returned no readable text; no visual content was fabricated." });
350886
+ const task = typeof latest?.content === "string" ? latest.content : "";
350887
+ const evidence = ocr.map((item) => `Image ${item.index} (OCR confidence ${item.confidence.toFixed(1)}):
350888
+ ${item.text}`).join("\n\n");
350889
+ const prompt = `The provider rejected image input. Answer the user's task using only this approximate OCR evidence. Correct obvious character, spacing, and line-break errors only when supported by context. Preserve [uncertain] markers for ambiguity and never invent missing visual content.
350890
+ User task:
350891
+ ${task.slice(0, 12e3)}
350892
+ OCR evidence:
350893
+ ${evidence}`;
350894
+ let corrected = "";
350895
+ try {
350896
+ const provider = this.engineModel();
350897
+ if (provider) corrected = String(await provider.chat(this.activeModelName(), [{ role: "user", content: prompt }], "You are a text-only OCR correction assistant. Be conservative and explicit about uncertainty.", 0.05, 3e3, signal) || "").trim();
350898
+ } catch {
350899
+ }
350900
+ return JSON.stringify({
350901
+ ok: !!(corrected || ocr.length),
350902
+ fallback: "mini_ocr_llm",
350903
+ approximate: true,
350904
+ warning: "\u89C6\u89C9\u8F93\u5165\u88AB\u62D2\u7EDD\uFF1B\u4EE5\u4E0B\u5185\u5BB9\u6765\u81EA\u672C\u5730 OCR\uFF0C\u5E76\u7ECF\u6587\u672C\u6A21\u578B\u4FDD\u5B88\u6821\u6B63\uFF0C\u53EF\u80FD\u4E0D\u5B8C\u6574\u3002",
350905
+ raw_ocr: ocr,
350906
+ corrected: corrected || ocr.map((item) => item.text).join("\n\n"),
350907
+ uncertainty: corrected ? "preserved" : "raw_ocr_only"
350908
+ }, null, 2);
350909
+ }
350827
350910
  engineModel() {
350828
350911
  if (this.forcedProvider) {
350829
350912
  const active = this.activeDeployment();
@@ -351206,8 +351289,10 @@ ${persisted.map((guide, index) => `Guide ${index + 1}: ${guide.text}`).join("\n"
351206
351289
  }
351207
351290
  const selectedModel = this.activeModelConfig();
351208
351291
  if (images.length && !selectedModel?.vision) {
351209
- this.status = "idle";
351210
- return [{ type: "text", text: `[Vision unavailable] ${this.activeModelName() || this.model} has not passed image-input validation. Select a validated vision model before asking about attachments.` }];
351292
+ const hasSameProviderVision = selectedModel && this.config.allModels().some(
351293
+ (model) => model.enabled !== false && model.provider_id === selectedModel.provider_id && model.name !== selectedModel.name && !!model.vision
351294
+ );
351295
+ if (hasSameProviderVision) this.switchToFallbackModel("vision input not supported by the selected model");
351211
351296
  }
351212
351297
  const now2 = this.nowLabel();
351213
351298
  const visibleUserInput = inputEnvelope?.visibleUserInput === void 0 ? text : String(inputEnvelope.visibleUserInput || "");
@@ -351968,7 +352053,10 @@ ${items.map((item) => this.formatAutomation(item)).join("\n")}`;
351968
352053
  if (!sa) return "[Subagent] Not found.";
351969
352054
  const requestedModel = this.normalizeSubagentModelSelection(sa.model && sa.model !== "default" ? sa.model : this.modelSelectionValue() || this.model);
351970
352055
  const requestedDeployment = parseDeploymentSelectionValue2(requestedModel);
351971
- const assignedModel = requestedModel === "auto" ? this.activeModelConfig() : requestedDeployment ? this.config.findDeployment(requestedDeployment) : this.config.findModel(requestedModel);
352056
+ let assignedModel = requestedModel === "auto" ? this.activeModelConfig() : requestedDeployment ? this.config.findDeployment(requestedDeployment) : this.config.findModel(requestedModel);
352057
+ if (!assignedModel && !requestedDeployment && requestedModel !== "auto") {
352058
+ assignedModel = this.activeModelConfig();
352059
+ }
351972
352060
  const model = assignedModel?.name || (requestedModel === "auto" ? this.activeModelName() : requestedModel);
351973
352061
  const activeModel = this.activeModelConfig();
351974
352062
  const activeProvider = this.engineModel();
@@ -353397,6 +353485,32 @@ var ConversationKernel = class {
353397
353485
  followUp: queued?.followUp.slice() || []
353398
353486
  };
353399
353487
  }
353488
+ /**
353489
+ * dev-0.5.6: 排队 followUp 消息 drain 时转成普通用户消息载荷。
353490
+ *
353491
+ * 入队时(enqueueSameSession)为去重/编辑保留了 clientMessageId,并把
353492
+ * runId 固定为入队时运行的 runId;若原样传给 process,写入 chatMessages
353493
+ * 的用户消息会携带旧 runId + clientMessageId,渲染端(PC renderTranscript /
353494
+ * 移动端 projectRemoteConversationItems)会把「clientMessageId + runId 命中
353495
+ * workRuns」的消息误判为 guide 消息而跳过气泡,导致排队自动发送的消息不
353496
+ * 显示在用户输入时间线。清除这两个字段后 process 走普通用户消息分支
353497
+ * (chatMessages.push,mode 取 visibleMode,runId 取当前 run)。
353498
+ */
353499
+ drainQueuedFollowUpMessage(message) {
353500
+ if (typeof message === "string") return message;
353501
+ const text = String(message.text || "");
353502
+ const images = message.images;
353503
+ const attachments = message.attachments;
353504
+ const visible = message.visibleUserInput;
353505
+ const visibleMode = message.visibleMode;
353506
+ return {
353507
+ text,
353508
+ ...images?.length ? { images } : {},
353509
+ ...attachments?.length ? { attachments } : {},
353510
+ ...visible ? { visibleUserInput: visible } : {},
353511
+ ...visibleMode ? { visibleMode } : {}
353512
+ };
353513
+ }
353400
353514
  queueItems(target) {
353401
353515
  const runtime = this.findRuntime(target);
353402
353516
  if (!runtime) return [];
@@ -354138,7 +354252,7 @@ ${batchText}`,
354138
354252
  };
354139
354253
  lastTokens = await this.runSingle(runtime, batchMessage, "steer");
354140
354254
  } else {
354141
- lastTokens = await this.runSingle(runtime, next.message, next.queueMode);
354255
+ lastTokens = await this.runSingle(runtime, this.drainQueuedFollowUpMessage(next.message), next.queueMode);
354142
354256
  }
354143
354257
  }
354144
354258
  const rootMessage = runtime.runner.subagents.readRootInbox()[0];
@@ -354597,7 +354711,11 @@ ${text}`;
354597
354711
  type: "queue_update",
354598
354712
  content: "Conversation queue updated.",
354599
354713
  conversationId: runtime.id,
354600
- queue: this.queued(runtime.target)
354714
+ queue: this.queued(runtime.target),
354715
+ // Structured rows with stable kernel ids so every consumer (PC UI and
354716
+ // the paired mobile client) can render/edit/delete the same items.
354717
+ queueItems: this.queueItems(runtime.target),
354718
+ queuePaused: runtime.queuePaused === true
354601
354719
  });
354602
354720
  }
354603
354721
  clearQueued(runtime) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "newmark-agent",
3
3
  "productName": "Newmark Agent",
4
- "version": "0.5.3",
4
+ "version": "0.5.7",
5
5
  "description": "Newmark Agent — Portable AI coding agent with rich GUI and CLI (TypeScript)",
6
6
  "homepage": "https://github.com/positer/Newmark-Agent",
7
7
  "repository": {
@@ -53,7 +53,7 @@
53
53
  "test:desktop": "npm run build && node dist/tests/conversationHistoryFirstVerify.js && npm run test:desktop:built",
54
54
  "test:deletion-safety": "npm run build && npm run test:deletion-safety:built",
55
55
  "test:deletion-safety:built": "node scripts/deletion-safety-stress.cjs",
56
- "test:desktop:built": "node dist/tests/verify.js && node dist/tests/thinkingTierMapCacheStressVerify.js && node dist/tests/computerUseSessionVerify.js && node dist/tests/contextSystemV2Verify.js && node dist/tests/contextSystemV2StressVerify.js && node dist/tests/providerAdapterV2Verify.js && node dist/tests/providerTimeoutRecoveryVerify.js && node dist/tests/agentRuntimeV2Verify.js && node dist/tests/toolchainExposureV2Verify.js && node dist/tests/localOcrFallbackVerify.js && node dist/tests/dev018ModeSubagentStressVerify.js && node dist/tests/conversationBranchStressVerify.js && node dist/tests/conversationArchiveConcurrencyVerify.js && node dist/tests/conversationArchiveRuntimeVerify.js && node dist/tests/dev040ComprehensiveStressVerify.js && node dist/tests/memoryPolicyVerify.js && node dist/tests/newmarkSelectVerify.js && node dist/tests/mcpManagerVerify.js && node dist/tests/dshCompatibilityVerify.js && node dist/tests/performanceOptimizationVerify.js && node scripts/compression-pressure-stress.cjs && node dist/tests/compressionFidelityVerify.js && node dist/tests/responseTrajectoryVerify.js && node dist/tests/normalChatRegressionVerify.js && node dist/tests/dev008-subagent.js && node dist/tests/dev009Verify.js && node dist/tests/runtimeIsolationVerify.js && node dist/tests/runtimePoolCapacityVerify.js && node dist/tests/guideWorkRunVerify.js && node dist/tests/modelSwitchBehaviorVerify.js && node scripts/flow-pause-stop-draft-stress.cjs && node dist/tests/guideUiReconcileVerify.js && node dist/tests/queueAttachmentIsolationVerify.js && node dist/tests/workspaceMenuVerify.js && node dist/tests/userImagePersistenceVerify.js && node dist/tests/displayImageVerify.js && node dist/tests/visualPreferencesVerify.js && node dist/tests/browserUseVerify.js && node dist/tests/toolProcessVerify.js && node dist/tests/toolProvisioningVerify.js && node dist/tests/taskToolsVerify.js && node dist/tests/contextCacheHitStressVerify.js && node dist/tests/startupPrewarmVerify.js && node dist/tests/pdfPreviewServerVerify.js && node dist/tests/editorLifecycleVerify.js && node dist/tests/terminalTakeoverVerify.js && node dist/tests/workspaceFileRouterVerify.js && node dist/tests/screenCaptureIndependentVerify.js && node dist/tests/computerUsePerformanceVerify.js && node dist/tests/autoRouterVerify.js && node dist/tests/autoAgentIntegrationVerify.js && node dist/tests/modelRecoveryStressVerify.js && node dist/tests/autoRouteRatingVerify.js && node dist/tests/providerIdentityVerify.js && node dist/tests/modelValidationVerify.js && node dist/tests/modelValidationAgentIntegrationVerify.js && node scripts/deletion-safety-stress.cjs",
56
+ "test:desktop:built": "node dist/tests/verify.js && node dist/tests/thinkingTierMapCacheStressVerify.js && node dist/tests/computerUseSessionVerify.js && node dist/tests/contextSystemV2Verify.js && node dist/tests/contextSystemV2StressVerify.js && node dist/tests/providerAdapterV2Verify.js && node dist/tests/providerTimeoutRecoveryVerify.js && node dist/tests/agentRuntimeV2Verify.js && node dist/tests/toolchainExposureV2Verify.js && node dist/tests/localOcrFallbackVerify.js && node dist/tests/dev018ModeSubagentStressVerify.js && node dist/tests/conversationBranchStressVerify.js && node dist/tests/conversationArchiveConcurrencyVerify.js && node dist/tests/conversationArchiveRuntimeVerify.js && node dist/tests/dev040ComprehensiveStressVerify.js && node dist/tests/memoryPolicyVerify.js && node dist/tests/newmarkSelectVerify.js && node dist/tests/mcpManagerVerify.js && node dist/tests/dshCompatibilityVerify.js && node dist/tests/performanceOptimizationVerify.js && node scripts/compression-pressure-stress.cjs && node dist/tests/compressionFidelityVerify.js && node dist/tests/responseTrajectoryVerify.js && node dist/tests/normalChatRegressionVerify.js && node dist/tests/dev008-subagent.js && node dist/tests/dev009Verify.js && node dist/tests/runtimeIsolationVerify.js && node dist/tests/runtimePoolCapacityVerify.js && node dist/tests/guideWorkRunVerify.js && node dist/tests/modelSwitchBehaviorVerify.js && node scripts/flow-pause-stop-draft-stress.cjs && node dist/tests/guideUiReconcileVerify.js && node dist/tests/workReviewDedupVerify.js && node dist/tests/queueAttachmentIsolationVerify.js && node dist/tests/queueDrainUserMessageVerify.js && node dist/tests/pcGlassMigrationVerify.js && node dist/tests/longHistoryDisplayVerify.js && node dist/tests/workspaceMenuVerify.js && node dist/tests/userImagePersistenceVerify.js && node dist/tests/displayImageVerify.js && node dist/tests/visualPreferencesVerify.js && node dist/tests/browserUseVerify.js && node dist/tests/toolProcessVerify.js && node dist/tests/toolProvisioningVerify.js && node dist/tests/taskToolsVerify.js && node dist/tests/contextCacheHitStressVerify.js && node dist/tests/startupPrewarmVerify.js && node dist/tests/pdfPreviewServerVerify.js && node dist/tests/editorLifecycleVerify.js && node dist/tests/terminalTakeoverVerify.js && node dist/tests/workspaceFileRouterVerify.js && node dist/tests/screenCaptureIndependentVerify.js && node dist/tests/computerUsePerformanceVerify.js && node dist/tests/autoRouterVerify.js && node dist/tests/autoAgentIntegrationVerify.js && node dist/tests/modelRecoveryStressVerify.js && node dist/tests/autoRouteRatingVerify.js && node dist/tests/providerIdentityVerify.js && node dist/tests/modelValidationVerify.js && node dist/tests/modelValidationAgentIntegrationVerify.js && node scripts/deletion-safety-stress.cjs",
57
57
  "test:conversation-branch-stress": "npm run build && node dist/tests/conversationBranchStressVerify.js",
58
58
  "test:conversation-archive-concurrency": "npm run build && node dist/tests/conversationArchiveConcurrencyVerify.js",
59
59
  "test:memory-policy": "npm run build && node dist/tests/memoryPolicyVerify.js",
@@ -126,6 +126,9 @@
126
126
  "release:ui-gemma-removal-smoke": "node scripts/release-ui-gemma-removal-smoke.cjs",
127
127
  "release:ui-icon-smoke": "node scripts/release-ui-icon-smoke.cjs",
128
128
  "release:ui-render-performance-smoke": "node scripts/release-ui-render-performance-smoke.cjs",
129
+ "test:liquid-renderer-calls": "node scripts/measure-liquid-renderer-calls.cjs",
130
+ "test:liquid-renderer-electron": "node scripts/dev-liquid-renderer-performance-smoke.cjs",
131
+ "release:ui-incremental-render-stress": "node scripts/release-ui-incremental-render-stress.cjs",
129
132
  "release:ui-flow-subagent-smoke": "node scripts/release-ui-flow-subagent-smoke.cjs",
130
133
  "release:ui-media-md-smoke": "node scripts/release-ui-media-md-smoke.cjs",
131
134
  "release:ui-native-editor-smoke": "node scripts/release-ui-native-editor-smoke.cjs",
@@ -184,7 +187,9 @@
184
187
  "dist:mac": "npm run build:clean && electron-builder --mac",
185
188
  "dist:windows-release": "npm run test:full-release && npm run build:clean && node scripts/dist-portable.cjs",
186
189
  "release:ocr-budget-smoke": "node scripts/verify-ocr-package-budget.cjs",
187
- "release:packaged-ocr-smoke": "node scripts/release-packaged-ocr-smoke.cjs"
190
+ "release:packaged-ocr-smoke": "node scripts/release-packaged-ocr-smoke.cjs",
191
+ "test:stream-unlimited-timeout-stress": "npm run build && node dist/tests/streamUnlimitedTimeoutStressVerify.js",
192
+ "test:queue-unify-stress": "npm run build && node dist/tests/queueUnifyStressVerify.js && node dist/tests/queueDrainUserMessageVerify.js"
188
193
  },
189
194
  "build": {
190
195
  "npmRebuild": false,