flavor-code 1.2.15 → 1.2.16

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.
@@ -15,7 +15,7 @@ import {
15
15
  packageVersion,
16
16
  redactErrorText,
17
17
  transcriptReducer
18
- } from "./chunk-5TG3E2EJ.js";
18
+ } from "./chunk-5SRARNAC.js";
19
19
  import "./chunk-IG4Z23CL.js";
20
20
  import {
21
21
  Box_default,
@@ -12,4 +12,11 @@ export interface OAuthTokenStore {
12
12
  load(): Promise<Record<string, StoredToken>>;
13
13
  save(tokens: Record<string, StoredToken>): Promise<void>;
14
14
  }
15
+ /**
16
+ * Reduce the token store to a single credential. `/login` is a switch-to
17
+ * operation: keeping tokens from earlier services made the runtime pick the
18
+ * active provider by registration order, so the welcome card could show a
19
+ * stale service (e.g. a previous "Token Plan") instead of the one just logged in.
20
+ */
21
+ export declare function retainOnlyCredentials(store: OAuthTokenStore, keepCredentialId: string): Promise<void>;
15
22
  export declare function createFileTokenStore(filePath: string): OAuthTokenStore;
@@ -2900,6 +2900,7 @@ var MVP_COMMANDS = [
2900
2900
  "init",
2901
2901
  "config",
2902
2902
  "login",
2903
+ "logout",
2903
2904
  "permissions",
2904
2905
  "skills",
2905
2906
  "plugins",
@@ -2937,6 +2938,7 @@ var COMMAND_DESCRIPTIONS = {
2937
2938
  init: "Initialize Flavor project files",
2938
2939
  config: "Show the resolved configuration",
2939
2940
  login: "Authenticate via OAuth PKCE",
2941
+ logout: "Clear stored OAuth credentials and restore configured models",
2940
2942
  permissions: "Change the tool permission mode",
2941
2943
  skills: "List discovered skills",
2942
2944
  plugins: "List loaded plugins",
@@ -3214,6 +3216,7 @@ var HELP = [
3214
3216
  "/model <main|subagent> <provider:model> switch any configured model",
3215
3217
  "/permissions <default|acceptEdits|plan|bypassPermissions|auto|bubble>",
3216
3218
  "/login authenticate via OAuth PKCE",
3219
+ "/logout clear stored OAuth credentials",
3217
3220
  "/init /config /skills /plugins /hooks /tasks",
3218
3221
  "/memory /remember [type] <text> /forget <text-or-id> /forget-cold /finish",
3219
3222
  "/checkpoint [label] /tree /rewind <node> /unrevert /fork <node>",
@@ -3628,6 +3631,8 @@ var FlavorSession = class {
3628
3631
  } else if (command.name === "login") {
3629
3632
  this.#notice("Opening browser for authentication...");
3630
3633
  this.#notice(await this.#services.login());
3634
+ } else if (command.name === "logout") {
3635
+ this.#notice(await this.#services.logout());
3631
3636
  } else if (command.name === "help") this.#notice(HELP);
3632
3637
  else if (command.name === "exit") this.#services.output({ type: "exit" });
3633
3638
  }
@@ -10646,7 +10651,7 @@ import { readFile as readFile11 } from "fs/promises";
10646
10651
  import { join as join16 } from "path";
10647
10652
 
10648
10653
  // src/tools/shell.ts
10649
- import { spawn as spawn6 } from "child_process";
10654
+ import { spawn as spawn6, spawnSync } from "child_process";
10650
10655
  import { isAbsolute as isAbsolute6, relative as relative11, resolve as resolve13, sep as sep10 } from "path";
10651
10656
  import { z as z16 } from "zod";
10652
10657
 
@@ -10776,6 +10781,29 @@ function tokenizeCommandLine(command) {
10776
10781
  function unquoteToken(token) {
10777
10782
  return token.length >= 2 && token.startsWith('"') && token.endsWith('"') ? token.slice(1, -1) : token;
10778
10783
  }
10784
+ var cachedWindowsShell;
10785
+ function hasExecutable(name) {
10786
+ try {
10787
+ return spawnSync("where", [name], { stdio: "ignore", windowsHide: true }).status === 0;
10788
+ } catch {
10789
+ return false;
10790
+ }
10791
+ }
10792
+ function detectWindowsShell() {
10793
+ if (cachedWindowsShell !== void 0) return cachedWindowsShell;
10794
+ cachedWindowsShell = hasExecutable("pwsh") ? "pwsh" : hasExecutable("powershell") ? "powershell" : "cmd";
10795
+ return cachedWindowsShell;
10796
+ }
10797
+ function psQuote(token) {
10798
+ return `'${token.replace(/'/g, "''")}'`;
10799
+ }
10800
+ function buildWindowsCommandLine(kind, commandLine, command, args) {
10801
+ if (kind === "cmd") return `chcp 65001>nul & ${commandLine}`;
10802
+ const executable = kind === "pwsh" ? "pwsh" : "powershell";
10803
+ const script = `& ${psQuote(command)}${args.length > 0 ? ` ${args.map(psQuote).join(" ")}` : ""}; exit $LASTEXITCODE`;
10804
+ const encoded = Buffer.from(script, "utf16le").toString("base64");
10805
+ return `chcp 65001>nul & ${executable} -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand ${encoded}`;
10806
+ }
10779
10807
  function createShellTool(workspace, options = {}) {
10780
10808
  const root = resolve13(workspace);
10781
10809
  const maxBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES2;
@@ -10896,7 +10924,7 @@ async function executeShell(root, input, cancellation, maxBytes, onOutput) {
10896
10924
  const quoteArg = (s) => s.includes(" ") ? `"${s.replace(/"/g, '""')}"` : s;
10897
10925
  const quoted = input.args.map(quoteArg).join(" ");
10898
10926
  const commandLine = quoted.length > 0 ? `${quoteArg(input.command)} ${quoted}` : quoteArg(input.command);
10899
- const shellCommandLine = process.platform === "win32" ? `chcp 65001>nul & ${commandLine}` : commandLine;
10927
+ const shellCommandLine = process.platform === "win32" ? buildWindowsCommandLine(detectWindowsShell(), commandLine, input.command, input.args) : commandLine;
10900
10928
  const child = spawn6(shellCommandLine, {
10901
10929
  cwd,
10902
10930
  shell: true,
@@ -12435,6 +12463,11 @@ function escapeHtml(text) {
12435
12463
 
12436
12464
  // src/auth/store.ts
12437
12465
  import { dirname as dirname13 } from "path";
12466
+ async function retainOnlyCredentials(store, keepCredentialId) {
12467
+ const tokens = await store.load();
12468
+ const retained = Object.fromEntries(Object.entries(tokens).filter(([id]) => id === keepCredentialId));
12469
+ await store.save(retained);
12470
+ }
12438
12471
  function createFileTokenStore(filePath) {
12439
12472
  let baseline = {};
12440
12473
  const store = {
@@ -19464,7 +19497,10 @@ async function createProductionRuntime(options) {
19464
19497
  states: { ...taskStates },
19465
19498
  results: { ...taskResults }
19466
19499
  },
19467
- models: { main: harness.mainModelId, subagent: harness.subagentModelId },
19500
+ // Persist the resolved decision, not the harness snapshot: after logout the
19501
+ // harness may still hold the old login model, and resuming from that stale
19502
+ // value is what made the welcome card show a previous service.
19503
+ models: { main: mainModel, subagent: childModel },
19468
19504
  permissionMode: harness.permissionMode,
19469
19505
  memory: memoryLifecycle,
19470
19506
  timeline: { version: 1, state: timelineState }
@@ -20105,8 +20141,8 @@ async function createProductionRuntime(options) {
20105
20141
  const services = {
20106
20142
  hooks,
20107
20143
  workspace,
20108
- mainModel: () => harness.mainModelId,
20109
- subagentModel: () => harness.subagentModelId,
20144
+ mainModel: () => mainModel,
20145
+ subagentModel: () => childModel,
20110
20146
  llmServiceName: () => effectiveLlm?.serviceName,
20111
20147
  permissionMode: () => harness.permissionMode,
20112
20148
  ...palServices === void 0 ? {} : { pals: palServices },
@@ -20180,6 +20216,8 @@ async function createProductionRuntime(options) {
20180
20216
  }
20181
20217
  }
20182
20218
  harness.setModel(role, id);
20219
+ if (role === "main") mainModel = id;
20220
+ else childModel = id;
20183
20221
  await persist();
20184
20222
  },
20185
20223
  setPermissionMode: async (mode) => {
@@ -20426,12 +20464,48 @@ ${renderMemoryDocument(entries)}`;
20426
20464
  goalOrchestrator.setModels(mainModel, mainModel);
20427
20465
  delete selectedModels.mainError;
20428
20466
  delete selectedModels.childError;
20467
+ await retainOnlyCredentials(tokenStore, credentialId);
20429
20468
  if (!secrets.includes(next.accessToken)) secrets.push(next.accessToken);
20430
20469
  await persist();
20431
20470
  return `Authenticated to "${next.serviceName}". Main model ${mainModel}; subagent ${childModel}; gateway ${next.baseURL}. Configuration is active now.`;
20432
20471
  } catch (error) {
20433
20472
  return `Login failed: ${message(error)}`;
20434
20473
  }
20474
+ },
20475
+ async logout() {
20476
+ const tokenStore = createFileTokenStore(join22(home, ".flavor-code", "auth.json"));
20477
+ const tokens = await tokenStore.load();
20478
+ const hadCredentials = Object.keys(tokens).length > 0 || effectiveLlm !== void 0;
20479
+ if (!hadCredentials) {
20480
+ return "Not authenticated \u2014 no stored OAuth credentials to clear.";
20481
+ }
20482
+ for (let i = registeredProviders.length - 1; i >= 0; i -= 1) {
20483
+ const provider = registeredProviders[i];
20484
+ if (provider !== void 0 && provider.pkceManaged === true) {
20485
+ registry.unregister(provider.name);
20486
+ registeredProviders.splice(i, 1);
20487
+ }
20488
+ }
20489
+ if (effectiveLlm !== void 0) {
20490
+ registry.unregister(effectiveLlm.providerId);
20491
+ effectiveLlm = void 0;
20492
+ }
20493
+ await tokenStore.save({});
20494
+ const fallback = selectModels(config, registeredProviders, diagnostics);
20495
+ mainModel = fallback.main;
20496
+ childModel = fallback.child;
20497
+ if (fallback.mainError === void 0) delete selectedModels.mainError;
20498
+ else selectedModels.mainError = fallback.mainError;
20499
+ if (fallback.childError === void 0) delete selectedModels.childError;
20500
+ else selectedModels.childError = fallback.childError;
20501
+ if (fallback.mainError === void 0 && registry.has(safeProvider(mainModel)) && registry.has(safeProvider(childModel))) {
20502
+ harness.setModel("main", mainModel);
20503
+ harness.setModel("subagent", childModel);
20504
+ hallucinationGuard.setModel(childModel);
20505
+ goalOrchestrator.setModels(mainModel, mainModel);
20506
+ }
20507
+ await persist();
20508
+ return fallback.mainError === void 0 ? `Logged out. Cleared OAuth credentials. Main model ${mainModel}; subagent ${childModel}.` : `Logged out. Cleared OAuth credentials. ${fallback.mainError}`;
20435
20509
  }
20436
20510
  };
20437
20511
  if (config.sleep) {
@@ -4,7 +4,7 @@ import {
4
4
  message,
5
5
  redactErrorText,
6
6
  redactSecrets
7
- } from "./chunk-5TG3E2EJ.js";
7
+ } from "./chunk-5SRARNAC.js";
8
8
 
9
9
  // src/rpc/server.ts
10
10
  import { createInterface } from "readline";
package/dist/cli.js CHANGED
@@ -3,7 +3,7 @@ import { createRequire } from "node:module"; const require = createRequire(impor
3
3
  import {
4
4
  FlavorRpcServer,
5
5
  TraceRecorder
6
- } from "./chunk-BKARQJQZ.js";
6
+ } from "./chunk-PGS3M32Y.js";
7
7
  import {
8
8
  staticTaskLines
9
9
  } from "./chunk-KKIBYDJI.js";
@@ -22,7 +22,7 @@ import {
22
22
  packageVersion,
23
23
  redactErrorText,
24
24
  runPalBroker
25
- } from "./chunk-5TG3E2EJ.js";
25
+ } from "./chunk-5SRARNAC.js";
26
26
  import {
27
27
  McpServerConfigSchema,
28
28
  McpServerNameSchema,
@@ -861,7 +861,7 @@ async function runInteractiveCli(props) {
861
861
  const [{ render, AlternateScreen }, { createElement }, { App }] = await Promise.all([
862
862
  import("./claude-ink-ORUA7GWG.js"),
863
863
  import("react"),
864
- import("./app-3KW2FTVJ.js")
864
+ import("./app-7ZCJ3UOI.js")
865
865
  ]);
866
866
  const instance = await render(createElement(
867
867
  AlternateScreen,
@@ -505,6 +505,7 @@ var DESKTOP_CHANNELS = {
505
505
  d2cRunQualityJudge: "desktop:d2c-run-quality-judge",
506
506
  d2cResolveQualityIssue: "desktop:d2c-resolve-quality-issue",
507
507
  d2cSetManualAcceptance: "desktop:d2c-set-manual-acceptance",
508
+ e2eGetDeliveryRun: "desktop:e2e-get-delivery-run",
508
509
  event: "desktop:event"
509
510
  };
510
511
 
@@ -11210,7 +11211,7 @@ import { readFile as readFile12 } from "fs/promises";
11210
11211
  import { join as join17 } from "path";
11211
11212
 
11212
11213
  // src/tools/shell.ts
11213
- import { spawn as spawn3 } from "child_process";
11214
+ import { spawn as spawn3, spawnSync } from "child_process";
11214
11215
  import { isAbsolute as isAbsolute8, relative as relative11, resolve as resolve13, sep as sep10 } from "path";
11215
11216
  import { z as z21 } from "zod";
11216
11217
 
@@ -11340,6 +11341,29 @@ function tokenizeCommandLine(command) {
11340
11341
  function unquoteToken(token) {
11341
11342
  return token.length >= 2 && token.startsWith('"') && token.endsWith('"') ? token.slice(1, -1) : token;
11342
11343
  }
11344
+ var cachedWindowsShell;
11345
+ function hasExecutable(name) {
11346
+ try {
11347
+ return spawnSync("where", [name], { stdio: "ignore", windowsHide: true }).status === 0;
11348
+ } catch {
11349
+ return false;
11350
+ }
11351
+ }
11352
+ function detectWindowsShell() {
11353
+ if (cachedWindowsShell !== void 0) return cachedWindowsShell;
11354
+ cachedWindowsShell = hasExecutable("pwsh") ? "pwsh" : hasExecutable("powershell") ? "powershell" : "cmd";
11355
+ return cachedWindowsShell;
11356
+ }
11357
+ function psQuote(token) {
11358
+ return `'${token.replace(/'/g, "''")}'`;
11359
+ }
11360
+ function buildWindowsCommandLine(kind, commandLine, command, args) {
11361
+ if (kind === "cmd") return `chcp 65001>nul & ${commandLine}`;
11362
+ const executable = kind === "pwsh" ? "pwsh" : "powershell";
11363
+ const script = `& ${psQuote(command)}${args.length > 0 ? ` ${args.map(psQuote).join(" ")}` : ""}; exit $LASTEXITCODE`;
11364
+ const encoded = Buffer.from(script, "utf16le").toString("base64");
11365
+ return `chcp 65001>nul & ${executable} -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand ${encoded}`;
11366
+ }
11343
11367
  function createShellTool(workspace, options = {}) {
11344
11368
  const root = resolve13(workspace);
11345
11369
  const maxBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES2;
@@ -11460,7 +11484,7 @@ async function executeShell(root, input, cancellation, maxBytes, onOutput) {
11460
11484
  const quoteArg = (s) => s.includes(" ") ? `"${s.replace(/"/g, '""')}"` : s;
11461
11485
  const quoted = input.args.map(quoteArg).join(" ");
11462
11486
  const commandLine = quoted.length > 0 ? `${quoteArg(input.command)} ${quoted}` : quoteArg(input.command);
11463
- const shellCommandLine = process.platform === "win32" ? `chcp 65001>nul & ${commandLine}` : commandLine;
11487
+ const shellCommandLine = process.platform === "win32" ? buildWindowsCommandLine(detectWindowsShell(), commandLine, input.command, input.args) : commandLine;
11464
11488
  const child = spawn3(shellCommandLine, {
11465
11489
  cwd,
11466
11490
  shell: true,
@@ -13090,6 +13114,11 @@ function escapeHtml(text) {
13090
13114
 
13091
13115
  // src/auth/store.ts
13092
13116
  import { dirname as dirname13 } from "path";
13117
+ async function retainOnlyCredentials(store, keepCredentialId) {
13118
+ const tokens2 = await store.load();
13119
+ const retained = Object.fromEntries(Object.entries(tokens2).filter(([id]) => id === keepCredentialId));
13120
+ await store.save(retained);
13121
+ }
13093
13122
  function createFileTokenStore(filePath) {
13094
13123
  let baseline = {};
13095
13124
  const store = {
@@ -18789,6 +18818,7 @@ var MVP_COMMANDS = [
18789
18818
  "init",
18790
18819
  "config",
18791
18820
  "login",
18821
+ "logout",
18792
18822
  "permissions",
18793
18823
  "skills",
18794
18824
  "plugins",
@@ -19066,6 +19096,7 @@ var HELP = [
19066
19096
  "/model <main|subagent> <provider:model> switch any configured model",
19067
19097
  "/permissions <default|acceptEdits|plan|bypassPermissions|auto|bubble>",
19068
19098
  "/login authenticate via OAuth PKCE",
19099
+ "/logout clear stored OAuth credentials",
19069
19100
  "/init /config /skills /plugins /hooks /tasks",
19070
19101
  "/memory /remember [type] <text> /forget <text-or-id> /forget-cold /finish",
19071
19102
  "/checkpoint [label] /tree /rewind <node> /unrevert /fork <node>",
@@ -19480,6 +19511,8 @@ var FlavorSession = class {
19480
19511
  } else if (command.name === "login") {
19481
19512
  this.#notice("Opening browser for authentication...");
19482
19513
  this.#notice(await this.#services.login());
19514
+ } else if (command.name === "logout") {
19515
+ this.#notice(await this.#services.logout());
19483
19516
  } else if (command.name === "help") this.#notice(HELP);
19484
19517
  else if (command.name === "exit") this.#services.output({ type: "exit" });
19485
19518
  }
@@ -23167,7 +23200,10 @@ async function createProductionRuntime(options) {
23167
23200
  states: { ...taskStates },
23168
23201
  results: { ...taskResults }
23169
23202
  },
23170
- models: { main: harness.mainModelId, subagent: harness.subagentModelId },
23203
+ // Persist the resolved decision, not the harness snapshot: after logout the
23204
+ // harness may still hold the old login model, and resuming from that stale
23205
+ // value is what made the welcome card show a previous service.
23206
+ models: { main: mainModel, subagent: childModel },
23171
23207
  permissionMode: harness.permissionMode,
23172
23208
  memory: memoryLifecycle,
23173
23209
  timeline: { version: 1, state: timelineState }
@@ -23808,8 +23844,8 @@ async function createProductionRuntime(options) {
23808
23844
  const services = {
23809
23845
  hooks,
23810
23846
  workspace,
23811
- mainModel: () => harness.mainModelId,
23812
- subagentModel: () => harness.subagentModelId,
23847
+ mainModel: () => mainModel,
23848
+ subagentModel: () => childModel,
23813
23849
  llmServiceName: () => effectiveLlm?.serviceName,
23814
23850
  permissionMode: () => harness.permissionMode,
23815
23851
  ...palServices === void 0 ? {} : { pals: palServices },
@@ -23883,6 +23919,8 @@ async function createProductionRuntime(options) {
23883
23919
  }
23884
23920
  }
23885
23921
  harness.setModel(role, id);
23922
+ if (role === "main") mainModel = id;
23923
+ else childModel = id;
23886
23924
  await persist();
23887
23925
  },
23888
23926
  setPermissionMode: async (mode) => {
@@ -24129,12 +24167,48 @@ ${renderMemoryDocument(entries)}`;
24129
24167
  goalOrchestrator.setModels(mainModel, mainModel);
24130
24168
  delete selectedModels.mainError;
24131
24169
  delete selectedModels.childError;
24170
+ await retainOnlyCredentials(tokenStore, credentialId);
24132
24171
  if (!secrets.includes(next.accessToken)) secrets.push(next.accessToken);
24133
24172
  await persist();
24134
24173
  return `Authenticated to "${next.serviceName}". Main model ${mainModel}; subagent ${childModel}; gateway ${next.baseURL}. Configuration is active now.`;
24135
24174
  } catch (error) {
24136
24175
  return `Login failed: ${message(error)}`;
24137
24176
  }
24177
+ },
24178
+ async logout() {
24179
+ const tokenStore = createFileTokenStore(join29(home, ".flavor-code", "auth.json"));
24180
+ const tokens2 = await tokenStore.load();
24181
+ const hadCredentials = Object.keys(tokens2).length > 0 || effectiveLlm !== void 0;
24182
+ if (!hadCredentials) {
24183
+ return "Not authenticated \u2014 no stored OAuth credentials to clear.";
24184
+ }
24185
+ for (let i = registeredProviders.length - 1; i >= 0; i -= 1) {
24186
+ const provider = registeredProviders[i];
24187
+ if (provider !== void 0 && provider.pkceManaged === true) {
24188
+ registry.unregister(provider.name);
24189
+ registeredProviders.splice(i, 1);
24190
+ }
24191
+ }
24192
+ if (effectiveLlm !== void 0) {
24193
+ registry.unregister(effectiveLlm.providerId);
24194
+ effectiveLlm = void 0;
24195
+ }
24196
+ await tokenStore.save({});
24197
+ const fallback = selectModels(config, registeredProviders, diagnostics);
24198
+ mainModel = fallback.main;
24199
+ childModel = fallback.child;
24200
+ if (fallback.mainError === void 0) delete selectedModels.mainError;
24201
+ else selectedModels.mainError = fallback.mainError;
24202
+ if (fallback.childError === void 0) delete selectedModels.childError;
24203
+ else selectedModels.childError = fallback.childError;
24204
+ if (fallback.mainError === void 0 && registry.has(safeProvider(mainModel)) && registry.has(safeProvider(childModel))) {
24205
+ harness.setModel("main", mainModel);
24206
+ harness.setModel("subagent", childModel);
24207
+ hallucinationGuard.setModel(childModel);
24208
+ goalOrchestrator.setModels(mainModel, mainModel);
24209
+ }
24210
+ await persist();
24211
+ return fallback.mainError === void 0 ? `Logged out. Cleared OAuth credentials. Main model ${mainModel}; subagent ${childModel}.` : `Logged out. Cleared OAuth credentials. ${fallback.mainError}`;
24138
24212
  }
24139
24213
  };
24140
24214
  if (config.sleep) {
@@ -27738,11 +27812,12 @@ var DesktopRuntimeController = class {
27738
27812
  ].join("\n");
27739
27813
  const delivery = await readDeliveryRun(workspace, task);
27740
27814
  if (delivery?.nodes.api.status === "running") {
27815
+ const apiArtifacts = await Promise.all(generated.files.map(async (file) => artifactRef(file, await readFile33(join39(project, file)))));
27741
27816
  const completed = await updateDeliveryRun(
27742
27817
  workspace,
27743
27818
  task,
27744
27819
  delivery.revision,
27745
- (run) => completeDeliveryNode(run, "api", generated.files.map((file) => artifactRef(file, file)))
27820
+ (run) => completeDeliveryNode(run, "api", apiArtifacts)
27746
27821
  );
27747
27822
  await updateDeliveryRun(
27748
27823
  workspace,
@@ -28018,6 +28093,12 @@ VITE_API_BASE_URL=${running.url}
28018
28093
  });
28019
28094
  return readD2cProductPlanView(workspace, task).then((view) => view);
28020
28095
  }
28096
+ /** Read-only snapshot of the seven-node E2E delivery run; undefined when the task never started a delivery. */
28097
+ async getE2eDeliveryRun(task) {
28098
+ const workspace = this.#workspace;
28099
+ if (workspace === void 0) return void 0;
28100
+ return readDeliveryRun(workspace, task);
28101
+ }
28021
28102
  async #assertProductPrdLocked(workspace, task) {
28022
28103
  const current = await readD2cProductPlanView(workspace, task);
28023
28104
  if (current?.plan.approvedPrd === void 0) return;
@@ -28742,6 +28823,9 @@ function installIpcHandlers() {
28742
28823
  const input = D2cQualityIssueDecisionInputSchema.parse(value);
28743
28824
  return controller.resolveD2cQualityIssue(input.task, input.issueId, input.decision);
28744
28825
  });
28826
+ ipcMain.handle(DESKTOP_CHANNELS.e2eGetDeliveryRun, async (_event, value) => {
28827
+ return controller.getE2eDeliveryRun(D2cTaskActionInputSchema.parse(value).task);
28828
+ });
28745
28829
  }
28746
28830
  function applicationMenu() {
28747
28831
  return Menu.buildFromTemplate([
@@ -65,6 +65,7 @@ var DESKTOP_CHANNELS = {
65
65
  d2cRunQualityJudge: "desktop:d2c-run-quality-judge",
66
66
  d2cResolveQualityIssue: "desktop:d2c-resolve-quality-issue",
67
67
  d2cSetManualAcceptance: "desktop:d2c-set-manual-acceptance",
68
+ e2eGetDeliveryRun: "desktop:e2e-get-delivery-run",
68
69
  event: "desktop:event"
69
70
  };
70
71
 
@@ -158,6 +159,7 @@ var api = {
158
159
  saveD2cJudgeConfig: (input) => import_electron.ipcRenderer.invoke(DESKTOP_CHANNELS.d2cSaveJudgeConfig, input),
159
160
  runD2cQualityJudge: (task) => import_electron.ipcRenderer.invoke(DESKTOP_CHANNELS.d2cRunQualityJudge, { task }),
160
161
  resolveD2cQualityIssue: (task, issueId, decision) => import_electron.ipcRenderer.invoke(DESKTOP_CHANNELS.d2cResolveQualityIssue, { task, issueId, decision }),
162
+ getE2eDeliveryRun: (task) => import_electron.ipcRenderer.invoke(DESKTOP_CHANNELS.e2eGetDeliveryRun, { task }),
161
163
  onEvent(listener) {
162
164
  const handler = (_event, value) => listener(value);
163
165
  import_electron.ipcRenderer.on(DESKTOP_CHANNELS.event, handler);