flavor-code 1.3.6 → 1.3.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.
@@ -1,8 +1,8 @@
1
1
  // src/desktop/main.ts
2
2
  import { appendFileSync } from "fs";
3
- import { createHash as createHash27, randomUUID as randomUUID28 } from "crypto";
3
+ import { createHash as createHash28, randomUUID as randomUUID29 } from "crypto";
4
4
  import { readFile as readFile39, stat as stat18, writeFile as writeFile19 } from "fs/promises";
5
- import { basename as basename11, dirname as dirname24, join as join46, resolve as resolve40 } from "path";
5
+ import { basename as basename11, dirname as dirname24, join as join47, resolve as resolve40 } from "path";
6
6
  import { fileURLToPath as fileURLToPath4 } from "url";
7
7
  import { app, BrowserWindow as BrowserWindow2, clipboard, dialog, ipcMain, Menu, nativeImage, Notification, shell } from "electron";
8
8
 
@@ -4218,9 +4218,9 @@ ${summarizeReport(report2)}`).join("\n\n")
4218
4218
 
4219
4219
  // src/production.ts
4220
4220
  import { readFile as readFile27 } from "fs/promises";
4221
- import { createHash as createHash20, randomUUID as randomUUID24 } from "crypto";
4222
- import { homedir as homedir2, release as osRelease, tmpdir as tmpdir3, version as osVersion } from "os";
4223
- import { basename as basename8, join as join31, relative as relative23, resolve as resolve32, sep as sep23 } from "path";
4221
+ import { createHash as createHash21, randomUUID as randomUUID25 } from "crypto";
4222
+ import { homedir as homedir2, release as osRelease, tmpdir as tmpdir4, version as osVersion } from "os";
4223
+ import { basename as basename8, join as join32, relative as relative23, resolve as resolve32, sep as sep23 } from "path";
4224
4224
 
4225
4225
  // src/agent/subagents.ts
4226
4226
  import { z as z10 } from "zod";
@@ -6568,6 +6568,7 @@ var AgentLoop = class {
6568
6568
  attempt,
6569
6569
  messages: modelRequest.messages
6570
6570
  });
6571
+ const modelStartedAt = Date.now();
6571
6572
  yield { type: "model-start", id: modelCallId };
6572
6573
  try {
6573
6574
  for await (const event of adapter.stream(modelRequest)) {
@@ -6626,6 +6627,13 @@ var AgentLoop = class {
6626
6627
  completed,
6627
6628
  agent: this.#options.agent,
6628
6629
  providerError,
6630
+ durationMs: Math.max(0, Date.now() - modelStartedAt),
6631
+ ...usage === void 0 ? {} : {
6632
+ inputTokens: usage.inputTokens,
6633
+ outputTokens: usage.outputTokens,
6634
+ ...usage.cacheReadTokens === void 0 ? {} : { cacheReadTokens: usage.cacheReadTokens },
6635
+ ...usage.cacheCreationTokens === void 0 ? {} : { cacheCreationTokens: usage.cacheCreationTokens }
6636
+ },
6629
6637
  ...terminalError === void 0 ? {} : {
6630
6638
  errorCode: terminalError.code,
6631
6639
  errorMessage: terminalError.message
@@ -8834,19 +8842,155 @@ function createIncidentReporter(options) {
8834
8842
  };
8835
8843
  }
8836
8844
 
8845
+ // src/island/control-server.ts
8846
+ import { createHash as createHash7, randomUUID as randomUUID10 } from "crypto";
8847
+ import { chmod, unlink as unlink2 } from "fs/promises";
8848
+ import { tmpdir } from "os";
8849
+ import { join as join9 } from "path";
8850
+ import { createServer as createServer2 } from "net";
8851
+ var MAX_REQUEST_BYTES = 64 * 1024;
8852
+ var SOCKET_TIMEOUT_MS = 1e4;
8853
+ function islandControlEndpoint(sessionId, platform = process.platform) {
8854
+ const digest = createHash7("sha256").update(`${process.pid}\0${sessionId}`).digest("hex").slice(0, 20);
8855
+ if (platform === "win32") return `\\\\.\\pipe\\flavor-island-control-${digest}`;
8856
+ const uid = typeof process.getuid === "function" ? process.getuid() : 0;
8857
+ return join9(tmpdir(), `flavor-island-control-${uid}-${digest}.sock`);
8858
+ }
8859
+ async function createIslandControlServer(options) {
8860
+ const platform = options.platform ?? process.platform;
8861
+ const endpoint2 = options.endpoint ?? islandControlEndpoint(options.sessionId, platform);
8862
+ const token = options.token ?? randomUUID10();
8863
+ const capabilities = [
8864
+ "abort",
8865
+ "steer",
8866
+ "follow_up",
8867
+ ...options.focus === void 0 ? [] : ["focus"]
8868
+ ];
8869
+ if (platform !== "win32") await unlink2(endpoint2).catch(() => void 0);
8870
+ const sockets = /* @__PURE__ */ new Set();
8871
+ const server = createServer2((socket) => {
8872
+ sockets.add(socket);
8873
+ socket.setTimeout(SOCKET_TIMEOUT_MS, () => socket.destroy());
8874
+ socket.on("close", () => sockets.delete(socket));
8875
+ socket.on("error", () => void 0);
8876
+ let buffer = Buffer.alloc(0);
8877
+ let handled = false;
8878
+ socket.on("data", (chunk) => {
8879
+ if (handled) return;
8880
+ const bytes = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
8881
+ if (buffer.length + bytes.length > MAX_REQUEST_BYTES) {
8882
+ handled = true;
8883
+ write(socket, { ok: false, error: "request_too_large" });
8884
+ return;
8885
+ }
8886
+ buffer = Buffer.concat([buffer, bytes]);
8887
+ const newline = buffer.indexOf(10);
8888
+ if (newline < 0) return;
8889
+ handled = true;
8890
+ const line = buffer.subarray(0, newline).toString("utf8");
8891
+ void dispatch(line, socket, options, token);
8892
+ });
8893
+ });
8894
+ await new Promise((resolve41, reject) => {
8895
+ const onError = (error) => {
8896
+ server.removeListener("listening", onListening);
8897
+ reject(error);
8898
+ };
8899
+ const onListening = () => {
8900
+ server.removeListener("error", onError);
8901
+ resolve41();
8902
+ };
8903
+ server.once("error", onError);
8904
+ server.once("listening", onListening);
8905
+ server.listen(endpoint2);
8906
+ });
8907
+ if (platform !== "win32") await chmod(endpoint2, 384).catch(() => void 0);
8908
+ let closed = false;
8909
+ return {
8910
+ endpoint: endpoint2,
8911
+ token,
8912
+ capabilities,
8913
+ async close() {
8914
+ if (closed) return;
8915
+ closed = true;
8916
+ for (const socket of sockets) socket.destroy();
8917
+ await closeServer(server);
8918
+ if (platform !== "win32") await unlink2(endpoint2).catch(() => void 0);
8919
+ }
8920
+ };
8921
+ }
8922
+ async function dispatch(line, socket, options, token) {
8923
+ let request;
8924
+ try {
8925
+ const parsed = JSON.parse(line);
8926
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new Error("invalid request");
8927
+ request = parsed;
8928
+ } catch {
8929
+ write(socket, { ok: false, error: "invalid_json" });
8930
+ return;
8931
+ }
8932
+ if (request.token !== token) {
8933
+ write(socket, { ok: false, error: "unauthorized" });
8934
+ return;
8935
+ }
8936
+ const command = request.command;
8937
+ try {
8938
+ if (command === "abort") {
8939
+ write(socket, { ok: true, result: options.session.interrupt() });
8940
+ } else if (command === "steer" || command === "follow_up") {
8941
+ const message2 = typeof request.message === "string" ? request.message.trim() : "";
8942
+ if (!message2 || message2.length > 1e5) {
8943
+ write(socket, { ok: false, error: "invalid_message" });
8944
+ return;
8945
+ }
8946
+ if (command === "steer") options.session.steer(message2);
8947
+ else options.session.followUp(message2);
8948
+ write(socket, { ok: true });
8949
+ } else if (command === "focus") {
8950
+ if (options.focus === void 0) {
8951
+ write(socket, { ok: false, error: "focus_unavailable" });
8952
+ return;
8953
+ }
8954
+ await options.focus();
8955
+ write(socket, { ok: true });
8956
+ } else {
8957
+ write(socket, { ok: false, error: "unknown_command" });
8958
+ }
8959
+ } catch (error) {
8960
+ write(socket, { ok: false, error: error instanceof Error ? error.message : String(error) });
8961
+ }
8962
+ }
8963
+ function write(socket, payload) {
8964
+ try {
8965
+ socket.end(`${JSON.stringify(payload)}
8966
+ `);
8967
+ } catch {
8968
+ socket.destroy();
8969
+ }
8970
+ }
8971
+ function closeServer(server) {
8972
+ return new Promise((resolve41) => {
8973
+ try {
8974
+ server.close(() => resolve41());
8975
+ } catch {
8976
+ resolve41();
8977
+ }
8978
+ });
8979
+ }
8980
+
8837
8981
  // src/evolve/service.ts
8838
8982
  import { spawn as spawn2 } from "child_process";
8839
8983
  import { writeFile as writeFile7 } from "fs/promises";
8840
- import { join as join11 } from "path";
8984
+ import { join as join12 } from "path";
8841
8985
  import { z as z19 } from "zod";
8842
8986
 
8843
8987
  // src/evolve/loader.ts
8844
8988
  import { cp as cp2, mkdir as mkdir7, mkdtemp, readdir as readdir3, rm as rm4, stat as stat5, writeFile as writeFile5 } from "fs/promises";
8845
- import { tmpdir } from "os";
8846
- import { join as join9, resolve as resolve10 } from "path";
8989
+ import { tmpdir as tmpdir2 } from "os";
8990
+ import { join as join10, resolve as resolve10 } from "path";
8847
8991
 
8848
8992
  // src/plugins/host.ts
8849
- import { createHash as createHash7 } from "crypto";
8993
+ import { createHash as createHash8 } from "crypto";
8850
8994
  import { lstatSync, realpathSync as realpathSync3 } from "fs";
8851
8995
  import { lstat as lstat3, open as open4, readFile as readFile7, readdir as readdir2, realpath as realpath6, stat as stat4, writeFile as writeFile4 } from "fs/promises";
8852
8996
  import { isAbsolute as isAbsolute6, relative as relative7, resolve as resolve9, sep as sep7 } from "path";
@@ -9207,7 +9351,7 @@ var PluginHost = class {
9207
9351
  const manifest = PluginManifestSchema.parse(rawManifest);
9208
9352
  const entry2 = resolveContained(root, manifest.main, "Plugin entry");
9209
9353
  const entrySnapshot = await snapshotEntry(root, entry2);
9210
- const fingerprint2 = createHash7("sha256").update(JSON.stringify(manifest)).update(await readFile7(entrySnapshot.physicalPath)).digest("hex");
9354
+ const fingerprint2 = createHash8("sha256").update(JSON.stringify(manifest)).update(await readFile7(entrySnapshot.physicalPath)).digest("hex");
9211
9355
  return { manifest, root, source, entry: entry2, entrySnapshot, fingerprint: fingerprint2 };
9212
9356
  } catch (error) {
9213
9357
  this.#diagnose(diagnosticLabel, error, inputRoot);
@@ -9566,8 +9710,8 @@ function compare(left, right) {
9566
9710
  }
9567
9711
 
9568
9712
  // src/evolve/loader.ts
9569
- var PLUGIN_DIR = join9(".flavor", "plugins");
9570
- var VERSIONS_DIR = join9(".flavor", "plugins", ".versions");
9713
+ var PLUGIN_DIR = join10(".flavor", "plugins");
9714
+ var VERSIONS_DIR = join10(".flavor", "plugins", ".versions");
9571
9715
  function sanitizePluginName(tool) {
9572
9716
  const base = String(tool ?? "fix").replace(/[^a-z0-9-]/gi, "-").toLowerCase();
9573
9717
  return base.startsWith("fix-") ? base : `fix-${base}`;
@@ -9611,8 +9755,8 @@ export function activate(ctx) {
9611
9755
  async function scaffoldFixPlugin(workspace, name) {
9612
9756
  const dir = fixPluginDir(workspace, name);
9613
9757
  await mkdir7(dir, { recursive: true });
9614
- const manifestPath = join9(dir, "flavor-plugin.json");
9615
- const entryPath = join9(dir, "index.js");
9758
+ const manifestPath = join10(dir, "flavor-plugin.json");
9759
+ const entryPath = join10(dir, "index.js");
9616
9760
  try {
9617
9761
  await writeFile5(manifestPath, SCAFFOLD_MANIFEST(name), { encoding: "utf8", flag: "wx" });
9618
9762
  await writeFile5(entryPath, SCAFFOLD_ENTRY(name), { encoding: "utf8", flag: "wx" });
@@ -9632,9 +9776,9 @@ async function verifyFixPlugin(workspace, name) {
9632
9776
  return { ok: false, provided: [], tools: [], commands: [], error: `Plugin "${name}" not found.` };
9633
9777
  }
9634
9778
  const collected = { tools: [], commands: [] };
9635
- const sandbox = await mkdtemp(join9(tmpdir(), "flavor-evolve-verify-"));
9779
+ const sandbox = await mkdtemp(join10(tmpdir2(), "flavor-evolve-verify-"));
9636
9780
  try {
9637
- await cp2(pluginRoot, join9(sandbox, name), { recursive: true });
9781
+ await cp2(pluginRoot, join10(sandbox, name), { recursive: true });
9638
9782
  const host = new PluginHost({
9639
9783
  projectPluginDirs: [sandbox],
9640
9784
  sandbox: true,
@@ -9685,7 +9829,7 @@ async function verifyFixPlugin(workspace, name) {
9685
9829
  }
9686
9830
  async function snapshotFixPlugin(workspace, name) {
9687
9831
  const pluginRoot = fixPluginDir(workspace, name);
9688
- const snapshotRoot = join9(versionsDirFor(workspace, name), timestamp());
9832
+ const snapshotRoot = join10(versionsDirFor(workspace, name), timestamp());
9689
9833
  await mkdir7(snapshotRoot, { recursive: true });
9690
9834
  await cp2(pluginRoot, snapshotRoot, { recursive: true });
9691
9835
  return snapshotRoot;
@@ -9706,7 +9850,7 @@ async function revertFixPlugin(workspace, name) {
9706
9850
  }
9707
9851
  const snapshots = entries.filter((entry2) => !entry2.startsWith(".")).sort();
9708
9852
  if (snapshots.length === 0) throw new Error(`Plugin "${name}" has no snapshot to restore.`);
9709
- const latest = join9(versionsRoot, snapshots[snapshots.length - 1]);
9853
+ const latest = join10(versionsRoot, snapshots[snapshots.length - 1]);
9710
9854
  await rm4(pluginRoot, { recursive: true, force: true });
9711
9855
  await mkdir7(pluginRoot, { recursive: true });
9712
9856
  await cp2(latest, pluginRoot, { recursive: true });
@@ -9714,14 +9858,14 @@ async function revertFixPlugin(workspace, name) {
9714
9858
  }
9715
9859
 
9716
9860
  // src/evolve/store.ts
9717
- import { createHash as createHash8 } from "crypto";
9861
+ import { createHash as createHash9 } from "crypto";
9718
9862
  import { appendFile, mkdir as mkdir8, readFile as readFile8, rm as rm5, writeFile as writeFile6 } from "fs/promises";
9719
- import { dirname as dirname8, join as join10 } from "path";
9863
+ import { dirname as dirname8, join as join11 } from "path";
9720
9864
  function normalizeError(message2) {
9721
9865
  return String(message2 ?? "").replace(/\s+/g, " ").replace(/"[^"]*"/g, '"\u2026"').replace(/`[^`]*`/g, '"\u2026"').trim().slice(0, 160);
9722
9866
  }
9723
9867
  function fingerprint(tool, errorCode, error) {
9724
- return createHash8("sha1").update(`${tool}::${errorCode ?? ""}::${normalizeError(error)}`).digest("hex").slice(0, 12);
9868
+ return createHash9("sha1").update(`${tool}::${errorCode ?? ""}::${normalizeError(error)}`).digest("hex").slice(0, 12);
9725
9869
  }
9726
9870
  function argKeys(args) {
9727
9871
  if (args === null || typeof args !== "object") return [];
@@ -9789,12 +9933,12 @@ var EvolveStore = class {
9789
9933
  #queue = Promise.resolve();
9790
9934
  constructor(options) {
9791
9935
  const { workspace, maxSignals = 400, maxRules = 20 } = options;
9792
- this.dir = join10(workspace, ".flavor", "evolve");
9793
- this.signalsFile = join10(this.dir, "signals.jsonl");
9794
- this.reflectionsFile = join10(this.dir, "reflections.jsonl");
9795
- this.doneFile = join10(this.dir, "done.json");
9796
- this.verifiedFile = join10(this.dir, "verified.json");
9797
- this.rulesFile = join10(this.dir, "rules.json");
9936
+ this.dir = join11(workspace, ".flavor", "evolve");
9937
+ this.signalsFile = join11(this.dir, "signals.jsonl");
9938
+ this.reflectionsFile = join11(this.dir, "reflections.jsonl");
9939
+ this.doneFile = join11(this.dir, "done.json");
9940
+ this.verifiedFile = join11(this.dir, "verified.json");
9941
+ this.rulesFile = join11(this.dir, "rules.json");
9798
9942
  this.maxSignals = maxSignals;
9799
9943
  this.maxRules = maxRules;
9800
9944
  }
@@ -10333,7 +10477,7 @@ function createEvolveService(options) {
10333
10477
  if (suggestion === void 0) return `No open suggestion with id "${suggestionId}". Use /evolve suggest to list them.`;
10334
10478
  const name = sanitizePluginName(suggestion.tool);
10335
10479
  const dir = await scaffoldFixPlugin(workspace, name);
10336
- await writeFile7(join11(dir, "PLAN.md"), buildPlan(suggestion, name, "See the repeated failure below; describe your fix in PLAN.md."), "utf8");
10480
+ await writeFile7(join12(dir, "PLAN.md"), buildPlan(suggestion, name, "See the repeated failure below; describe your fix in PLAN.md."), "utf8");
10337
10481
  await snapshotFixPlugin(workspace, name);
10338
10482
  return [
10339
10483
  `suggestion ${suggestion.id}: ${suggestion.tool} x${suggestion.count} \u2014 ${suggestion.error}`,
@@ -10424,7 +10568,7 @@ ${result.stderr.slice(-4e3)}` : ""}`;
10424
10568
  }
10425
10569
  const name = sanitizePluginName(suggestion.tool);
10426
10570
  const dir = await scaffoldFixPlugin(workspace, name);
10427
- await writeFile7(join11(dir, "PLAN.md"), buildPlan(suggestion, name, implementation), "utf8");
10571
+ await writeFile7(join12(dir, "PLAN.md"), buildPlan(suggestion, name, implementation), "utf8");
10428
10572
  await snapshotFixPlugin(workspace, name);
10429
10573
  return [
10430
10574
  `Scaffolded fix plugin at ${dir} for suggestion [${suggestion.id}] (${suggestion.tool} x${suggestion.count}).`,
@@ -10449,7 +10593,7 @@ ${result.stderr.slice(-4e3)}` : ""}`;
10449
10593
  // src/init/project.ts
10450
10594
  import { lstat as lstat4, mkdir as mkdir9, readdir as readdir4, readFile as readFile9, realpath as realpath7, writeFile as writeFile8 } from "fs/promises";
10451
10595
  import { copyFileSync, mkdirSync as mkdirSync2, readdirSync } from "fs";
10452
- import { basename as basename4, dirname as dirname9, isAbsolute as isAbsolute7, join as join12, relative as relative8, sep as sep8 } from "path";
10596
+ import { basename as basename4, dirname as dirname9, isAbsolute as isAbsolute7, join as join13, relative as relative8, sep as sep8 } from "path";
10453
10597
  import { fileURLToPath } from "url";
10454
10598
  var GENERATED_START = "<!-- flavor-code:start -->";
10455
10599
  var GENERATED_END = "<!-- flavor-code:end -->";
@@ -10571,7 +10715,7 @@ async function sampleSourceExtensions(cwd, root, directories) {
10571
10715
  const extensions = /* @__PURE__ */ new Set();
10572
10716
  const sampleDirectories = ["", ...directories].slice(0, 12);
10573
10717
  for (const relativeDirectory of sampleDirectories) {
10574
- const absoluteDirectory = join12(cwd, relativeDirectory);
10718
+ const absoluteDirectory = join13(cwd, relativeDirectory);
10575
10719
  if (!isContainedPath(root, await realpath7(absoluteDirectory))) continue;
10576
10720
  let entries;
10577
10721
  try {
@@ -10592,15 +10736,15 @@ async function inspectProject(cwd) {
10592
10736
  const root = await realpath7(cwd);
10593
10737
  const sourceDirectories = [];
10594
10738
  for (const directory of SOURCE_DIRECTORIES) {
10595
- if (await pathKind(join12(cwd, directory), root) === "directory") sourceDirectories.push(directory);
10739
+ if (await pathKind(join13(cwd, directory), root) === "directory") sourceDirectories.push(directory);
10596
10740
  }
10597
10741
  const instructionFiles = [];
10598
10742
  for (const file of INSTRUCTION_FILES) {
10599
- if (await pathKind(join12(cwd, file), root) === "file") instructionFiles.push(file);
10743
+ if (await pathKind(join13(cwd, file), root) === "file") instructionFiles.push(file);
10600
10744
  }
10601
10745
  const configFiles = [];
10602
10746
  for (const file of CONFIG_FILES) {
10603
- if (await pathKind(join12(cwd, file), root) === "file") configFiles.push(file);
10747
+ if (await pathKind(join13(cwd, file), root) === "file") configFiles.push(file);
10604
10748
  }
10605
10749
  const manifestNames = [
10606
10750
  "package.json",
@@ -10613,7 +10757,7 @@ async function inspectProject(cwd) {
10613
10757
  ];
10614
10758
  const present = /* @__PURE__ */ new Set();
10615
10759
  for (const manifest of manifestNames) {
10616
- if (await pathKind(join12(cwd, manifest), root) === "file") present.add(manifest);
10760
+ if (await pathKind(join13(cwd, manifest), root) === "file") present.add(manifest);
10617
10761
  }
10618
10762
  const detectedLockfiles = JAVASCRIPT_LOCKFILES.filter(({ name }) => present.has(name));
10619
10763
  const detectedJsManagers = [
@@ -10639,7 +10783,7 @@ async function inspectProject(cwd) {
10639
10783
  let projectName = sanitizeProjectName(basename4(cwd)) ?? "project";
10640
10784
  let declaredJsManager;
10641
10785
  if (present.has("package.json")) {
10642
- const text = await readTextIfSmall(join12(cwd, "package.json"), root);
10786
+ const text = await readTextIfSmall(join13(cwd, "package.json"), root);
10643
10787
  if (text === void 0) {
10644
10788
  cautions.push("package.json was too large to inspect; its scripts were ignored.");
10645
10789
  } else {
@@ -10693,8 +10837,8 @@ async function inspectProject(cwd) {
10693
10837
  addScriptCommand(testCommands, scripts, jsManager, ["test"]);
10694
10838
  addScriptCommand(lintCommands, scripts, jsManager, ["lint"]);
10695
10839
  addScriptCommand(formatCommands, scripts, jsManager, ["format", "format:check"]);
10696
- const pyproject = present.has("pyproject.toml") ? await readTextIfSmall(join12(cwd, "pyproject.toml"), root) : void 0;
10697
- const requirements = present.has("requirements.txt") ? await readTextIfSmall(join12(cwd, "requirements.txt"), root) : void 0;
10840
+ const pyproject = present.has("pyproject.toml") ? await readTextIfSmall(join13(cwd, "pyproject.toml"), root) : void 0;
10841
+ const requirements = present.has("requirements.txt") ? await readTextIfSmall(join13(cwd, "requirements.txt"), root) : void 0;
10698
10842
  const pythonTools = detectPythonTools(pyproject, requirements, configFiles);
10699
10843
  const pythonManager = pythonManagers[0];
10700
10844
  const pythonPrefix = pythonManager === "uv" ? "uv run " : pythonManager === "poetry" ? "poetry run " : pythonManager === "pipenv" ? "pipenv run " : "";
@@ -10712,8 +10856,8 @@ async function inspectProject(cwd) {
10712
10856
  if (present.has("pyproject.toml") || present.has("requirements.txt") || extensions.has("py")) {
10713
10857
  languages.add("Python");
10714
10858
  }
10715
- const gitignorePath = await pathKind(join12(cwd, ".gitignore"), root) === "file" ? ".gitignore" : void 0;
10716
- const hasCodeGraph = await pathKind(join12(cwd, ".flavor", "astgraph", "index.db"), root) === "file";
10859
+ const gitignorePath = await pathKind(join13(cwd, ".gitignore"), root) === "file" ? ".gitignore" : void 0;
10860
+ const hasCodeGraph = await pathKind(join13(cwd, ".flavor", "astgraph", "index.db"), root) === "file";
10717
10861
  return {
10718
10862
  cwd,
10719
10863
  projectName,
@@ -10822,7 +10966,7 @@ function isEntryIgnored(lines, entry2) {
10822
10966
  });
10823
10967
  }
10824
10968
  async function addSessionsToGitignore(cwd) {
10825
- const path = join12(cwd, ".gitignore");
10969
+ const path = join13(cwd, ".gitignore");
10826
10970
  const root = await realpath7(cwd);
10827
10971
  await assertSafeManagedPath(path, root);
10828
10972
  let existing;
@@ -10856,9 +11000,9 @@ async function assertSafeManagedPath(path, root) {
10856
11000
  }
10857
11001
  async function ensureFlavorDirectories(cwd) {
10858
11002
  const root = await realpath7(cwd);
10859
- const sessionsDir = join12(cwd, ".flavor", "sessions");
10860
- const skillsDir = join12(cwd, ".flavor", "skills");
10861
- const pluginsDir = join12(cwd, ".flavor", "plugins");
11003
+ const sessionsDir = join13(cwd, ".flavor", "sessions");
11004
+ const skillsDir = join13(cwd, ".flavor", "skills");
11005
+ const pluginsDir = join13(cwd, ".flavor", "plugins");
10862
11006
  await mkdir9(sessionsDir, { recursive: true, mode: 448 });
10863
11007
  await mkdir9(skillsDir, { recursive: true, mode: 448 });
10864
11008
  await mkdir9(pluginsDir, { recursive: true, mode: 448 });
@@ -10871,7 +11015,7 @@ async function ensureFlavorDirectories(cwd) {
10871
11015
  }
10872
11016
  }
10873
11017
  async function createExampleFlavorConfig(cwd) {
10874
- const configPath = join12(cwd, ".flavor", "flavor.json");
11018
+ const configPath = join13(cwd, ".flavor", "flavor.json");
10875
11019
  const root = await realpath7(cwd);
10876
11020
  await assertSafeManagedPath(configPath, root);
10877
11021
  try {
@@ -10901,9 +11045,9 @@ async function createExampleFlavorConfig(cwd) {
10901
11045
  };
10902
11046
  await writeFile8(configPath, JSON.stringify(example, null, 2) + "\n");
10903
11047
  }
10904
- var ASTGRAPH_SRC_DIR = join12(dirname9(fileURLToPath(import.meta.url)), "astgraph");
11048
+ var ASTGRAPH_SRC_DIR = join13(dirname9(fileURLToPath(import.meta.url)), "astgraph");
10905
11049
  async function copyAstgraphPlugin(cwd) {
10906
- const pluginDir = join12(cwd, ".flavor", "plugins", "astgraph");
11050
+ const pluginDir = join13(cwd, ".flavor", "plugins", "astgraph");
10907
11051
  try {
10908
11052
  await lstat4(pluginDir);
10909
11053
  return;
@@ -10915,8 +11059,8 @@ async function copyAstgraphPlugin(cwd) {
10915
11059
  function copyDirectory(from, to) {
10916
11060
  mkdirSync2(to, { recursive: true, mode: 448 });
10917
11061
  for (const entry2 of readdirSync(from, { withFileTypes: true })) {
10918
- const source = join12(from, entry2.name);
10919
- const target = join12(to, entry2.name);
11062
+ const source = join13(from, entry2.name);
11063
+ const target = join13(to, entry2.name);
10920
11064
  if (entry2.isDirectory()) copyDirectory(source, target);
10921
11065
  else if (entry2.isFile()) copyFileSync(source, target);
10922
11066
  }
@@ -10926,7 +11070,7 @@ async function initializeFlavor(cwd) {
10926
11070
  await copyAstgraphPlugin(cwd);
10927
11071
  await createExampleFlavorConfig(cwd);
10928
11072
  const facts = await inspectProject(cwd);
10929
- const path = join12(cwd, "FLAVOR.md");
11073
+ const path = join13(cwd, "FLAVOR.md");
10930
11074
  const root = await realpath7(cwd);
10931
11075
  await assertSafeManagedPath(path, root);
10932
11076
  let existing;
@@ -11342,9 +11486,9 @@ ${evidence.summary}`;
11342
11486
  };
11343
11487
 
11344
11488
  // src/goal/orchestrator.ts
11345
- import { createHash as createHash10 } from "crypto";
11489
+ import { createHash as createHash11 } from "crypto";
11346
11490
  import { writeFile as writeFile9, mkdir as mkdir10 } from "fs/promises";
11347
- import { join as join14 } from "path";
11491
+ import { join as join15 } from "path";
11348
11492
 
11349
11493
  // src/goal/types.ts
11350
11494
  import { z as z21 } from "zod";
@@ -11507,9 +11651,9 @@ function extractJson(text) {
11507
11651
  }
11508
11652
 
11509
11653
  // src/goal/classifier.ts
11510
- import { createHash as createHash9 } from "crypto";
11654
+ import { createHash as createHash10 } from "crypto";
11511
11655
  import { readFile as readFile10 } from "fs/promises";
11512
- import { join as join13 } from "path";
11656
+ import { join as join14 } from "path";
11513
11657
  function buildSkepticPrompt(evidence, plan, index) {
11514
11658
  const criteriaList = plan.criteria.map((c) => ` ${c.id}. [${c.type}] ${c.description}`).join("\n");
11515
11659
  return [
@@ -11682,11 +11826,11 @@ function deduplicateGaps(gaps) {
11682
11826
  }
11683
11827
  function computeFingerprint(gaps) {
11684
11828
  const content = gaps.map((g) => `${g.criterion}:${g.description}`).sort().join("\n");
11685
- return createHash9("sha256").update(content).digest("hex").slice(0, 16);
11829
+ return createHash10("sha256").update(content).digest("hex").slice(0, 16);
11686
11830
  }
11687
- async function collectEvidence(workspace, objective, finalResponse, priorGaps, contractHash2 = createHash9("sha256").update(objective).digest("hex"), hostVerification) {
11831
+ async function collectEvidence(workspace, objective, finalResponse, priorGaps, contractHash2 = createHash10("sha256").update(objective).digest("hex"), hostVerification) {
11688
11832
  const workspaceState = await collectWorkspaceState(workspace);
11689
- const planPath2 = join13(workspace, ".flavor", "goal-plan.md");
11833
+ const planPath2 = join14(workspace, ".flavor", "goal-plan.md");
11690
11834
  let planFile = null;
11691
11835
  try {
11692
11836
  planFile = await readFile10(planPath2, "utf8");
@@ -11713,7 +11857,7 @@ async function collectWorkspaceState(workspace) {
11713
11857
  return {
11714
11858
  changedFiles: [],
11715
11859
  status: ["not-a-git-worktree"],
11716
- diffHash: createHash9("sha256").update("not-a-git-worktree").digest("hex")
11860
+ diffHash: createHash10("sha256").update("not-a-git-worktree").digest("hex")
11717
11861
  };
11718
11862
  }
11719
11863
  const status = statusResult.stdout.split(/\r?\n/).map((line) => line.trimEnd()).filter(Boolean);
@@ -11730,7 +11874,7 @@ async function collectWorkspaceState(workspace) {
11730
11874
  return {
11731
11875
  changedFiles,
11732
11876
  status,
11733
- diffHash: createHash9("sha256").update(diff.stdout).update("\nUNTRACKED\n").update(untracked).digest("hex")
11877
+ diffHash: createHash10("sha256").update(diff.stdout).update("\nUNTRACKED\n").update(untracked).digest("hex")
11734
11878
  };
11735
11879
  }
11736
11880
 
@@ -11862,7 +12006,7 @@ var GoalOrchestrator = class {
11862
12006
  type: "not_achieved",
11863
12007
  gaps,
11864
12008
  summary: hostVerification.summary,
11865
- fingerprint: createHash10("sha256").update(hostVerification.summary).digest("hex").slice(0, 16)
12009
+ fingerprint: createHash11("sha256").update(hostVerification.summary).digest("hex").slice(0, 16)
11866
12010
  };
11867
12011
  }
11868
12012
  } else try {
@@ -11936,11 +12080,11 @@ var GoalOrchestrator = class {
11936
12080
  }
11937
12081
  };
11938
12082
  function contractHash(objective, plan) {
11939
- return createHash10("sha256").update(JSON.stringify({ objective, plan })).digest("hex");
12083
+ return createHash11("sha256").update(JSON.stringify({ objective, plan })).digest("hex");
11940
12084
  }
11941
12085
  async function writePlanFile(workspace, plan) {
11942
- const dir = join14(workspace, ".flavor");
11943
- const planPath2 = join14(dir, "goal-plan.md");
12086
+ const dir = join15(workspace, ".flavor");
12087
+ const planPath2 = join15(dir, "goal-plan.md");
11944
12088
  await mkdir10(dir, { recursive: true });
11945
12089
  const criteriaText = plan.criteria.map((c) => `- [${c.type}] AC-${c.id}: ${c.description}`).join("\n");
11946
12090
  const content = [
@@ -12016,9 +12160,9 @@ function formatPriorGaps(gaps) {
12016
12160
 
12017
12161
  // src/goal/store.ts
12018
12162
  import { constants as constants3 } from "fs";
12019
- import { randomUUID as randomUUID10 } from "crypto";
12163
+ import { randomUUID as randomUUID11 } from "crypto";
12020
12164
  import { lstat as lstat5, mkdir as mkdir11, open as open5, rename as rename4, rm as rm6 } from "fs/promises";
12021
- import { dirname as dirname10, join as join15, relative as relative9, resolve as resolve11, sep as sep9 } from "path";
12165
+ import { dirname as dirname10, join as join16, relative as relative9, resolve as resolve11, sep as sep9 } from "path";
12022
12166
  var DEFAULT_MAX_BYTES = 1024 * 1024;
12023
12167
  var GoalStore = class {
12024
12168
  #workspace;
@@ -12026,7 +12170,7 @@ var GoalStore = class {
12026
12170
  #maxBytes;
12027
12171
  constructor(options) {
12028
12172
  this.#workspace = resolve11(options.workspace);
12029
- this.#root = join15(this.#workspace, ".flavor", "goals");
12173
+ this.#root = join16(this.#workspace, ".flavor", "goals");
12030
12174
  this.#maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
12031
12175
  }
12032
12176
  async save(input) {
@@ -12034,13 +12178,13 @@ var GoalStore = class {
12034
12178
  await assertNoSymlink(this.#workspace, dirname10(this.#root));
12035
12179
  await mkdir11(this.#root, { recursive: true, mode: 448 });
12036
12180
  await assertNoSymlink(this.#workspace, this.#root);
12037
- const target = join15(this.#root, `${state.id}.json`);
12181
+ const target = join16(this.#root, `${state.id}.json`);
12038
12182
  const body = `${JSON.stringify(state, null, 2)}
12039
12183
  `;
12040
12184
  if (Buffer.byteLength(body) > this.#maxBytes) {
12041
12185
  throw new Error(`Goal state exceeds maximum size of ${this.#maxBytes} bytes`);
12042
12186
  }
12043
- const temporary = join15(this.#root, `.${state.id}.${process.pid}.${randomUUID10()}.tmp`);
12187
+ const temporary = join16(this.#root, `.${state.id}.${process.pid}.${randomUUID11()}.tmp`);
12044
12188
  let handle;
12045
12189
  try {
12046
12190
  handle = await open5(temporary, constants3.O_CREAT | constants3.O_EXCL | constants3.O_WRONLY, 384);
@@ -12081,7 +12225,7 @@ function isCode4(error, code) {
12081
12225
 
12082
12226
  // src/loop/isolation.ts
12083
12227
  import { appendFile as appendFile2, mkdir as mkdir12, readFile as readFile11 } from "fs/promises";
12084
- import { join as join16, resolve as resolve12 } from "path";
12228
+ import { join as join17, resolve as resolve12 } from "path";
12085
12229
  var CODE_CHANGE = /\b(?:fix|implement|add|update|change|modify|refactor|build|create|remove|delete|write|migrate)\b|修复|实现|添加|更新|修改|重构|创建|删除|迁移/i;
12086
12230
  var READ_ONLY = /\b(?:review|analy[sz]e|inspect|explain|research|investigate|audit|summari[sz]e|report)\b|调研|分析|审查|检查|解释|研究|总结|报告/i;
12087
12231
  function inferGoalIntent(goal) {
@@ -12104,8 +12248,8 @@ async function prepareLoopWorkspace(options) {
12104
12248
  return { kind: "needs_human", reason: "The workspace has uncommitted changes that a new worktree would omit." };
12105
12249
  }
12106
12250
  options.signal?.throwIfAborted();
12107
- const worktrees = join16(root, ".worktrees");
12108
- const path = join16(worktrees, `loop-${options.loopId}`);
12251
+ const worktrees = join17(root, ".worktrees");
12252
+ const path = join17(worktrees, `loop-${options.loopId}`);
12109
12253
  const branch = `loop/${options.loopId}`;
12110
12254
  try {
12111
12255
  await ensureWorktreeDirectoryIgnored(root);
@@ -12135,8 +12279,8 @@ async function ensureWorktreeDirectoryIgnored(root) {
12135
12279
  const commonDirectory = await git(root, ["rev-parse", "--git-common-dir"]);
12136
12280
  if (commonDirectory.code !== 0) throw new Error(commonDirectory.stderr.trim() || "Git common directory is unavailable");
12137
12281
  const gitDirectory = resolve12(root, commonDirectory.stdout.trim());
12138
- const infoDirectory = join16(gitDirectory, "info");
12139
- const excludePath = join16(infoDirectory, "exclude");
12282
+ const infoDirectory = join17(gitDirectory, "info");
12283
+ const excludePath = join17(infoDirectory, "exclude");
12140
12284
  await mkdir12(infoDirectory, { recursive: true });
12141
12285
  let existing = "";
12142
12286
  try {
@@ -12152,8 +12296,8 @@ async function ensureWorktreeDirectoryIgnored(root) {
12152
12296
  // src/loop/store.ts
12153
12297
  import { constants as constants4 } from "fs";
12154
12298
  import { lstat as lstat6, mkdir as mkdir13, open as open6, readFile as readFile12, realpath as realpath8, rename as rename5, rm as rm7, stat as stat6 } from "fs/promises";
12155
- import { dirname as dirname11, join as join17, relative as relative10, resolve as resolve13, sep as sep10 } from "path";
12156
- import { randomUUID as randomUUID11 } from "crypto";
12299
+ import { dirname as dirname11, join as join18, relative as relative10, resolve as resolve13, sep as sep10 } from "path";
12300
+ import { randomUUID as randomUUID12 } from "crypto";
12157
12301
  var LOOP_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
12158
12302
  var DEFAULT_MAX_BYTES2 = 5 * 1024 * 1024;
12159
12303
  var LoopStore = class {
@@ -12163,7 +12307,7 @@ var LoopStore = class {
12163
12307
  #appendTails = /* @__PURE__ */ new Map();
12164
12308
  constructor(options) {
12165
12309
  this.#workspace = resolve13(options.workspace);
12166
- this.#root = join17(this.#workspace, ".flavor", "loops");
12310
+ this.#root = join18(this.#workspace, ".flavor", "loops");
12167
12311
  this.#maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES2;
12168
12312
  }
12169
12313
  async create(state) {
@@ -12180,11 +12324,11 @@ var LoopStore = class {
12180
12324
  const state = LoopStateSchema.parse(input);
12181
12325
  await this.#assertWorkspace(state.workspace);
12182
12326
  const directory = await this.#prepare(state.loopId);
12183
- const target = join17(directory, "state.json");
12327
+ const target = join18(directory, "state.json");
12184
12328
  const body = `${JSON.stringify(state, null, 2)}
12185
12329
  `;
12186
12330
  if (Buffer.byteLength(body) > this.#maxBytes) throw new Error(`Loop state exceeds maximum size of ${this.#maxBytes} bytes`);
12187
- const temporary = join17(directory, `.state.${process.pid}.${randomUUID11()}.tmp`);
12331
+ const temporary = join18(directory, `.state.${process.pid}.${randomUUID12()}.tmp`);
12188
12332
  let handle;
12189
12333
  try {
12190
12334
  handle = await open6(temporary, constants4.O_CREAT | constants4.O_EXCL | constants4.O_WRONLY, 384);
@@ -12200,7 +12344,7 @@ var LoopStore = class {
12200
12344
  }
12201
12345
  async load(loopId) {
12202
12346
  const directory = await this.#safeExisting(loopId);
12203
- const target = join17(directory, "state.json");
12347
+ const target = join18(directory, "state.json");
12204
12348
  try {
12205
12349
  const metadata = await stat6(target);
12206
12350
  if (!metadata.isFile() || metadata.size > this.#maxBytes) throw new Error("Loop state is not a bounded regular file");
@@ -12210,7 +12354,7 @@ var LoopStore = class {
12210
12354
  return state;
12211
12355
  } catch (error) {
12212
12356
  if (isCode5(error, "ENOENT")) throw new Error(`Loop "${loopId}" was not found`);
12213
- const quarantine = `${target}.corrupt-${Date.now()}-${randomUUID11().slice(0, 8)}`;
12357
+ const quarantine = `${target}.corrupt-${Date.now()}-${randomUUID12().slice(0, 8)}`;
12214
12358
  await rename5(target, quarantine).catch(() => void 0);
12215
12359
  throw new Error(`Loop "${loopId}" is corrupt and was quarantined: ${message(error)}`);
12216
12360
  }
@@ -12220,7 +12364,7 @@ var LoopStore = class {
12220
12364
  const previous = this.#appendTails.get(event.loopId) ?? Promise.resolve();
12221
12365
  const next = previous.catch(() => void 0).then(async () => {
12222
12366
  const directory = await this.#prepare(event.loopId);
12223
- const path = join17(directory, "events.jsonl");
12367
+ const path = join18(directory, "events.jsonl");
12224
12368
  const handle = await open6(path, constants4.O_CREAT | constants4.O_APPEND | constants4.O_WRONLY, 384);
12225
12369
  try {
12226
12370
  await handle.writeFile(`${JSON.stringify(event)}
@@ -12237,7 +12381,7 @@ var LoopStore = class {
12237
12381
  await assertNoSymlink2(this.#workspace, dirname11(this.#root));
12238
12382
  await mkdir13(this.#root, { recursive: true, mode: 448 });
12239
12383
  await assertNoSymlink2(this.#workspace, this.#root);
12240
- const directory = join17(this.#root, loopId);
12384
+ const directory = join18(this.#root, loopId);
12241
12385
  await mkdir13(directory, { recursive: true, mode: 448 });
12242
12386
  await assertNoSymlink2(this.#workspace, directory);
12243
12387
  return directory;
@@ -12245,7 +12389,7 @@ var LoopStore = class {
12245
12389
  async #safeExisting(loopId) {
12246
12390
  validateId(loopId);
12247
12391
  await assertNoSymlink2(this.#workspace, this.#root);
12248
- const directory = join17(this.#root, loopId);
12392
+ const directory = join18(this.#root, loopId);
12249
12393
  await assertNoSymlink2(this.#workspace, directory);
12250
12394
  return directory;
12251
12395
  }
@@ -12294,7 +12438,7 @@ function isCode5(error, code) {
12294
12438
 
12295
12439
  // src/loop/verifier.ts
12296
12440
  import { readFile as readFile13 } from "fs/promises";
12297
- import { join as join18 } from "path";
12441
+ import { join as join19 } from "path";
12298
12442
 
12299
12443
  // src/tools/shell.ts
12300
12444
  import { spawn as spawn3, spawnSync } from "child_process";
@@ -12852,13 +12996,13 @@ var SCRIPT_PRIORITY = ["test", "typecheck", "lint", "build", "smoke:install"];
12852
12996
  async function inferVerificationPlan(workspace) {
12853
12997
  const commands = [];
12854
12998
  const seen = /* @__PURE__ */ new Set();
12855
- const packageJson = await optionalJson(join18(workspace, "package.json"));
12999
+ const packageJson = await optionalJson(join19(workspace, "package.json"));
12856
13000
  const scripts = isRecord3(packageJson?.scripts) ? packageJson.scripts : {};
12857
13001
  for (const name of SCRIPT_PRIORITY) {
12858
13002
  if (typeof scripts[name] !== "string" || isUnconditionalPassThrough(scripts[name])) continue;
12859
13003
  add(commands, seen, npmScript(name));
12860
13004
  }
12861
- const flavor = await optionalText(join18(workspace, "FLAVOR.md"));
13005
+ const flavor = await optionalText(join19(workspace, "FLAVOR.md"));
12862
13006
  if (flavor !== void 0) {
12863
13007
  for (const match of flavor.matchAll(/^- `([^`]+)`\s*$/gm)) {
12864
13008
  const parsed = parseTrustedCommand(match[1] ?? "");
@@ -12995,11 +13139,11 @@ function isEnvTruthy(value) {
12995
13139
 
12996
13140
  // src/utils/log.ts
12997
13141
  import { appendFile as appendFile3, mkdir as mkdir14 } from "fs/promises";
12998
- import { dirname as dirname12, join as join19, resolve as resolve15 } from "path";
13142
+ import { dirname as dirname12, join as join20, resolve as resolve15 } from "path";
12999
13143
  var pending = Promise.resolve();
13000
13144
  var usagePending = Promise.resolve();
13001
13145
  function usageLogPath() {
13002
- return process.env.FLAVOR_USAGE_FILE ?? join19(process.cwd(), ".flavor", "usage.jsonl");
13146
+ return process.env.FLAVOR_USAGE_FILE ?? join20(process.cwd(), ".flavor", "usage.jsonl");
13003
13147
  }
13004
13148
  var usageSessionId = "unknown";
13005
13149
  var truncateOnNextAppend = false;
@@ -13028,7 +13172,7 @@ var AuditLogger = class {
13028
13172
  #path;
13029
13173
  #closed = false;
13030
13174
  constructor(workspace) {
13031
- this.#path = join19(resolve15(workspace), ".flavor", "audit.jsonl");
13175
+ this.#path = join20(resolve15(workspace), ".flavor", "audit.jsonl");
13032
13176
  }
13033
13177
  get path() {
13034
13178
  return this.#path;
@@ -13626,7 +13770,7 @@ var ModelRegistry = class {
13626
13770
  };
13627
13771
 
13628
13772
  // src/mcp/client.ts
13629
- import { createHash as createHash11 } from "crypto";
13773
+ import { createHash as createHash12 } from "crypto";
13630
13774
  import { z as z24 } from "zod";
13631
13775
  var McpManager = class {
13632
13776
  #workspace;
@@ -13793,7 +13937,7 @@ function mcpToolName(serverName, remoteName) {
13793
13937
  const safe = remoteName.replace(/[^A-Za-z0-9_-]/g, "_") || "tool";
13794
13938
  const direct = `${prefix}${safe}`;
13795
13939
  if (direct.length <= 64 && safe === remoteName) return direct;
13796
- const suffix = `__${createHash11("sha256").update(remoteName).digest("hex").slice(0, 8)}`;
13940
+ const suffix = `__${createHash12("sha256").update(remoteName).digest("hex").slice(0, 8)}`;
13797
13941
  return `${prefix}${safe.slice(0, Math.max(1, 64 - prefix.length - suffix.length))}${suffix}`;
13798
13942
  }
13799
13943
  function mcpErrorText(content) {
@@ -13824,7 +13968,7 @@ import {
13824
13968
 
13825
13969
  // src/utils/version.ts
13826
13970
  import { readFileSync as readFileSync2 } from "fs";
13827
- import { dirname as dirname13, join as join20 } from "path";
13971
+ import { dirname as dirname13, join as join21 } from "path";
13828
13972
  import { fileURLToPath as fileURLToPath2 } from "url";
13829
13973
  var cached;
13830
13974
  function packageVersion() {
@@ -13832,7 +13976,7 @@ function packageVersion() {
13832
13976
  let directory = dirname13(fileURLToPath2(import.meta.url));
13833
13977
  for (; ; ) {
13834
13978
  try {
13835
- const manifest = JSON.parse(readFileSync2(join20(directory, "package.json"), "utf8"));
13979
+ const manifest = JSON.parse(readFileSync2(join21(directory, "package.json"), "utf8"));
13836
13980
  if (typeof manifest.version === "string" && manifest.version.length > 0) {
13837
13981
  cached = manifest.version;
13838
13982
  return cached;
@@ -13885,14 +14029,14 @@ async function connectSdkMcpClient(input, dependencies2 = DEFAULT_DEPENDENCIES)
13885
14029
  }
13886
14030
 
13887
14031
  // src/auth/oauth.ts
13888
- import { randomBytes as randomBytes2, createHash as createHash13 } from "crypto";
13889
- import { createServer as createServer2 } from "http";
14032
+ import { randomBytes as randomBytes2, createHash as createHash14 } from "crypto";
14033
+ import { createServer as createServer3 } from "http";
13890
14034
  import { URL as URL2, URLSearchParams } from "url";
13891
14035
 
13892
14036
  // src/auth/oauth-config.ts
13893
- import { createHash as createHash12 } from "crypto";
14037
+ import { createHash as createHash13 } from "crypto";
13894
14038
  function oauthCredentialId(tokenUrl, clientId) {
13895
- const digest = createHash12("sha256").update(`${tokenUrl}\0${clientId}`, "utf8").digest("base64url");
14039
+ const digest = createHash13("sha256").update(`${tokenUrl}\0${clientId}`, "utf8").digest("base64url");
13896
14040
  return `oauth:${digest}`;
13897
14041
  }
13898
14042
  function parseOAuthLlmConfig(value) {
@@ -14069,7 +14213,7 @@ var OAuthCallbackAuthProvider = class {
14069
14213
  serverResolve = resolve41;
14070
14214
  serverReject = reject;
14071
14215
  });
14072
- const server = createServer2((req, res) => {
14216
+ const server = createServer3((req, res) => {
14073
14217
  const url = new URL2(req.url ?? "/", `http://${this.#callbackHost}:${server.address().port}`);
14074
14218
  if (url.searchParams.has("error")) {
14075
14219
  const error = url.searchParams.get("error") ?? "access_denied";
@@ -14149,7 +14293,7 @@ var OAuthCallbackAuthProvider = class {
14149
14293
  return randomBytes2(32).toString("base64url");
14150
14294
  }
14151
14295
  #computeCodeChallenge(verifier) {
14152
- return createHash13("sha256").update(verifier).digest("base64url");
14296
+ return createHash14("sha256").update(verifier).digest("base64url");
14153
14297
  }
14154
14298
  #generateState() {
14155
14299
  return randomBytes2(32).toString("base64url");
@@ -14260,7 +14404,7 @@ function isStoredToken(value) {
14260
14404
 
14261
14405
  // src/permissions/policy.ts
14262
14406
  import { readFile as readFile16 } from "fs/promises";
14263
- import { join as join21, resolve as resolve17 } from "path";
14407
+ import { join as join22, resolve as resolve17 } from "path";
14264
14408
  import { z as z25 } from "zod";
14265
14409
  var DecisionSchema2 = z25.enum(["allow", "ask", "deny"]);
14266
14410
  var PrefixSchema = z25.array(z25.string().min(1).max(1024)).min(1).max(64);
@@ -14297,9 +14441,9 @@ var CompiledPermissionPolicy = class {
14297
14441
  async function loadPermissionPolicy(options) {
14298
14442
  const sources = [
14299
14443
  ...options.managedPath === void 0 ? [] : [{ tier: "managed", path: resolve17(options.managedPath) }],
14300
- { tier: "user", path: join21(resolve17(options.home), ".flavor-code", "permissions.json") },
14301
- { tier: "project", path: join21(resolve17(options.workspace), ".flavor", "permissions.json") },
14302
- { tier: "local", path: join21(resolve17(options.workspace), ".flavor", "permissions.local.json") }
14444
+ { tier: "user", path: join22(resolve17(options.home), ".flavor-code", "permissions.json") },
14445
+ { tier: "project", path: join22(resolve17(options.workspace), ".flavor", "permissions.json") },
14446
+ { tier: "local", path: join22(resolve17(options.workspace), ".flavor", "permissions.local.json") }
14303
14447
  ];
14304
14448
  const rules = [];
14305
14449
  for (const source of sources) {
@@ -15068,8 +15212,8 @@ function createSkillResourceTool(registry) {
15068
15212
  // src/session/store.ts
15069
15213
  import { constants as constants6 } from "fs";
15070
15214
  import { lstat as lstat8, mkdir as mkdir15, open as open7, readFile as readFile17, readdir as readdir6, realpath as realpath10, rename as rename6, rm as rm8, stat as stat7 } from "fs/promises";
15071
- import { basename as basename5, dirname as dirname15, join as join22, relative as relative13, resolve as resolve19, sep as sep13 } from "path";
15072
- import { randomUUID as randomUUID12 } from "crypto";
15215
+ import { basename as basename5, dirname as dirname15, join as join23, relative as relative13, resolve as resolve19, sep as sep13 } from "path";
15216
+ import { randomUUID as randomUUID13 } from "crypto";
15073
15217
  import { z as z27 } from "zod";
15074
15218
 
15075
15219
  // src/ui/transcript.ts
@@ -15725,7 +15869,7 @@ var SessionStore = class {
15725
15869
  #maxSessions;
15726
15870
  constructor(options) {
15727
15871
  this.#workspace = resolve19(options.workspace);
15728
- this.#sessions = join22(this.#workspace, ".flavor", "sessions");
15872
+ this.#sessions = join23(this.#workspace, ".flavor", "sessions");
15729
15873
  this.#maxBytes = options.maxBytes ?? DEFAULT_MAX_SESSION_BYTES;
15730
15874
  if (!Number.isSafeInteger(this.#maxBytes) || this.#maxBytes < 256) throw new Error("maxBytes must be an integer of at least 256");
15731
15875
  this.#maxSessions = options.maxSessions ?? 50;
@@ -15757,7 +15901,7 @@ var SessionStore = class {
15757
15901
  const body = `${lines.join("\n")}
15758
15902
  `;
15759
15903
  if (Buffer.byteLength(body) > this.#maxBytes) throw new Error(`Session exceeds maximum size of ${this.#maxBytes} bytes`);
15760
- const temporary = join22(this.#sessions, `.${document.sessionId}.${process.pid}.${randomUUID12()}.tmp`);
15904
+ const temporary = join23(this.#sessions, `.${document.sessionId}.${process.pid}.${randomUUID13()}.tmp`);
15761
15905
  let handle;
15762
15906
  try {
15763
15907
  handle = await open7(temporary, constants6.O_CREAT | constants6.O_EXCL | constants6.O_WRONLY, 384);
@@ -15874,7 +16018,7 @@ var SessionStore = class {
15874
16018
  const metadata = await lstat8(path);
15875
16019
  if (!metadata.isFile()) throw new Error("Session path is not a regular file");
15876
16020
  await rm8(path);
15877
- await rm8(join22(this.#sessions, `${sessionId}.events.jsonl`), { force: true }).catch(() => void 0);
16021
+ await rm8(join23(this.#sessions, `${sessionId}.events.jsonl`), { force: true }).catch(() => void 0);
15878
16022
  } catch (error) {
15879
16023
  if (!isCode8(error, "ENOENT")) throw error;
15880
16024
  }
@@ -15891,7 +16035,7 @@ var SessionStore = class {
15891
16035
  const excess = entries.slice(this.#maxSessions);
15892
16036
  for (const entry2 of excess) {
15893
16037
  await rm8(this.#path(entry2.sessionId), { force: true }).catch(() => void 0);
15894
- await rm8(join22(this.#sessions, `${entry2.sessionId}.events.jsonl`), { force: true }).catch(() => void 0);
16038
+ await rm8(join23(this.#sessions, `${entry2.sessionId}.events.jsonl`), { force: true }).catch(() => void 0);
15895
16039
  }
15896
16040
  }
15897
16041
  async #assertWorkspace(stored) {
@@ -15913,7 +16057,7 @@ var SessionStore = class {
15913
16057
  if (!isWithin5(canonicalRoot, canonicalSessions)) throw new Error("Session directory escapes the workspace");
15914
16058
  }
15915
16059
  async #quarantine(path) {
15916
- const target = `${path}.corrupt-${Date.now()}-${randomUUID12().slice(0, 8)}`;
16060
+ const target = `${path}.corrupt-${Date.now()}-${randomUUID13().slice(0, 8)}`;
15917
16061
  await rename6(path, target);
15918
16062
  return target;
15919
16063
  }
@@ -16132,15 +16276,15 @@ function sanitize2(input, seen = /* @__PURE__ */ new WeakSet()) {
16132
16276
  }
16133
16277
 
16134
16278
  // src/session/tree.ts
16135
- import { randomUUID as randomUUID14 } from "crypto";
16279
+ import { randomUUID as randomUUID15 } from "crypto";
16136
16280
  import { mkdir as mkdir17, readFile as readFile19, rename as rename8, writeFile as writeFile11 } from "fs/promises";
16137
- import { dirname as dirname17, join as join24, resolve as resolve21 } from "path";
16281
+ import { dirname as dirname17, join as join25, resolve as resolve21 } from "path";
16138
16282
 
16139
16283
  // src/session/checkpoint.ts
16140
- import { createHash as createHash14, randomUUID as randomUUID13 } from "crypto";
16284
+ import { createHash as createHash15, randomUUID as randomUUID14 } from "crypto";
16141
16285
  import { execFile as execFile2 } from "child_process";
16142
16286
  import { lstat as lstat9, mkdir as mkdir16, open as open8, readFile as readFile18, readdir as readdir7, rename as rename7, rm as rm9, writeFile as writeFile10 } from "fs/promises";
16143
- import { dirname as dirname16, join as join23, relative as relative14, resolve as resolve20, sep as sep14 } from "path";
16287
+ import { dirname as dirname16, join as join24, relative as relative14, resolve as resolve20, sep as sep14 } from "path";
16144
16288
  var EXCLUDED = /* @__PURE__ */ new Set([".git", ".flavor", "node_modules", "dist", "build", "release", ".worktrees"]);
16145
16289
  var MAX_FILE_BYTES = 16 * 1024 * 1024;
16146
16290
  var MAX_TOTAL_BYTES = 128 * 1024 * 1024;
@@ -16153,9 +16297,9 @@ var WorkspaceCheckpointStore = class {
16153
16297
  #maxTotalBytes;
16154
16298
  constructor(options) {
16155
16299
  this.#workspace = resolve20(options.workspace);
16156
- this.#root = join23(this.#workspace, ".flavor", "checkpoints");
16157
- this.#objects = join23(this.#root, "objects");
16158
- this.#manifests = join23(this.#root, "manifests");
16300
+ this.#root = join24(this.#workspace, ".flavor", "checkpoints");
16301
+ this.#objects = join24(this.#root, "objects");
16302
+ this.#manifests = join24(this.#root, "manifests");
16159
16303
  this.#maxFileBytes = options.maxFileBytes ?? MAX_FILE_BYTES;
16160
16304
  this.#maxTotalBytes = options.maxTotalBytes ?? MAX_TOTAL_BYTES;
16161
16305
  }
@@ -16174,8 +16318,8 @@ var WorkspaceCheckpointStore = class {
16174
16318
  total += info.size;
16175
16319
  if (total > this.#maxTotalBytes) throw new Error("Checkpoint exceeds total size limit");
16176
16320
  const content = await readFile18(absolute);
16177
- const digest = createHash14("sha256").update(content).digest("hex");
16178
- const objectPath = join23(this.#objects, digest);
16321
+ const digest = createHash15("sha256").update(content).digest("hex");
16322
+ const objectPath = join24(this.#objects, digest);
16179
16323
  try {
16180
16324
  const handle = await open8(objectPath, "wx");
16181
16325
  try {
@@ -16190,17 +16334,17 @@ var WorkspaceCheckpointStore = class {
16190
16334
  }
16191
16335
  const checkpoint = {
16192
16336
  version: 1,
16193
- id: `checkpoint-${Date.now()}-${randomUUID13().slice(0, 8)}`,
16337
+ id: `checkpoint-${Date.now()}-${randomUUID14().slice(0, 8)}`,
16194
16338
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
16195
16339
  ...label === void 0 || label.trim().length === 0 ? {} : { label: label.trim() },
16196
16340
  files
16197
16341
  };
16198
- await atomicJson(join23(this.#manifests, `${checkpoint.id}.json`), checkpoint);
16342
+ await atomicJson(join24(this.#manifests, `${checkpoint.id}.json`), checkpoint);
16199
16343
  return checkpoint;
16200
16344
  }
16201
16345
  async load(id) {
16202
16346
  if (!/^checkpoint-[A-Za-z0-9-]+$/.test(id)) throw new Error("Invalid checkpoint id");
16203
- const value = JSON.parse(await readFile18(join23(this.#manifests, `${id}.json`), "utf8"));
16347
+ const value = JSON.parse(await readFile18(join24(this.#manifests, `${id}.json`), "utf8"));
16204
16348
  if (value.version !== 1 || value.id !== id || !Array.isArray(value.files)) throw new Error("Invalid checkpoint manifest");
16205
16349
  for (const file of value.files) {
16206
16350
  contained(this.#workspace, file.path);
@@ -16212,8 +16356,8 @@ var WorkspaceCheckpointStore = class {
16212
16356
  const checkpoint = await this.load(id);
16213
16357
  const objects = /* @__PURE__ */ new Map();
16214
16358
  for (const file of checkpoint.files) {
16215
- const object = await readFile18(join23(this.#objects, file.digest));
16216
- if (object.length !== file.size || createHash14("sha256").update(object).digest("hex") !== file.digest) {
16359
+ const object = await readFile18(join24(this.#objects, file.digest));
16360
+ if (object.length !== file.size || createHash15("sha256").update(object).digest("hex") !== file.digest) {
16217
16361
  throw new Error(`Checkpoint object is corrupt: ${file.digest}`);
16218
16362
  }
16219
16363
  objects.set(file.digest, object);
@@ -16227,7 +16371,7 @@ var WorkspaceCheckpointStore = class {
16227
16371
  const target = contained(this.#workspace, file.path);
16228
16372
  const object = objects.get(file.digest);
16229
16373
  await mkdir16(dirname16(target), { recursive: true });
16230
- const temporary = `${target}.${process.pid}.${randomUUID13()}.tmp`;
16374
+ const temporary = `${target}.${process.pid}.${randomUUID14()}.tmp`;
16231
16375
  await writeFile10(temporary, object, { mode: file.mode });
16232
16376
  await rename7(temporary, target);
16233
16377
  }
@@ -16235,7 +16379,7 @@ var WorkspaceCheckpointStore = class {
16235
16379
  }
16236
16380
  };
16237
16381
  async function discoverFiles(workspace) {
16238
- if (await exists2(join23(workspace, ".git"))) {
16382
+ if (await exists2(join24(workspace, ".git"))) {
16239
16383
  const listed = await gitFiles(workspace);
16240
16384
  return listed.filter((path) => !EXCLUDED.has(path.split("/")[0] ?? "")).sort();
16241
16385
  }
@@ -16244,7 +16388,7 @@ async function discoverFiles(workspace) {
16244
16388
  const entries = await readdir7(directory, { withFileTypes: true });
16245
16389
  for (const entry2 of entries) {
16246
16390
  if (EXCLUDED.has(entry2.name)) continue;
16247
- const absolute = join23(directory, entry2.name);
16391
+ const absolute = join24(directory, entry2.name);
16248
16392
  const path = normalizeRelative(relative14(workspace, absolute));
16249
16393
  if (entry2.isSymbolicLink()) throw new Error(`Checkpoint refuses symbolic link: ${path}`);
16250
16394
  if (entry2.isDirectory()) await walk(absolute);
@@ -16299,7 +16443,7 @@ function contained(workspace, path) {
16299
16443
  }
16300
16444
  async function atomicJson(path, value) {
16301
16445
  await mkdir16(dirname16(path), { recursive: true });
16302
- const temporary = `${path}.${process.pid}.${randomUUID13()}.tmp`;
16446
+ const temporary = `${path}.${process.pid}.${randomUUID14()}.tmp`;
16303
16447
  await writeFile10(temporary, `${JSON.stringify(value)}
16304
16448
  `, { encoding: "utf8", mode: 384 });
16305
16449
  await rename7(temporary, path);
@@ -16317,14 +16461,14 @@ var SessionHistory = class _SessionHistory {
16317
16461
  #leafId;
16318
16462
  #unrevert;
16319
16463
  constructor(options, document) {
16320
- this.#path = join24(resolve21(options.workspace), ".flavor", "session-trees", options.sessionId, "tree.json");
16464
+ this.#path = join25(resolve21(options.workspace), ".flavor", "session-trees", options.sessionId, "tree.json");
16321
16465
  this.#checkpoints = new WorkspaceCheckpointStore({ workspace: options.workspace });
16322
16466
  this.#restoreContext = options.restoreContext;
16323
16467
  this.#nodes = document.nodes;
16324
16468
  this.#leafId = document.leafId;
16325
16469
  }
16326
16470
  static async open(options) {
16327
- const path = join24(resolve21(options.workspace), ".flavor", "session-trees", options.sessionId, "tree.json");
16471
+ const path = join25(resolve21(options.workspace), ".flavor", "session-trees", options.sessionId, "tree.json");
16328
16472
  let document = { version: 1, sessionId: options.sessionId, leafId: null, nodes: [] };
16329
16473
  try {
16330
16474
  const parsed = JSON.parse(await readFile19(path, "utf8"));
@@ -16344,7 +16488,7 @@ var SessionHistory = class _SessionHistory {
16344
16488
  async append(input) {
16345
16489
  const checkpoint = await this.#checkpoints.create(input.label);
16346
16490
  const node = {
16347
- id: `turn-${Date.now()}-${randomUUID14().slice(0, 8)}`,
16491
+ id: `turn-${Date.now()}-${randomUUID15().slice(0, 8)}`,
16348
16492
  parentId: this.#leafId,
16349
16493
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
16350
16494
  prompt: input.prompt,
@@ -16402,7 +16546,7 @@ var SessionHistory = class _SessionHistory {
16402
16546
  nodes: this.#nodes
16403
16547
  };
16404
16548
  await mkdir17(dirname17(this.#path), { recursive: true });
16405
- const temporary = `${this.#path}.${process.pid}.${randomUUID14()}.tmp`;
16549
+ const temporary = `${this.#path}.${process.pid}.${randomUUID15()}.tmp`;
16406
16550
  await writeFile11(temporary, `${JSON.stringify(document)}
16407
16551
  `, { encoding: "utf8", mode: 384 });
16408
16552
  await rename8(temporary, this.#path);
@@ -16428,9 +16572,9 @@ function isCode10(error, code) {
16428
16572
 
16429
16573
  // src/sleep/organizer.ts
16430
16574
  import { constants as constants7 } from "fs";
16431
- import { randomUUID as randomUUID15 } from "crypto";
16575
+ import { randomUUID as randomUUID16 } from "crypto";
16432
16576
  import { lstat as lstat10, mkdir as mkdir18, open as open9, readdir as readdir8, realpath as realpath11, rename as rename9, rm as rm10 } from "fs/promises";
16433
- import { isAbsolute as isAbsolute10, join as join25, relative as relative15, resolve as resolve22, sep as sep15 } from "path";
16577
+ import { isAbsolute as isAbsolute10, join as join26, relative as relative15, resolve as resolve22, sep as sep15 } from "path";
16434
16578
  import { z as z28 } from "zod";
16435
16579
  var DateKeySchema = z28.string().regex(/^\d{4}-\d{2}-\d{2}$/);
16436
16580
  var ReviewSchema = z28.object({
@@ -16485,7 +16629,7 @@ var ProjectSleepOrganizer = class {
16485
16629
  #generate;
16486
16630
  constructor(options) {
16487
16631
  this.#workspace = resolve22(options.workspace);
16488
- this.#sleepDirectory = join25(this.#workspace, ".flavor", "sleep");
16632
+ this.#sleepDirectory = join26(this.#workspace, ".flavor", "sleep");
16489
16633
  this.#sessions = options.sessions ?? new SessionStore({ workspace: this.#workspace });
16490
16634
  this.#generate = options.generate;
16491
16635
  }
@@ -16494,7 +16638,7 @@ var ProjectSleepOrganizer = class {
16494
16638
  signal.throwIfAborted();
16495
16639
  await this.#prepareDirectory();
16496
16640
  if (await this.#hasReport(date)) return { status: "exists", date };
16497
- const lockPath = join25(this.#sleepDirectory, `.${date}.lock`);
16641
+ const lockPath = join26(this.#sleepDirectory, `.${date}.lock`);
16498
16642
  let lock;
16499
16643
  try {
16500
16644
  lock = await open9(lockPath, constants7.O_CREAT | constants7.O_EXCL | constants7.O_WRONLY, 384);
@@ -16529,7 +16673,7 @@ Previous output was invalid. Repair it and return strict JSON only.`;
16529
16673
  }
16530
16674
  if (review === void 0) throw lastError;
16531
16675
  const filename2 = `${date}-${filenameSummary(review.title)}.md`;
16532
- const path = join25(this.#sleepDirectory, filename2);
16676
+ const path = join26(this.#sleepDirectory, filename2);
16533
16677
  const markdown = renderSleepReport(date, review, documents);
16534
16678
  await this.#atomicWrite(path, markdown);
16535
16679
  return { status: "written", date, path, sessionCount: documents.length };
@@ -16571,7 +16715,7 @@ Previous output was invalid. Repair it and return strict JSON only.`;
16571
16715
  });
16572
16716
  }
16573
16717
  async #prepareDirectory() {
16574
- const flavorDirectory = join25(this.#workspace, ".flavor");
16718
+ const flavorDirectory = join26(this.#workspace, ".flavor");
16575
16719
  await assertNotSymlink(flavorDirectory);
16576
16720
  await mkdir18(flavorDirectory, { recursive: true, mode: 448 });
16577
16721
  await assertNotSymlink(this.#sleepDirectory);
@@ -16585,7 +16729,7 @@ Previous output was invalid. Repair it and return strict JSON only.`;
16585
16729
  return (await readdir8(this.#sleepDirectory, { withFileTypes: true })).some((entry2) => entry2.isFile() && entry2.name.startsWith(prefix) && entry2.name.endsWith(".md"));
16586
16730
  }
16587
16731
  async #atomicWrite(path, content) {
16588
- const temporary = join25(this.#sleepDirectory, `.${randomUUID15()}.tmp`);
16732
+ const temporary = join26(this.#sleepDirectory, `.${randomUUID16()}.tmp`);
16589
16733
  let handle;
16590
16734
  try {
16591
16735
  handle = await open9(temporary, constants7.O_CREAT | constants7.O_EXCL | constants7.O_WRONLY, 384);
@@ -16961,7 +17105,7 @@ function computeSessionStats(documents) {
16961
17105
  import { constants as constants8 } from "fs";
16962
17106
  import { mkdir as mkdir19, open as open10, readFile as readFile20, realpath as realpath12, rename as rename10, rm as rm11, stat as stat8 } from "fs/promises";
16963
17107
  import { dirname as dirname18, isAbsolute as isAbsolute11, relative as relative16, resolve as resolve23, sep as sep16 } from "path";
16964
- import { randomUUID as randomUUID16 } from "crypto";
17108
+ import { randomUUID as randomUUID17 } from "crypto";
16965
17109
  import { z as z29 } from "zod";
16966
17110
 
16967
17111
  // src/tools/file-diff.ts
@@ -17314,7 +17458,7 @@ function createPathGuard(workspace) {
17314
17458
  async function atomicWrite(path, content, signal, expectedVersion) {
17315
17459
  abortIfNeeded(signal);
17316
17460
  await mkdir19(dirname18(path), { recursive: true });
17317
- const temporary = `${path}.${randomUUID16()}.tmp`;
17461
+ const temporary = `${path}.${randomUUID17()}.tmp`;
17318
17462
  try {
17319
17463
  const handle = await open10(temporary, constants8.O_CREAT | constants8.O_EXCL | constants8.O_WRONLY, 384);
17320
17464
  try {
@@ -19511,9 +19655,9 @@ function createTodoWriteTool() {
19511
19655
  }
19512
19656
 
19513
19657
  // src/tools/managed.ts
19514
- import { randomUUID as randomUUID17 } from "crypto";
19515
- import { link, lstat as lstat11, mkdir as mkdir20, readFile as readFile22, readdir as readdir9, unlink as unlink2, writeFile as writeFile12 } from "fs/promises";
19516
- import { dirname as dirname21, join as join26, resolve as resolve26 } from "path";
19658
+ import { randomUUID as randomUUID18 } from "crypto";
19659
+ import { link, lstat as lstat11, mkdir as mkdir20, readFile as readFile22, readdir as readdir9, unlink as unlink3, writeFile as writeFile12 } from "fs/promises";
19660
+ import { dirname as dirname21, join as join27, resolve as resolve26 } from "path";
19517
19661
  import { z as z37 } from "zod";
19518
19662
  var MANAGED_TOOL_VERSION = 1;
19519
19663
  var MAX_RECORD_BYTES = 256 * 1024;
@@ -19556,8 +19700,8 @@ var ManagedToolStore = class {
19556
19700
  #diagnostics = [];
19557
19701
  constructor(options) {
19558
19702
  this.#workspace = resolve26(options.workspace);
19559
- this.#projectRoot = join26(this.#workspace, ".flavor", "tools");
19560
- this.#globalRoot = join26(resolve26(options.home), ".flavor-code", "tools");
19703
+ this.#projectRoot = join27(this.#workspace, ".flavor", "tools");
19704
+ this.#globalRoot = join27(resolve26(options.home), ".flavor-code", "tools");
19561
19705
  this.#now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
19562
19706
  }
19563
19707
  get diagnostics() {
@@ -19604,7 +19748,7 @@ var ManagedToolStore = class {
19604
19748
  version: MANAGED_TOOL_VERSION,
19605
19749
  createdAt: this.#now()
19606
19750
  });
19607
- const path = join26(this.directory(input.scope), filename(input.name));
19751
+ const path = join27(this.directory(input.scope), filename(input.name));
19608
19752
  const definition = compileDefinition(record3, input.scope, this.#workspace);
19609
19753
  await writeExclusive(path, `${JSON.stringify(record3, void 0, 2)}
19610
19754
  `);
@@ -19620,7 +19764,7 @@ var ManagedToolStore = class {
19620
19764
  const entry2 = matches[0];
19621
19765
  const info = await lstat11(entry2.path);
19622
19766
  if (!info.isFile() || info.isSymbolicLink()) throw new Error(`Managed tool path is no longer a regular file: ${entry2.path}`);
19623
- await unlink2(entry2.path);
19767
+ await unlink3(entry2.path);
19624
19768
  this.#entries.delete(scopedKey(entry2.scope, entry2.record.name));
19625
19769
  return summary(entry2, false);
19626
19770
  }
@@ -19629,7 +19773,7 @@ var ManagedToolStore = class {
19629
19773
  if (!parsed.success) return [];
19630
19774
  const matches = this.#matching(parsed.data.name).filter((entry2) => parsed.data.scope === void 0 || entry2.scope === parsed.data.scope);
19631
19775
  if (matches.length > 0) return matches.map((entry2) => entry2.path);
19632
- return [join26(this.directory(parsed.data.scope ?? "project"), filename(parsed.data.name))];
19776
+ return [join27(this.directory(parsed.data.scope ?? "project"), filename(parsed.data.name))];
19633
19777
  }
19634
19778
  async #loadDirectory(scope2) {
19635
19779
  const root = this.directory(scope2);
@@ -19642,7 +19786,7 @@ var ManagedToolStore = class {
19642
19786
  return;
19643
19787
  }
19644
19788
  for (const name of names) {
19645
- const path = join26(root, name);
19789
+ const path = join27(root, name);
19646
19790
  try {
19647
19791
  const info = await lstat11(path);
19648
19792
  if (!info.isFile() || info.isSymbolicLink()) throw new Error("Managed tool record must be a regular file");
@@ -19798,13 +19942,13 @@ ${sourceUrl}`
19798
19942
  }
19799
19943
  async function writeExclusive(path, content) {
19800
19944
  await mkdir20(dirname21(path), { recursive: true });
19801
- const temporary = `${path}.${randomUUID17()}.tmp`;
19945
+ const temporary = `${path}.${randomUUID18()}.tmp`;
19802
19946
  try {
19803
19947
  await writeFile12(temporary, content, { encoding: "utf8", flag: "wx", mode: 384 });
19804
19948
  await link(temporary, path);
19805
19949
  } finally {
19806
19950
  try {
19807
- await unlink2(temporary);
19951
+ await unlink3(temporary);
19808
19952
  } catch {
19809
19953
  }
19810
19954
  }
@@ -20752,6 +20896,8 @@ var FlavorSession = class {
20752
20896
  this.#activeSubmission = submission;
20753
20897
  this.#interrupted = false;
20754
20898
  let outcome = "completed";
20899
+ let assistantSummary = "";
20900
+ let deliverables = [];
20755
20901
  try {
20756
20902
  const decision = await this.#services.hooks.emit({
20757
20903
  version: 1,
@@ -20778,6 +20924,8 @@ var FlavorSession = class {
20778
20924
  ...submission.initialUserMessage === void 0 ? {} : { initialUserMessage: submission.initialUserMessage }
20779
20925
  })) {
20780
20926
  this.#services.output(event);
20927
+ if (event.type === "text") assistantSummary = `${assistantSummary}${event.text}`.slice(-2e3);
20928
+ if (event.type === "deliverables") deliverables = event.files.slice(0, 100);
20781
20929
  if (event.type === "error") outcome = "failed";
20782
20930
  }
20783
20931
  if (controller2.signal.aborted) outcome = "cancelled";
@@ -20802,7 +20950,15 @@ var FlavorSession = class {
20802
20950
  this.#activeSubmission = void 0;
20803
20951
  if (submission.coWorkPlanningKey !== void 0) this.#finishActivePlanning(submission.coWorkPlanningKey);
20804
20952
  try {
20805
- await this.#services.hooks.emit({ version: 1, type: "Stop", payload: { outcome } });
20953
+ await this.#services.hooks.emit({
20954
+ version: 1,
20955
+ type: "Stop",
20956
+ payload: {
20957
+ outcome,
20958
+ ...assistantSummary.trim() ? { summary: assistantSummary.trim() } : {},
20959
+ ...deliverables.length === 0 ? {} : { deliverables }
20960
+ }
20961
+ });
20806
20962
  } catch (error) {
20807
20963
  try {
20808
20964
  this.#services.output({ type: "error", error: { code: "unknown", message: message(error) } });
@@ -21535,7 +21691,7 @@ function buildWarningMessages(report, languageTag) {
21535
21691
  }
21536
21692
 
21537
21693
  // src/hallucination/sliding-window.ts
21538
- import { createHash as createHash15 } from "crypto";
21694
+ import { createHash as createHash16 } from "crypto";
21539
21695
  var SlidingWindow = class {
21540
21696
  #windowSize;
21541
21697
  #threshold;
@@ -21551,7 +21707,7 @@ var SlidingWindow = class {
21551
21707
  }
21552
21708
  hash(toolName, params) {
21553
21709
  const sorted = JSON.stringify(params, sortedKeys(params));
21554
- return createHash15("sha256").update(`${toolName}:${sorted}`).digest("hex");
21710
+ return createHash16("sha256").update(`${toolName}:${sorted}`).digest("hex");
21555
21711
  }
21556
21712
  push(toolName, params) {
21557
21713
  const hash = this.hash(toolName, params);
@@ -21906,9 +22062,9 @@ ${total}`;
21906
22062
  }
21907
22063
 
21908
22064
  // src/memory/store.ts
21909
- import { createHash as createHash16 } from "crypto";
22065
+ import { createHash as createHash17 } from "crypto";
21910
22066
  import { readFile as readFile23, rm as rm12 } from "fs/promises";
21911
- import { resolve as resolve27, join as join27, relative as relative19, sep as sep19 } from "path";
22067
+ import { resolve as resolve27, join as join28, relative as relative19, sep as sep19 } from "path";
21912
22068
 
21913
22069
  // src/memory/similarity.ts
21914
22070
  function normalizeForSimilarity(value) {
@@ -22011,9 +22167,9 @@ var MemoryStore = class {
22011
22167
  if (!Number.isSafeInteger(options.maxEntries) || options.maxEntries < 1) throw new Error("maxEntries must be an integer of at least 1");
22012
22168
  if (!Number.isSafeInteger(options.maxEntryChars) || options.maxEntryChars < 1) throw new Error("maxEntryChars must be an integer of at least 1");
22013
22169
  this.workspace = resolve27(options.workspace);
22014
- this.#memoryRoot = join27(this.workspace, ".flavor", "memory");
22015
- this.path = join27(this.#memoryRoot, "MEMORY.md");
22016
- this.#behaviorPath = join27(this.#memoryRoot, "behavior.json");
22170
+ this.#memoryRoot = join28(this.workspace, ".flavor", "memory");
22171
+ this.path = join28(this.#memoryRoot, "MEMORY.md");
22172
+ this.#behaviorPath = join28(this.#memoryRoot, "behavior.json");
22017
22173
  this.#maxEntries = options.maxEntries;
22018
22174
  this.#maxEntryChars = options.maxEntryChars;
22019
22175
  }
@@ -22392,7 +22548,7 @@ function sanitizeTopicKey(value) {
22392
22548
  return value.normalize("NFKC").toLocaleLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 128);
22393
22549
  }
22394
22550
  function memoryId(type, content) {
22395
- return createHash16("sha256").update(`${type}\0${normalizeMemoryContent(content).toLocaleLowerCase()}`, "utf8").digest("hex").slice(0, 12);
22551
+ return createHash17("sha256").update(`${type}\0${normalizeMemoryContent(content).toLocaleLowerCase()}`, "utf8").digest("hex").slice(0, 12);
22396
22552
  }
22397
22553
  function assertTaskId(taskId) {
22398
22554
  if (!TASK_ID.test(taskId)) throw new Error(`Invalid memory task id: ${taskId}`);
@@ -22802,7 +22958,7 @@ function createExecutionEnvironment(workspace, config) {
22802
22958
 
22803
22959
  // src/ide/client.ts
22804
22960
  import { readFile as readFile24, readdir as readdir10, stat as stat10 } from "fs/promises";
22805
- import { basename as basename7, join as join28, relative as relative21, resolve as resolve29, sep as sep21 } from "path";
22961
+ import { basename as basename7, join as join29, relative as relative21, resolve as resolve29, sep as sep21 } from "path";
22806
22962
  var FlavorIdeClient = class {
22807
22963
  #workspace;
22808
22964
  #home;
@@ -22898,7 +23054,7 @@ var FlavorIdeClient = class {
22898
23054
  };
22899
23055
  if (await this.#healthy(configured)) return configured;
22900
23056
  }
22901
- const directory = join28(this.#home, ".flavor-code", "ide");
23057
+ const directory = join29(this.#home, ".flavor-code", "ide");
22902
23058
  let entries;
22903
23059
  try {
22904
23060
  entries = (await readdir10(directory)).filter((name) => name.endsWith(".lock"));
@@ -22906,7 +23062,7 @@ var FlavorIdeClient = class {
22906
23062
  return void 0;
22907
23063
  }
22908
23064
  const candidates = (await Promise.all(entries.map(async (name) => {
22909
- const path = join28(directory, name);
23065
+ const path = join29(directory, name);
22910
23066
  try {
22911
23067
  const [contents, info] = await Promise.all([readFile24(path, "utf8"), stat10(path)]);
22912
23068
  const lock = parseLockfile(contents);
@@ -23026,7 +23182,7 @@ function relativeDisplay(workspace, filePath) {
23026
23182
  }
23027
23183
 
23028
23184
  // src/jobs/registry.ts
23029
- import { randomUUID as randomUUID18 } from "crypto";
23185
+ import { randomUUID as randomUUID19 } from "crypto";
23030
23186
  var JobRegistry = class {
23031
23187
  #jobs = /* @__PURE__ */ new Map();
23032
23188
  #maxOutputChars;
@@ -23040,7 +23196,7 @@ var JobRegistry = class {
23040
23196
  }
23041
23197
  create(input) {
23042
23198
  this.#pruneCompleted();
23043
- const id = `job-${randomUUID18().slice(0, 12)}`;
23199
+ const id = `job-${randomUUID19().slice(0, 12)}`;
23044
23200
  const now = (/* @__PURE__ */ new Date()).toISOString();
23045
23201
  let settle;
23046
23202
  const done = new Promise((resolve41) => {
@@ -23166,7 +23322,7 @@ function snapshot2(job) {
23166
23322
  }
23167
23323
 
23168
23324
  // src/terminal/service.ts
23169
- import { randomUUID as randomUUID19 } from "crypto";
23325
+ import { randomUUID as randomUUID20 } from "crypto";
23170
23326
  import { createRequire as nodeCreateRequire } from "module";
23171
23327
  import { isAbsolute as isAbsolute14, relative as relative22, resolve as resolve30, sep as sep22 } from "path";
23172
23328
  var TerminalService = class {
@@ -23184,7 +23340,7 @@ var TerminalService = class {
23184
23340
  open(input) {
23185
23341
  const cwd = workspacePath(this.#root, input.cwd ?? ".");
23186
23342
  const shell2 = input.shell ?? defaultShell();
23187
- const id = `term-${randomUUID19().slice(0, 12)}`;
23343
+ const id = `term-${randomUUID20().slice(0, 12)}`;
23188
23344
  const pty = this.#factory(shell2, input.args ?? [], {
23189
23345
  cwd,
23190
23346
  cols: input.columns ?? 100,
@@ -23394,10 +23550,10 @@ function createTerminalTools(terminals, workspace = process.cwd()) {
23394
23550
  }
23395
23551
 
23396
23552
  // src/pals/address.ts
23397
- import { createHash as createHash17 } from "crypto";
23553
+ import { createHash as createHash18 } from "crypto";
23398
23554
  function opaqueUserScope(userScope) {
23399
23555
  if (userScope.length === 0) throw new Error("User scope must not be empty");
23400
- const digest = createHash17("sha256").update(userScope, "utf8").digest("hex").slice(0, 16);
23556
+ const digest = createHash18("sha256").update(userScope, "utf8").digest("hex").slice(0, 16);
23401
23557
  return `u-${digest}`;
23402
23558
  }
23403
23559
  function palSocketAddress(options) {
@@ -23410,32 +23566,32 @@ function palSocketAddress(options) {
23410
23566
  }
23411
23567
 
23412
23568
  // src/pals/broker-cli.ts
23413
- import { createHash as createHash19 } from "crypto";
23569
+ import { createHash as createHash20 } from "crypto";
23414
23570
  import { Socket as Socket2 } from "net";
23415
- import { tmpdir as tmpdir2 } from "os";
23416
- import { join as join30 } from "path";
23571
+ import { tmpdir as tmpdir3 } from "os";
23572
+ import { join as join31 } from "path";
23417
23573
  import { spawn as spawn7 } from "child_process";
23418
23574
 
23419
23575
  // src/pals/broker.ts
23420
- import { createHash as createHash18, randomUUID as randomUUID22, timingSafeEqual } from "crypto";
23421
- import { chmod as chmod2, lstat as lstat12, mkdir as mkdir23, unlink as unlink5 } from "fs/promises";
23422
- import { createServer as createServer3, Socket } from "net";
23576
+ import { createHash as createHash19, randomUUID as randomUUID23, timingSafeEqual } from "crypto";
23577
+ import { chmod as chmod3, lstat as lstat12, mkdir as mkdir23, unlink as unlink6 } from "fs/promises";
23578
+ import { createServer as createServer4, Socket } from "net";
23423
23579
  import { dirname as dirname23 } from "path";
23424
23580
 
23425
23581
  // src/pals/auth.ts
23426
- import { randomBytes as randomBytes3, randomUUID as randomUUID20 } from "crypto";
23427
- import { chmod, link as link2, mkdir as mkdir21, open as open12, readFile as readFile25, unlink as unlink3 } from "fs/promises";
23582
+ import { randomBytes as randomBytes3, randomUUID as randomUUID21 } from "crypto";
23583
+ import { chmod as chmod2, link as link2, mkdir as mkdir21, open as open12, readFile as readFile25, unlink as unlink4 } from "fs/promises";
23428
23584
  import { homedir } from "os";
23429
- import { join as join29 } from "path";
23585
+ import { join as join30 } from "path";
23430
23586
  var PAL_AUTH_TOKEN_BYTES = 32;
23431
23587
  var TOKEN_PATTERN = /^[a-f0-9]{64}$/;
23432
23588
  async function loadOrCreatePalAuthToken(options = {}) {
23433
- const directory = join29(options.home ?? homedir(), ".flavor-code", "pals");
23434
- const tokenPath = join29(directory, "auth-token");
23589
+ const directory = join30(options.home ?? homedir(), ".flavor-code", "pals");
23590
+ const tokenPath = join30(directory, "auth-token");
23435
23591
  await mkdir21(directory, { recursive: true, mode: 448 });
23436
- await chmod(directory, 448);
23592
+ await chmod2(directory, 448);
23437
23593
  const token = (options.random ?? randomBytes3)(PAL_AUTH_TOKEN_BYTES).toString("hex");
23438
- const temporaryPath = join29(directory, `.auth-token-${process.pid}-${randomUUID20()}.tmp`);
23594
+ const temporaryPath = join30(directory, `.auth-token-${process.pid}-${randomUUID21()}.tmp`);
23439
23595
  let handle;
23440
23596
  try {
23441
23597
  handle = await open12(temporaryPath, "wx", 384);
@@ -23454,13 +23610,13 @@ async function loadOrCreatePalAuthToken(options = {}) {
23454
23610
  }
23455
23611
  } finally {
23456
23612
  await handle?.close();
23457
- await unlink3(temporaryPath).catch((error) => {
23613
+ await unlink4(temporaryPath).catch((error) => {
23458
23614
  if (error.code !== "ENOENT") throw error;
23459
23615
  });
23460
23616
  }
23461
23617
  const stored = (await readFile25(tokenPath, "utf8")).trim();
23462
23618
  if (!TOKEN_PATTERN.test(stored)) throw new Error("Pals authentication token store is invalid");
23463
- await chmod(tokenPath, 384);
23619
+ await chmod2(tokenPath, 384);
23464
23620
  return stored;
23465
23621
  }
23466
23622
  function validatePalAuthToken(token) {
@@ -23469,8 +23625,8 @@ function validatePalAuthToken(token) {
23469
23625
  }
23470
23626
 
23471
23627
  // src/pals/lifecycle.ts
23472
- import { randomUUID as randomUUID21 } from "crypto";
23473
- import { mkdir as mkdir22, open as open13, readFile as readFile26, rename as rename11, stat as stat11, unlink as unlink4 } from "fs/promises";
23628
+ import { randomUUID as randomUUID22 } from "crypto";
23629
+ import { mkdir as mkdir22, open as open13, readFile as readFile26, rename as rename11, stat as stat11, unlink as unlink5 } from "fs/promises";
23474
23630
  import { dirname as dirname22 } from "path";
23475
23631
  function defaultProcessAlive(pid) {
23476
23632
  if (!Number.isSafeInteger(pid) || pid <= 0) return true;
@@ -23495,7 +23651,7 @@ async function acquirePalFileLock(options) {
23495
23651
  await mkdir22(dirname22(options.path), { recursive: true, mode: 448 });
23496
23652
  const pid = options.pid ?? process.pid;
23497
23653
  const now = options.now ?? Date.now;
23498
- const nonce = randomUUID21();
23654
+ const nonce = randomUUID22();
23499
23655
  const metadata = { pid, createdAt: now(), nonce };
23500
23656
  let handle;
23501
23657
  try {
@@ -23520,7 +23676,7 @@ async function acquirePalFileLock(options) {
23520
23676
  if (openError.code !== "EEXIST") throw openError;
23521
23677
  return void 0;
23522
23678
  } finally {
23523
- await unlink4(tombstone).catch((unlinkError) => {
23679
+ await unlink5(tombstone).catch((unlinkError) => {
23524
23680
  if (unlinkError.code !== "ENOENT") throw unlinkError;
23525
23681
  });
23526
23682
  }
@@ -23534,7 +23690,7 @@ async function acquirePalFileLock(options) {
23534
23690
  const release = async () => {
23535
23691
  const current = parseMetadata(await readFile26(options.path, "utf8").catch(() => ""));
23536
23692
  if (current?.nonce !== nonce) return;
23537
- await unlink4(options.path).catch((error) => {
23693
+ await unlink5(options.path).catch((error) => {
23538
23694
  if (error.code !== "ENOENT") throw error;
23539
23695
  });
23540
23696
  };
@@ -23564,8 +23720,8 @@ function canConnect(address) {
23564
23720
  });
23565
23721
  }
23566
23722
  function startupLockPath(address) {
23567
- const digest = createHash19("sha256").update(address, "utf8").digest("hex").slice(0, 24);
23568
- return join30(tmpdir2(), `flavor-code-pals-${digest}.startup.lock`);
23723
+ const digest = createHash20("sha256").update(address, "utf8").digest("hex").slice(0, 24);
23724
+ return join31(tmpdir3(), `flavor-code-pals-${digest}.startup.lock`);
23569
23725
  }
23570
23726
  async function spawnProductionBroker(address) {
23571
23727
  const entry2 = process.argv[1];
@@ -23614,7 +23770,7 @@ async function ensureOnce(options) {
23614
23770
  }
23615
23771
 
23616
23772
  // src/pals/client.ts
23617
- import { randomUUID as randomUUID23 } from "crypto";
23773
+ import { randomUUID as randomUUID24 } from "crypto";
23618
23774
  import { Socket as Socket3 } from "net";
23619
23775
  var DEFAULT_REQUEST_TIMEOUT_MS = 5e3;
23620
23776
  var DEFAULT_HEARTBEAT_INTERVAL_MS = 1e4;
@@ -23690,7 +23846,7 @@ var PalClient = class {
23690
23846
  return this.starting;
23691
23847
  }
23692
23848
  async list() {
23693
- const data2 = await this.request({ version: 1, type: "list", requestId: randomUUID23() });
23849
+ const data2 = await this.request({ version: 1, type: "list", requestId: randomUUID24() });
23694
23850
  return PalPresenceListSchema.parse(data2);
23695
23851
  }
23696
23852
  async rename(alias) {
@@ -23703,38 +23859,38 @@ var PalClient = class {
23703
23859
  throw error;
23704
23860
  }
23705
23861
  }
23706
- async sendTask(target, message2, messageId = randomUUID23()) {
23707
- const data2 = await this.request({ version: 1, type: "task", requestId: randomUUID23(), messageId, target, goal: message2 });
23862
+ async sendTask(target, message2, messageId = randomUUID24()) {
23863
+ const data2 = await this.request({ version: 1, type: "task", requestId: randomUUID24(), messageId, target, goal: message2 });
23708
23864
  return DeliveryReceiptSchema.parse(data2);
23709
23865
  }
23710
- async sendChat(target, message2, messageId = randomUUID23()) {
23711
- const data2 = await this.request({ version: 1, type: "chat", requestId: randomUUID23(), messageId, target, message: message2 });
23866
+ async sendChat(target, message2, messageId = randomUUID24()) {
23867
+ const data2 = await this.request({ version: 1, type: "chat", requestId: randomUUID24(), messageId, target, message: message2 });
23712
23868
  return DeliveryReceiptSchema.parse(data2);
23713
23869
  }
23714
23870
  async startCoWork(input) {
23715
23871
  const data2 = await this.request({
23716
23872
  version: 1,
23717
23873
  type: "cowork-propose",
23718
- requestId: randomUUID23(),
23719
- coWorkId: input.coWorkId ?? randomUUID23(),
23874
+ requestId: randomUUID24(),
23875
+ coWorkId: input.coWorkId ?? randomUUID24(),
23720
23876
  goal: input.goal,
23721
23877
  participants: input.participants
23722
23878
  });
23723
23879
  return CoWorkSnapshotSchema.parse(data2);
23724
23880
  }
23725
23881
  async coWorkAction(action) {
23726
- const request = { version: 1, requestId: randomUUID23(), ...action };
23882
+ const request = { version: 1, requestId: randomUUID24(), ...action };
23727
23883
  return CoWorkSnapshotSchema.parse(await this.request(request));
23728
23884
  }
23729
23885
  async coWorkStatus(coWorkId) {
23730
- const data2 = await this.request({ version: 1, type: "cowork-get", requestId: randomUUID23(), coWorkId });
23886
+ const data2 = await this.request({ version: 1, type: "cowork-get", requestId: randomUUID24(), coWorkId });
23731
23887
  return CoWorkSnapshotSchema.parse(data2);
23732
23888
  }
23733
23889
  async integrateCoWork(input) {
23734
23890
  return this.coWorkAction({ type: "cowork-integration", ...input });
23735
23891
  }
23736
23892
  async cancelCoWork(coWorkId, reason) {
23737
- const data2 = await this.request({ version: 1, type: "cowork-cancel", requestId: randomUUID23(), coWorkId, reason });
23893
+ const data2 = await this.request({ version: 1, type: "cowork-cancel", requestId: randomUUID24(), coWorkId, reason });
23738
23894
  return CoWorkSnapshotSchema.parse(data2);
23739
23895
  }
23740
23896
  subscribe(listener) {
@@ -23746,7 +23902,7 @@ var PalClient = class {
23746
23902
  if (this.registered && this.socket !== void 0) {
23747
23903
  let disconnectTimer;
23748
23904
  await Promise.race([
23749
- this.request({ version: 1, type: "disconnect", requestId: randomUUID23() }).catch(() => void 0),
23905
+ this.request({ version: 1, type: "disconnect", requestId: randomUUID24() }).catch(() => void 0),
23750
23906
  new Promise((resolve41) => {
23751
23907
  disconnectTimer = setTimeout(resolve41, Math.min(this.requestTimeoutMs, 250));
23752
23908
  })
@@ -23837,7 +23993,7 @@ var PalClient = class {
23837
23993
  const data2 = await this.request({
23838
23994
  version: 1,
23839
23995
  type: "register",
23840
- requestId: randomUUID23(),
23996
+ requestId: randomUUID24(),
23841
23997
  authToken: this.authToken,
23842
23998
  presence: { version: 1, ...this.registration, connectedAt: now, lastSeenAt: now }
23843
23999
  });
@@ -23949,7 +24105,7 @@ var PalClient = class {
23949
24105
  if (!this.registered) return;
23950
24106
  if (this.heartbeatPending) return;
23951
24107
  this.heartbeatPending = true;
23952
- void this.request({ version: 1, type: "heartbeat", requestId: randomUUID23() }).catch(() => void 0).finally(() => {
24108
+ void this.request({ version: 1, type: "heartbeat", requestId: randomUUID24() }).catch(() => void 0).finally(() => {
23953
24109
  this.heartbeatPending = false;
23954
24110
  });
23955
24111
  }, this.heartbeatIntervalMs);
@@ -24236,7 +24392,7 @@ var ApprovalBridge = class {
24236
24392
  request(request, signal = new AbortController().signal) {
24237
24393
  if (this.#settle !== void 0) return Promise.resolve("deny");
24238
24394
  if (signal.aborted) return Promise.resolve("deny");
24239
- this.#pending = { id: randomUUID24(), ...request };
24395
+ this.#pending = { id: randomUUID25(), ...request };
24240
24396
  this.#onChange?.();
24241
24397
  return new Promise((resolvePromise) => {
24242
24398
  this.#settle = resolvePromise;
@@ -24356,11 +24512,17 @@ async function createProductionRuntime(options) {
24356
24512
  environment.ANTHROPIC_API_KEY
24357
24513
  ].filter((value) => typeof value === "string" && value.length > 0);
24358
24514
  let hookSessionId;
24515
+ let islandControlMetadata;
24359
24516
  const hooks = new HookBus({
24360
24517
  eventContext: () => ({
24361
24518
  protocolVersion: 2,
24362
24519
  workspace,
24363
- ...hookSessionId === void 0 ? {} : { sessionId: hookSessionId }
24520
+ ...hookSessionId === void 0 ? {} : { sessionId: hookSessionId },
24521
+ ...islandControlMetadata === void 0 ? {} : {
24522
+ islandControlEndpoint: islandControlMetadata.endpoint,
24523
+ islandControlToken: islandControlMetadata.token,
24524
+ islandControlCapabilities: islandControlMetadata.capabilities
24525
+ }
24364
24526
  })
24365
24527
  });
24366
24528
  hooks.on(
@@ -24475,8 +24637,8 @@ async function createProductionRuntime(options) {
24475
24637
  const registeredProviders = registration.registered;
24476
24638
  let effectiveLlm = registration.effectiveLlm;
24477
24639
  const pluginHost = new PluginHost({
24478
- globalPluginDirs: [join31(home, ".flavor-code", "plugins")],
24479
- projectPluginDirs: [join31(workspace, ".flavor", "plugins")],
24640
+ globalPluginDirs: [join32(home, ".flavor-code", "plugins")],
24641
+ projectPluginDirs: [join32(workspace, ".flavor", "plugins")],
24480
24642
  config,
24481
24643
  // Existing project plugins (including astgraph and superharness) use Node.js
24482
24644
  // built-ins. The Worker/vm sandbox deliberately blocks those imports, so it
@@ -24550,6 +24712,7 @@ async function createProductionRuntime(options) {
24550
24712
  const pendingCollaborationEvents = [];
24551
24713
  let collaborationEventPump;
24552
24714
  let collaborationEventsOpen = true;
24715
+ let islandControlServer;
24553
24716
  const pumpCollaborationEvents = () => {
24554
24717
  if (collaborationEventPump !== void 0 || collaborationSession === void 0 || deliverCollaborationEvent === void 0) return;
24555
24718
  collaborationEventPump = (async () => {
@@ -24583,7 +24746,7 @@ async function createProductionRuntime(options) {
24583
24746
  const address = palSocketAddress({
24584
24747
  platform: process.platform,
24585
24748
  userScope: home,
24586
- runtimeDir: join31(tmpdir3(), `flavor-code-pals-${createHash20("sha256").update(home).digest("hex").slice(0, 16)}`)
24749
+ runtimeDir: join32(tmpdir4(), `flavor-code-pals-${createHash21("sha256").update(home).digest("hex").slice(0, 16)}`)
24587
24750
  });
24588
24751
  const baseCollaborationClient = collaboration.client ?? collaboration.createClient?.({
24589
24752
  instanceId: collaboration.instanceId,
@@ -24694,8 +24857,8 @@ async function createProductionRuntime(options) {
24694
24857
  diagnostics.push(`MCP servers could not start: ${message(error)}`);
24695
24858
  });
24696
24859
  const skills = new SkillRegistry({
24697
- globalRoots: [join31(home, ".flavor-code", "skills")],
24698
- projectRoots: [join31(workspace, ".flavor", "skills"), ...pluginSkillRoots],
24860
+ globalRoots: [join32(home, ".flavor-code", "skills")],
24861
+ projectRoots: [join32(workspace, ".flavor", "skills"), ...pluginSkillRoots],
24699
24862
  authorizeResource: async () => true,
24700
24863
  disabledNames: config.skills.disabled
24701
24864
  });
@@ -24703,7 +24866,7 @@ async function createProductionRuntime(options) {
24703
24866
  skillsReady.catch(() => void 0);
24704
24867
  tools.push(createSkillTool(skills), createSkillResourceTool(skills));
24705
24868
  if (options.extraTools !== void 0) tools.push(...options.extraTools);
24706
- const flavor = await optionalText2(join31(workspace, "FLAVOR.md"));
24869
+ const flavor = await optionalText2(join32(workspace, "FLAVOR.md"));
24707
24870
  const instructionBaseline = await workspaceInstructions.baseline();
24708
24871
  let memoryContext;
24709
24872
  if (memoryStore !== void 0) {
@@ -24727,7 +24890,7 @@ async function createProductionRuntime(options) {
24727
24890
  let taskResults = { ...recovered?.tasks.results ?? {} };
24728
24891
  const subagentStartedAt = {};
24729
24892
  const subagentElapsedMs = {};
24730
- let sessionId = recovered?.sessionId ?? `session-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "").slice(0, 17)}-${randomUUID24().slice(0, 8)}`;
24893
+ let sessionId = recovered?.sessionId ?? `session-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "").slice(0, 17)}-${randomUUID25().slice(0, 8)}`;
24731
24894
  hookSessionId = sessionId;
24732
24895
  let harnessJournal = new HarnessJournal({ workspace, sessionId });
24733
24896
  const harnessRecovery = harnessJournal.recover();
@@ -25237,7 +25400,7 @@ async function createProductionRuntime(options) {
25237
25400
  evolveService.toolDefinition(),
25238
25401
  ...mcpTools
25239
25402
  ];
25240
- const loopFlavor = await optionalText2(join31(input.workspace, "FLAVOR.md"));
25403
+ const loopFlavor = await optionalText2(join32(input.workspace, "FLAVOR.md"));
25241
25404
  const loopInstructionBaseline = await loopInstructions.baseline();
25242
25405
  const loopEnvironment = createPromptEnvironment({
25243
25406
  now: /* @__PURE__ */ new Date(),
@@ -25376,7 +25539,7 @@ async function createProductionRuntime(options) {
25376
25539
  return answers[0] === "Continue" ? "approved" : "rejected";
25377
25540
  },
25378
25541
  fingerprint: workspaceFingerprint,
25379
- idFactory: () => `loop-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "").slice(0, 17)}-${randomUUID24().slice(0, 8)}`
25542
+ idFactory: () => `loop-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "").slice(0, 17)}-${randomUUID25().slice(0, 8)}`
25380
25543
  });
25381
25544
  const goalStore = new GoalStore({ workspace });
25382
25545
  const goalOrchestrator = new GoalOrchestrator({
@@ -25395,7 +25558,7 @@ async function createProductionRuntime(options) {
25395
25558
  executionEnvironment
25396
25559
  ),
25397
25560
  now: () => (/* @__PURE__ */ new Date()).toISOString(),
25398
- idFactory: () => `goal-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "").slice(0, 17)}-${randomUUID24().slice(0, 8)}`,
25561
+ idFactory: () => `goal-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "").slice(0, 17)}-${randomUUID25().slice(0, 8)}`,
25399
25562
  runWorker: ({ workspace: goalWorkspace, prompt, signal }) => runLoopWorker({ workspace: goalWorkspace, prompt, signal })
25400
25563
  });
25401
25564
  let sessionHistory = await SessionHistory.open({
@@ -25666,7 +25829,7 @@ ${summary2}`;
25666
25829
  for (const key of Object.keys(subagentStartedAt)) delete subagentStartedAt[key];
25667
25830
  for (const key of Object.keys(subagentElapsedMs)) delete subagentElapsedMs[key];
25668
25831
  const previousIdeSessionId = ideSessionId;
25669
- sessionId = `session-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "").slice(0, 17)}-${randomUUID24().slice(0, 8)}`;
25832
+ sessionId = `session-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "").slice(0, 17)}-${randomUUID25().slice(0, 8)}`;
25670
25833
  hookSessionId = sessionId;
25671
25834
  harnessJournal = new HarnessJournal({ workspace, sessionId });
25672
25835
  setUsageSession(sessionId);
@@ -25767,7 +25930,7 @@ ${renderMemoryDocument(entries)}`;
25767
25930
  return `Provider "${providerName}" is missing authorizationUrl, tokenUrl, or clientId.`;
25768
25931
  }
25769
25932
  try {
25770
- const tokenStore = createFileTokenStore(join31(home, ".flavor-code", "auth.json"));
25933
+ const tokenStore = createFileTokenStore(join32(home, ".flavor-code", "auth.json"));
25771
25934
  const credentialId = oauthCredentialId(oauthConfig.tokenUrl, oauthConfig.clientId);
25772
25935
  await migrateLegacyOAuthToken(tokenStore, providerName, credentialId);
25773
25936
  const oauth = new OAuthCallbackAuthProvider({
@@ -25810,7 +25973,7 @@ ${renderMemoryDocument(entries)}`;
25810
25973
  }
25811
25974
  },
25812
25975
  async logout() {
25813
- const tokenStore = createFileTokenStore(join31(home, ".flavor-code", "auth.json"));
25976
+ const tokenStore = createFileTokenStore(join32(home, ".flavor-code", "auth.json"));
25814
25977
  const tokens2 = await tokenStore.load();
25815
25978
  const hadCredentials = Object.keys(tokens2).length > 0 || effectiveLlm !== void 0;
25816
25979
  if (!hadCredentials) {
@@ -25867,6 +26030,22 @@ ${renderMemoryDocument(entries)}`;
25867
26030
  sleepScheduler.start();
25868
26031
  }
25869
26032
  const session = new FlavorSession(services);
26033
+ if (pluginHost.loadedPlugins.some((plugin) => plugin.name === "flavor-island")) {
26034
+ try {
26035
+ islandControlServer = await createIslandControlServer({
26036
+ sessionId,
26037
+ session,
26038
+ ...options.islandControl?.focus === void 0 ? {} : { focus: options.islandControl.focus }
26039
+ });
26040
+ islandControlMetadata = {
26041
+ endpoint: islandControlServer.endpoint,
26042
+ token: islandControlServer.token,
26043
+ capabilities: islandControlServer.capabilities
26044
+ };
26045
+ } catch (error) {
26046
+ diagnostics.push(`Flavor Island control channel unavailable: ${message(error)}`);
26047
+ }
26048
+ }
25870
26049
  collaborationSession = session;
25871
26050
  pumpCollaborationEvents();
25872
26051
  const authorization = {
@@ -25902,6 +26081,7 @@ ${renderMemoryDocument(entries)}`;
25902
26081
  if (persistTail !== void 0) await boundedStep(stepTimeoutMs, diagnostics, "persist-tail", persistTail);
25903
26082
  if (ideSessionId !== void 0) await boundedStep(stepTimeoutMs, diagnostics, "ide-end-session", ide.endSession(ideSessionId));
25904
26083
  if (executionEnvironment !== void 0) await boundedStep(stepTimeoutMs, diagnostics, "execution-environment", executionEnvironment.dispose());
26084
+ if (islandControlServer !== void 0) await boundedStep(stepTimeoutMs, diagnostics, "island-control", islandControlServer.close());
25905
26085
  terminals.dispose();
25906
26086
  await boundedStep(stepTimeoutMs, diagnostics, "jobs", jobs.dispose());
25907
26087
  auditLogger.close();
@@ -25915,6 +26095,7 @@ ${renderMemoryDocument(entries)}`;
25915
26095
  collaborationEventsOpen = false;
25916
26096
  mcpDiscarded = true;
25917
26097
  memoryReviews.dispose();
26098
+ await islandControlServer?.close().catch(() => void 0);
25918
26099
  try {
25919
26100
  const stepTimeoutMs = options.shutdownStepTimeoutMs ?? DEFAULT_SHUTDOWN_STEP_TIMEOUT_MS;
25920
26101
  if (ideSessionId !== void 0) await boundedStep(stepTimeoutMs, diagnostics, "ide-end-session", ide.endSession(ideSessionId));
@@ -26052,7 +26233,7 @@ function terminalProgressState(status) {
26052
26233
  return "failed";
26053
26234
  }
26054
26235
  async function workspaceFingerprint(workspace) {
26055
- const hash = createHash20("sha256");
26236
+ const hash = createHash21("sha256");
26056
26237
  const diff = await execFileNoThrow(
26057
26238
  "git",
26058
26239
  ["-C", workspace, "diff", "--no-ext-diff", "--binary", "HEAD"],
@@ -26287,7 +26468,7 @@ async function registerConfiguredAdapters(providers, registry, environment, diag
26287
26468
  const configured = { ...providers };
26288
26469
  if (configured.openai === void 0 && environment.OPENAI_API_KEY) configured.openai = { type: "openai", apiKey: environment.OPENAI_API_KEY };
26289
26470
  if (configured.anthropic === void 0 && environment.ANTHROPIC_API_KEY) configured.anthropic = { type: "anthropic", apiKey: environment.ANTHROPIC_API_KEY };
26290
- const oauthTokenStore = createFileTokenStore(join31(home, ".flavor-code", "auth.json"));
26471
+ const oauthTokenStore = createFileTokenStore(join32(home, ".flavor-code", "auth.json"));
26291
26472
  const registered = [];
26292
26473
  let effectiveLlm;
26293
26474
  for (const [name, provider] of Object.entries(configured)) {
@@ -26706,21 +26887,21 @@ async function* runGoalSession(orchestrator, goal, signal) {
26706
26887
  }
26707
26888
  function memoryTranscriptHash(messages) {
26708
26889
  const visible = messages.filter((item) => item.role === "user" || item.role === "assistant").map((item) => `${item.role}\0${modelContentText(item.content).trim()}`).join("\n");
26709
- return createHash20("sha256").update(visible, "utf8").digest("hex");
26890
+ return createHash21("sha256").update(visible, "utf8").digest("hex");
26710
26891
  }
26711
26892
  function createMemoryTaskId() {
26712
- return `memory-${randomUUID24()}`;
26893
+ return `memory-${randomUUID25()}`;
26713
26894
  }
26714
26895
 
26715
26896
  // src/desktop/runtime-controller.ts
26716
- import { createHash as createHash26 } from "crypto";
26897
+ import { createHash as createHash27 } from "crypto";
26717
26898
  import { mkdir as mkdir27, readFile as readFile35, readdir as readdir12, rm as rm15, stat as stat14, writeFile as writeFile17 } from "fs/promises";
26718
26899
  import { homedir as homedir4 } from "os";
26719
- import { basename as basename9, join as join41, resolve as resolve35 } from "path";
26900
+ import { basename as basename9, join as join42, resolve as resolve35 } from "path";
26720
26901
 
26721
26902
  // src/d2c/workflow.ts
26722
- import { createHash as createHash21 } from "crypto";
26723
- import { join as join32 } from "path";
26903
+ import { createHash as createHash22 } from "crypto";
26904
+ import { join as join33 } from "path";
26724
26905
  import { z as z42 } from "zod";
26725
26906
 
26726
26907
  // src/d2c/workflow-shared.ts
@@ -26834,7 +27015,7 @@ function pageId(report) {
26834
27015
  return report.page?.id ?? "index";
26835
27016
  }
26836
27017
  function issueSignature(issue, kind) {
26837
- return createHash21("sha256").update(JSON.stringify({ kind, ...issue })).digest("hex");
27018
+ return createHash22("sha256").update(JSON.stringify({ kind, ...issue })).digest("hex");
26838
27019
  }
26839
27020
  function reviewsFor(report, previous) {
26840
27021
  const prior = new Map(previous?.reviews.map((item) => [`${item.pageId}:${item.fingerprint}`, item]) ?? []);
@@ -26866,7 +27047,7 @@ function reviewsFor(report, previous) {
26866
27047
  function implementationDirectory(report) {
26867
27048
  const source = report.implementation.source;
26868
27049
  if (!/^https?:\/\//i.test(source)) return source;
26869
- return join32("src", "d2c-output", report.task);
27050
+ return join33("src", "d2c-output", report.task);
26870
27051
  }
26871
27052
  function createWorkflow(report, framework) {
26872
27053
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -26990,7 +27171,7 @@ function applyQualityIssueDecision(workflow, issueId2, decision) {
26990
27171
  };
26991
27172
  }
26992
27173
  function workflowPath(workspace, task) {
26993
- return join32(taskDir(workspace, task), "workflow.json");
27174
+ return join33(taskDir(workspace, task), "workflow.json");
26994
27175
  }
26995
27176
  async function readWorkflow(workspace, task) {
26996
27177
  return (await readRecoverableFile(workflowPath(workspace, task), decodeWorkflow))?.value;
@@ -27244,7 +27425,7 @@ function confirmApiMapping(mapping, operationKey, operations) {
27244
27425
 
27245
27426
  // src/d2c/modules.ts
27246
27427
  import { readFile as readFile28 } from "fs/promises";
27247
- import { isAbsolute as isAbsolute15, join as join33, normalize as normalize2, posix, sep as sep24, win32 as win322 } from "path";
27428
+ import { isAbsolute as isAbsolute15, join as join34, normalize as normalize2, posix, sep as sep24, win32 as win322 } from "path";
27248
27429
  import { z as z43 } from "zod";
27249
27430
  var ModuleSchema = z43.object({
27250
27431
  id: z43.string().regex(/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/),
@@ -27263,13 +27444,13 @@ function safeSource(path) {
27263
27444
  }
27264
27445
  function d2cOutputDirectory(workspace, task) {
27265
27446
  if (!D2C_TASK_PATTERN.test(task)) throw new Error(`Invalid D2C task: ${task}`);
27266
- return join33(workspace, "src", "d2c-output", task);
27447
+ return join34(workspace, "src", "d2c-output", task);
27267
27448
  }
27268
27449
  async function readD2cModules(workspace, task) {
27269
27450
  const project = d2cOutputDirectory(workspace, task);
27270
27451
  let raw;
27271
27452
  try {
27272
- raw = await readFile28(join33(project, "d2c.modules.json"), "utf8");
27453
+ raw = await readFile28(join34(project, "d2c.modules.json"), "utf8");
27273
27454
  } catch {
27274
27455
  return [{ id: "page", label: task, sourceFiles: ["src/App.vue", "src/App.jsx"], keywords: [task] }];
27275
27456
  }
@@ -27290,7 +27471,7 @@ async function readD2cModules(workspace, task) {
27290
27471
 
27291
27472
  // src/d2c/integration.ts
27292
27473
  import { mkdir as mkdir24, readFile as readFile29, writeFile as writeFile13 } from "fs/promises";
27293
- import { join as join34 } from "path";
27474
+ import { join as join35 } from "path";
27294
27475
  function record2(value) {
27295
27476
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
27296
27477
  }
@@ -27426,7 +27607,7 @@ async def reset_acceptance(request: Request):
27426
27607
  }
27427
27608
  async function generateIntegrationArtifacts(projectDir, document, mappings, options = {}) {
27428
27609
  if (mappings.some((mapping) => mapping.status === "needs-confirmation")) throw new Error("Confirm every uncertain OpenAPI mapping before generating integration code");
27429
- const packagePath = join34(projectDir, "package.json");
27610
+ const packagePath = join35(projectDir, "package.json");
27430
27611
  let pkg;
27431
27612
  try {
27432
27613
  pkg = JSON.parse(await readFile29(packagePath, "utf8"));
@@ -27436,9 +27617,9 @@ async function generateIntegrationArtifacts(projectDir, document, mappings, opti
27436
27617
  const scripts = options.pythonServer ? { ...record2(pkg.scripts) ?? {} } : { ...record2(pkg.scripts) ?? {}, mock: "node mock/server.mjs" };
27437
27618
  const dependencies2 = options.pythonServer ? { ...record2(pkg.dependencies) ?? {}, axios: "^1.7.9" } : { ...record2(pkg.dependencies) ?? {}, axios: "^1.7.9", express: "^5.2.1" };
27438
27619
  const selected = [...new Set(mappings.map((mapping) => mapping.operationKey))].map((key) => document.operations.find((operation) => operation.id === key)).filter((operation) => operation !== void 0);
27439
- const apiDir = join34(projectDir, "src", "api");
27440
- const mockDir = join34(projectDir, "mock");
27441
- const serverDir = join34(projectDir, "server");
27620
+ const apiDir = join35(projectDir, "src", "api");
27621
+ const mockDir = join35(projectDir, "mock");
27622
+ const serverDir = join35(projectDir, "server");
27442
27623
  await Promise.all([
27443
27624
  mkdir24(apiDir, { recursive: true }),
27444
27625
  ...options.pythonServer ? [] : [mkdir24(mockDir, { recursive: true })],
@@ -27448,23 +27629,23 @@ async function generateIntegrationArtifacts(projectDir, document, mappings, opti
27448
27629
  if (options.pythonServer) files.push("server/main.py", "server/requirements.txt", "server/README.md", "server/flavor-runtime.json");
27449
27630
  else files.push("mock/server.mjs");
27450
27631
  await Promise.all([
27451
- writeFile13(join34(apiDir, "http.js"), `import axios from "axios";
27632
+ writeFile13(join35(apiDir, "http.js"), `import axios from "axios";
27452
27633
 
27453
27634
  export const http = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL || ${JSON.stringify(document.baseUrl ?? "")}, timeout: 15000 });
27454
27635
 
27455
27636
  http.interceptors.response.use((response) => response, (error) => Promise.reject({ name: "ApiError", status: error.response?.status, message: error.response?.data?.message || error.message, cause: error }));
27456
27637
  `),
27457
- writeFile13(join34(apiDir, "d2c-api.js"), apiModule(selected)),
27458
- writeFile13(join34(apiDir, "d2c-bindings.json"), `${JSON.stringify({ schema: 1, generatedAt: (/* @__PURE__ */ new Date()).toISOString(), mappings }, null, 2)}
27638
+ writeFile13(join35(apiDir, "d2c-api.js"), apiModule(selected)),
27639
+ writeFile13(join35(apiDir, "d2c-bindings.json"), `${JSON.stringify({ schema: 1, generatedAt: (/* @__PURE__ */ new Date()).toISOString(), mappings }, null, 2)}
27459
27640
  `),
27460
- ...options.pythonServer ? [] : [writeFile13(join34(mockDir, "server.mjs"), mockModule({ ...document, operations: selected }))],
27641
+ ...options.pythonServer ? [] : [writeFile13(join35(mockDir, "server.mjs"), mockModule({ ...document, operations: selected }))],
27461
27642
  writeFile13(packagePath, `${JSON.stringify({ ...pkg, scripts, dependencies: dependencies2 }, null, 2)}
27462
27643
  `),
27463
27644
  ...options.pythonServer ? [
27464
- writeFile13(join34(serverDir, "main.py"), pythonServerModule({ ...document, operations: selected })),
27465
- writeFile13(join34(serverDir, "requirements.txt"), "fastapi>=0.116,<1\nuvicorn[standard]>=0.35,<1\nsqlalchemy>=2.0,<3\n"),
27466
- writeFile13(join34(serverDir, "README.md"), "# Python API service\n\nThis is the real integration service, not a mock. Development defaults to SQLite through `DATABASE_URL=sqlite:///./data/app.db`. Set the same environment variable to a SQLAlchemy MySQL or PostgreSQL URL for deployment; keep schema changes in migrations instead of database-specific SQL. Flavor Code starts the service automatically for acceptance.\n"),
27467
- writeFile13(join34(serverDir, "flavor-runtime.json"), `${JSON.stringify({
27645
+ writeFile13(join35(serverDir, "main.py"), pythonServerModule({ ...document, operations: selected })),
27646
+ writeFile13(join35(serverDir, "requirements.txt"), "fastapi>=0.116,<1\nuvicorn[standard]>=0.35,<1\nsqlalchemy>=2.0,<3\n"),
27647
+ writeFile13(join35(serverDir, "README.md"), "# Python API service\n\nThis is the real integration service, not a mock. Development defaults to SQLite through `DATABASE_URL=sqlite:///./data/app.db`. Set the same environment variable to a SQLAlchemy MySQL or PostgreSQL URL for deployment; keep schema changes in migrations instead of database-specific SQL. Flavor Code starts the service automatically for acceptance.\n"),
27648
+ writeFile13(join35(serverDir, "flavor-runtime.json"), `${JSON.stringify({
27468
27649
  schema: 1,
27469
27650
  kind: "python-fastapi",
27470
27651
  cwd: "server",
@@ -27484,8 +27665,8 @@ http.interceptors.response.use((response) => response, (error) => Promise.reject
27484
27665
  // src/d2c/mock-runner.ts
27485
27666
  import { spawn as spawn8 } from "child_process";
27486
27667
  import { access as access3, readFile as readFile30 } from "fs/promises";
27487
- import { createServer as createServer4 } from "net";
27488
- import { join as join35 } from "path";
27668
+ import { createServer as createServer5 } from "net";
27669
+ import { join as join36 } from "path";
27489
27670
  async function exists3(path) {
27490
27671
  try {
27491
27672
  await access3(path);
@@ -27496,7 +27677,7 @@ async function exists3(path) {
27496
27677
  }
27497
27678
  async function port() {
27498
27679
  return new Promise((resolvePromise, rejectPromise) => {
27499
- const server = createServer4();
27680
+ const server = createServer5();
27500
27681
  server.once("error", rejectPromise);
27501
27682
  server.listen(0, "127.0.0.1", () => {
27502
27683
  const address = server.address();
@@ -27593,7 +27774,7 @@ ${output.trim()}` : ""}`);
27593
27774
  }
27594
27775
  }
27595
27776
  async function runPythonBackend(projectDir, options) {
27596
- const serverDir = join35(projectDir, "server");
27777
+ const serverDir = join36(projectDir, "server");
27597
27778
  if (options.installDependencies !== false) await installPython(serverDir, options.signal);
27598
27779
  const selectedPort = await port();
27599
27780
  const url = `http://127.0.0.1:${selectedPort}`;
@@ -27639,7 +27820,7 @@ ${managed.output().slice(-4e3)}`);
27639
27820
  };
27640
27821
  }
27641
27822
  async function runD2cMockServer(projectDir, options = {}) {
27642
- const runtimePath = join35(projectDir, "server", "flavor-runtime.json");
27823
+ const runtimePath = join36(projectDir, "server", "flavor-runtime.json");
27643
27824
  if (await exists3(runtimePath)) {
27644
27825
  let runtime;
27645
27826
  try {
@@ -27650,9 +27831,9 @@ async function runD2cMockServer(projectDir, options = {}) {
27650
27831
  if (runtime.schema !== 1 || runtime.kind !== "python-fastapi") throw new Error("Unsupported E2E backend runtime manifest");
27651
27832
  return runPythonBackend(projectDir, options);
27652
27833
  }
27653
- const serverPath = join35(projectDir, "mock", "server.mjs");
27834
+ const serverPath = join36(projectDir, "mock", "server.mjs");
27654
27835
  if (!await exists3(serverPath)) throw new Error(`D2C mock server is not generated at ${serverPath}`);
27655
- if (options.installDependencies === false && !await exists3(join35(projectDir, "node_modules", "express", "package.json"))) {
27836
+ if (options.installDependencies === false && !await exists3(join36(projectDir, "node_modules", "express", "package.json"))) {
27656
27837
  throw new Error("D2C mock server dependencies are not installed");
27657
27838
  }
27658
27839
  if (options.installDependencies !== false) await install(projectDir, options.signal);
@@ -27693,16 +27874,16 @@ ${managed.output().slice(-4e3)}`);
27693
27874
  }
27694
27875
 
27695
27876
  // src/d2c/product.ts
27696
- import { createHash as createHash23, randomUUID as randomUUID26 } from "crypto";
27697
- import { copyFile as copyFile2, mkdir as mkdir25, readFile as readFile32, rename as rename13, stat as stat12, unlink as unlink6, writeFile as writeFile15 } from "fs/promises";
27698
- import { join as join36 } from "path";
27877
+ import { createHash as createHash24, randomUUID as randomUUID27 } from "crypto";
27878
+ import { copyFile as copyFile2, mkdir as mkdir25, readFile as readFile32, rename as rename13, stat as stat12, unlink as unlink7, writeFile as writeFile15 } from "fs/promises";
27879
+ import { join as join37 } from "path";
27699
27880
  import { z as z44 } from "zod";
27700
27881
 
27701
27882
  // src/e2e/prd-governance.ts
27702
- import { createHash as createHash22, randomUUID as randomUUID25 } from "crypto";
27883
+ import { createHash as createHash23, randomUUID as randomUUID26 } from "crypto";
27703
27884
  import { readFile as readFile31, rename as rename12, rm as rm13, writeFile as writeFile14 } from "fs/promises";
27704
27885
  function hashPrd(markdown) {
27705
- return createHash22("sha256").update(markdown, "utf8").digest("hex");
27886
+ return createHash23("sha256").update(markdown, "utf8").digest("hex");
27706
27887
  }
27707
27888
  function parsePrdSections(markdown) {
27708
27889
  const headings = [...markdown.matchAll(/^(#{2,6})[ \t]+(.+?)[ \t]*$/gm)];
@@ -27799,7 +27980,7 @@ ${body}
27799
27980
 
27800
27981
  `;
27801
27982
  const markdown = `${current.slice(0, section.contentStart)}${replacement}${current.slice(section.contentEnd)}`;
27802
- const temporary = `${path}.${process.pid}.${randomUUID25()}.tmp`;
27983
+ const temporary = `${path}.${process.pid}.${randomUUID26()}.tmp`;
27803
27984
  try {
27804
27985
  await writeFile14(temporary, markdown, { encoding: "utf8", flag: "wx", mode: 384 });
27805
27986
  await rename12(temporary, path);
@@ -27813,7 +27994,7 @@ ${body}
27813
27994
  var RelativePrdPath = "product/prd.md";
27814
27995
  var RelativePrototypePath = "product/prototype/index.html";
27815
27996
  var RelativeInteractionPath = "product/prototype/interaction-manifest.json";
27816
- var defaultPlanFileOperations = { rename: rename13, copyFile: copyFile2, unlink: unlink6 };
27997
+ var defaultPlanFileOperations = { rename: rename13, copyFile: copyFile2, unlink: unlink7 };
27817
27998
  var planWriteQueues = /* @__PURE__ */ new Map();
27818
27999
  var PlanSchema2 = z44.object({
27819
28000
  schema: z44.literal(1),
@@ -27850,13 +28031,13 @@ var PlanSchema2 = z44.object({
27850
28031
  }).strict();
27851
28032
  function d2cProductDirectory(workspace, task) {
27852
28033
  if (!D2C_TASK_PATTERN.test(task)) throw new Error("Invalid D2C task name");
27853
- return join36(taskDir(workspace, task), "product");
28034
+ return join37(taskDir(workspace, task), "product");
27854
28035
  }
27855
28036
  function d2cProductPrototypeDirectory(workspace, task) {
27856
- return join36(d2cProductDirectory(workspace, task), "prototype");
28037
+ return join37(d2cProductDirectory(workspace, task), "prototype");
27857
28038
  }
27858
28039
  function planPath(workspace, task) {
27859
- return join36(taskDir(workspace, task), "product-plan.json");
28040
+ return join37(taskDir(workspace, task), "product-plan.json");
27860
28041
  }
27861
28042
  function resolveD2cProductTechnology(requirement, fallbackFramework = "vue") {
27862
28043
  const frontendCandidates = [
@@ -27952,7 +28133,7 @@ async function fileHash(path) {
27952
28133
  if (error.code === "ENOENT") return void 0;
27953
28134
  throw error;
27954
28135
  });
27955
- return buffer === void 0 ? void 0 : createHash23("sha256").update(buffer).digest("hex");
28136
+ return buffer === void 0 ? void 0 : createHash24("sha256").update(buffer).digest("hex");
27956
28137
  }
27957
28138
  async function validateAndNormalizePrototypeManifest(path) {
27958
28139
  const raw = await readFile32(path, "utf8").catch((error) => {
@@ -27999,7 +28180,7 @@ async function writeD2cProductPlan(workspace, plan, operations = defaultPlanFile
27999
28180
  const target = planPath(workspace, parsed.task);
28000
28181
  await serializePlanWrite(target, async () => {
28001
28182
  await mkdir25(taskDir(workspace, parsed.task), { recursive: true });
28002
- const temporary = `${target}.${process.pid}.${randomUUID26()}.tmp`;
28183
+ const temporary = `${target}.${process.pid}.${randomUUID27()}.tmp`;
28003
28184
  await writeFile15(temporary, `${JSON.stringify(parsed, null, 2)}
28004
28185
  `, { encoding: "utf8", mode: 384 });
28005
28186
  await replaceD2cProductPlanFile(temporary, target, operations);
@@ -28039,16 +28220,16 @@ async function readD2cProductPlan(workspace, task) {
28039
28220
  }
28040
28221
  async function discoverD2cProductArtifacts(workspace, plan) {
28041
28222
  const product = d2cProductDirectory(workspace, plan.task);
28042
- const prdUpdatedAt = await fileTimestamp(join36(product, "prd.md"));
28043
- const prdHash = await fileHash(join36(product, "prd.md"));
28044
- const prototypeUpdatedAt = await fileTimestamp(join36(product, "prototype", "index.html"));
28045
- const prototypeHash = await fileHash(join36(product, "prototype", "index.html"));
28046
- const expectedManifest = join36(product, "prototype", "interaction-manifest.json");
28223
+ const prdUpdatedAt = await fileTimestamp(join37(product, "prd.md"));
28224
+ const prdHash = await fileHash(join37(product, "prd.md"));
28225
+ const prototypeUpdatedAt = await fileTimestamp(join37(product, "prototype", "index.html"));
28226
+ const prototypeHash = await fileHash(join37(product, "prototype", "index.html"));
28227
+ const expectedManifest = join37(product, "prototype", "interaction-manifest.json");
28047
28228
  let manifestUpdatedAt = await fileTimestamp(expectedManifest);
28048
28229
  if (manifestUpdatedAt === void 0) {
28049
- const misplacedManifest = join36(product, "interaction-manifest.json");
28230
+ const misplacedManifest = join37(product, "interaction-manifest.json");
28050
28231
  if (await fileTimestamp(misplacedManifest) !== void 0) {
28051
- await mkdir25(join36(product, "prototype"), { recursive: true });
28232
+ await mkdir25(join37(product, "prototype"), { recursive: true });
28052
28233
  await copyFile2(misplacedManifest, expectedManifest);
28053
28234
  manifestUpdatedAt = await fileTimestamp(expectedManifest);
28054
28235
  }
@@ -28081,8 +28262,8 @@ async function readD2cProductPlanView(workspace, task) {
28081
28262
  if (stored === void 0) return void 0;
28082
28263
  const plan = await discoverD2cProductArtifacts(workspace, stored);
28083
28264
  if (plan.revision !== stored.revision) await writeD2cProductPlan(workspace, plan);
28084
- const prdMarkdown = plan.prd === void 0 ? void 0 : await readFile32(join36(taskDir(workspace, task), plan.prd.path), "utf8");
28085
- const manifestPath = join36(d2cProductDirectory(workspace, task), "prototype", "interaction-manifest.json");
28265
+ const prdMarkdown = plan.prd === void 0 ? void 0 : await readFile32(join37(taskDir(workspace, task), plan.prd.path), "utf8");
28266
+ const manifestPath = join37(d2cProductDirectory(workspace, task), "prototype", "interaction-manifest.json");
28086
28267
  const validationError = plan.phase === "design-generating" && await fileTimestamp(manifestPath) !== void 0 ? await validateAndNormalizePrototypeManifest(manifestPath) : void 0;
28087
28268
  return {
28088
28269
  plan,
@@ -28171,11 +28352,11 @@ ${prdMarkdown.slice(0, 2e4)}`
28171
28352
  }
28172
28353
 
28173
28354
  // src/e2e/acceptance-baseline.ts
28174
- import { createHash as createHash24 } from "crypto";
28355
+ import { createHash as createHash25 } from "crypto";
28175
28356
  import { readFile as readFile33 } from "fs/promises";
28176
28357
  async function fileArtifact(path) {
28177
28358
  const content = await readFile33(path);
28178
- return { path, hash: createHash24("sha256").update(content).digest("hex"), bytes: content.byteLength };
28359
+ return { path, hash: createHash25("sha256").update(content).digest("hex"), bytes: content.byteLength };
28179
28360
  }
28180
28361
  async function verifyAcceptanceArtifact(path, expected, label) {
28181
28362
  const current = await fileArtifact(path);
@@ -28240,8 +28421,8 @@ function createAcceptanceEvidence(coverage, run, now = /* @__PURE__ */ new Date(
28240
28421
  }
28241
28422
 
28242
28423
  // src/e2e/delivery-run.ts
28243
- import { createHash as createHash25 } from "crypto";
28244
- import { join as join37 } from "path";
28424
+ import { createHash as createHash26 } from "crypto";
28425
+ import { join as join38 } from "path";
28245
28426
  import { z as z45 } from "zod";
28246
28427
  var DELIVERY_NODE_IDS = ["requirement", "prd", "design", "d2c", "api", "acceptance", "delivery"];
28247
28428
  var ArtifactSchema = z45.object({
@@ -28279,7 +28460,7 @@ var dependencies = {
28279
28460
  };
28280
28461
  function artifactRef(path, content, now = /* @__PURE__ */ new Date()) {
28281
28462
  const bytes = typeof content === "string" ? Buffer.from(content, "utf8") : Buffer.from(content);
28282
- return { path, hash: createHash25("sha256").update(bytes).digest("hex"), bytes: bytes.byteLength, createdAt: now.toISOString() };
28463
+ return { path, hash: createHash26("sha256").update(bytes).digest("hex"), bytes: bytes.byteLength, createdAt: now.toISOString() };
28283
28464
  }
28284
28465
  function emptyNode(id) {
28285
28466
  return { id, status: "pending", attempt: 0, inputs: [], outputs: [] };
@@ -28358,7 +28539,7 @@ function completeDeliveryNode(run, node, outputs, now = /* @__PURE__ */ new Date
28358
28539
  return { ...run, nodes, updatedAt: timestamp2 };
28359
28540
  }
28360
28541
  function deliveryRunPath(workspace, task) {
28361
- return join37(taskDir(workspace, task), "delivery-run.json");
28542
+ return join38(taskDir(workspace, task), "delivery-run.json");
28362
28543
  }
28363
28544
  function decodeDeliveryRun(raw) {
28364
28545
  return DeliveryRunSchema.parse(JSON.parse(raw));
@@ -28401,7 +28582,7 @@ async function updateDeliveryRun(workspace, task, expectedRevision, mutation) {
28401
28582
  // src/skills/manager.ts
28402
28583
  import { lstat as lstat13, mkdir as mkdir26, readFile as readFile34, readdir as readdir11, realpath as realpath13, rm as rm14, writeFile as writeFile16 } from "fs/promises";
28403
28584
  import { homedir as homedir3 } from "os";
28404
- import { isAbsolute as isAbsolute16, join as join38, relative as relative24, resolve as resolve33, sep as sep25 } from "path";
28585
+ import { isAbsolute as isAbsolute16, join as join39, relative as relative24, resolve as resolve33, sep as sep25 } from "path";
28405
28586
  import { stringify } from "yaml";
28406
28587
  var SkillManager = class {
28407
28588
  #workspace;
@@ -28424,7 +28605,7 @@ var SkillManager = class {
28424
28605
  async create(draft) {
28425
28606
  const value = parseDraft(draft);
28426
28607
  const projectRoot = this.#projectRoot();
28427
- const directory = join38(projectRoot, value.name);
28608
+ const directory = join39(projectRoot, value.name);
28428
28609
  await mkdir26(projectRoot, { recursive: true, mode: 448 });
28429
28610
  try {
28430
28611
  await mkdir26(directory, { mode: 448 });
@@ -28433,7 +28614,7 @@ var SkillManager = class {
28433
28614
  throw error;
28434
28615
  }
28435
28616
  try {
28436
- await writeFile16(join38(directory, "SKILL.md"), renderSkill(value), { encoding: "utf8", flag: "wx", mode: 384 });
28617
+ await writeFile16(join39(directory, "SKILL.md"), renderSkill(value), { encoding: "utf8", flag: "wx", mode: 384 });
28437
28618
  await this.#persistEnabled(value.name, true);
28438
28619
  return this.get(value.name);
28439
28620
  } catch (error) {
@@ -28451,7 +28632,7 @@ var SkillManager = class {
28451
28632
  throw error;
28452
28633
  });
28453
28634
  if (!info.isDirectory() || info.isSymbolicLink()) throw new Error(`Project skill path is not a real directory: ${validName}`);
28454
- const skillFile = join38(directory, "SKILL.md");
28635
+ const skillFile = join39(directory, "SKILL.md");
28455
28636
  const fileInfo = await lstat13(skillFile);
28456
28637
  if (!fileInfo.isFile() || fileInfo.isSymbolicLink()) throw new Error(`Project skill file is not a real file: ${validName}`);
28457
28638
  await writeFile16(skillFile, renderSkill(value), { encoding: "utf8", mode: 384 });
@@ -28483,12 +28664,12 @@ var SkillManager = class {
28483
28664
  async #registry() {
28484
28665
  const loaded = await loadConfig({ cwd: this.#workspace, home: this.#home });
28485
28666
  const [globalPluginRoots, projectPluginRoots] = await Promise.all([
28486
- discoverPluginSkillRoots(join38(this.#home, ".flavor-code", "plugins")),
28487
- discoverPluginSkillRoots(join38(this.#workspace, ".flavor", "plugins"))
28667
+ discoverPluginSkillRoots(join39(this.#home, ".flavor-code", "plugins")),
28668
+ discoverPluginSkillRoots(join39(this.#workspace, ".flavor", "plugins"))
28488
28669
  ]);
28489
28670
  return {
28490
28671
  registry: new SkillRegistry({
28491
- globalRoots: [join38(this.#home, ".flavor-code", "skills"), ...globalPluginRoots],
28672
+ globalRoots: [join39(this.#home, ".flavor-code", "skills"), ...globalPluginRoots],
28492
28673
  projectRoots: [this.#projectRoot(), ...projectPluginRoots]
28493
28674
  }),
28494
28675
  disabled: new Set(loaded.config.skills.disabled)
@@ -28504,10 +28685,10 @@ var SkillManager = class {
28504
28685
  };
28505
28686
  }
28506
28687
  #projectRoot() {
28507
- return join38(this.#workspace, ".flavor", "skills");
28688
+ return join39(this.#workspace, ".flavor", "skills");
28508
28689
  }
28509
28690
  #projectSkillDirectory(name) {
28510
- return join38(this.#projectRoot(), name);
28691
+ return join39(this.#projectRoot(), name);
28511
28692
  }
28512
28693
  };
28513
28694
  function parseName(value) {
@@ -28548,9 +28729,9 @@ async function discoverPluginSkillRoots(directory) {
28548
28729
  const roots = [];
28549
28730
  for (const entry2 of entries) {
28550
28731
  if (!entry2.isDirectory() || entry2.isSymbolicLink()) continue;
28551
- const pluginRoot = await realpath13(join38(directory, entry2.name));
28732
+ const pluginRoot = await realpath13(join39(directory, entry2.name));
28552
28733
  try {
28553
- const manifest = PluginManifestSchema.parse(JSON.parse(await readFile34(join38(pluginRoot, "flavor-plugin.json"), "utf8")));
28734
+ const manifest = PluginManifestSchema.parse(JSON.parse(await readFile34(join39(pluginRoot, "flavor-plugin.json"), "utf8")));
28554
28735
  for (const contribution of manifest.contributes.skillRoots) {
28555
28736
  const candidate = resolve33(pluginRoot, contribution.path);
28556
28737
  const info = await lstat13(candidate);
@@ -28625,11 +28806,11 @@ async function createProjectMemoryManager(options) {
28625
28806
  }
28626
28807
 
28627
28808
  // src/mcp/config-manager.ts
28628
- import { join as join39 } from "path";
28809
+ import { join as join40 } from "path";
28629
28810
  var ProjectMcpConfigManager = class {
28630
28811
  path;
28631
28812
  constructor(workspace) {
28632
- this.path = join39(workspace, ".flavor", "flavor.json");
28813
+ this.path = join40(workspace, ".flavor", "flavor.json");
28633
28814
  }
28634
28815
  async list() {
28635
28816
  const document = await readRecoverableFile(this.path, (raw) => parseDocument2(this.path, raw));
@@ -28726,7 +28907,7 @@ function isRecord7(value) {
28726
28907
  }
28727
28908
 
28728
28909
  // src/desktop/model-config.ts
28729
- import { join as join40 } from "path";
28910
+ import { join as join41 } from "path";
28730
28911
  var DEFAULT_DESKTOP_MODELS = [
28731
28912
  {
28732
28913
  id: "anthropic:deepseek-v4-pro",
@@ -28747,7 +28928,7 @@ var DEFAULT_DESKTOP_MODELS = [
28747
28928
  ];
28748
28929
  async function loadDesktopModels(workspace, home) {
28749
28930
  try {
28750
- const tokens2 = await createFileTokenStore(join40(home, ".flavor-code", "auth.json")).load();
28931
+ const tokens2 = await createFileTokenStore(join41(home, ".flavor-code", "auth.json")).load();
28751
28932
  const pkceModels = [];
28752
28933
  const knownPkce = /* @__PURE__ */ new Set();
28753
28934
  for (const token of Object.values(tokens2)) {
@@ -28816,7 +28997,7 @@ function protocolLabel(type) {
28816
28997
  // src/desktop/d2c-product-preview.ts
28817
28998
  import { createReadStream as createReadStream2 } from "fs";
28818
28999
  import { realpath as realpath14, stat as stat13 } from "fs/promises";
28819
- import { createServer as createServer5 } from "http";
29000
+ import { createServer as createServer6 } from "http";
28820
29001
  import { extname as extname3, isAbsolute as isAbsolute17, relative as relative25, resolve as resolve34, sep as sep26 } from "path";
28821
29002
  var MIME_TYPES = {
28822
29003
  ".css": "text/css; charset=utf-8",
@@ -28842,7 +29023,7 @@ async function startD2cProductPreview(rootDirectory) {
28842
29023
  const root = await realpath14(resolve34(rootDirectory));
28843
29024
  const rootInfo = await stat13(root);
28844
29025
  if (!rootInfo.isDirectory()) throw new Error("D2C product prototype directory is unavailable");
28845
- const server = createServer5(async (request, response2) => {
29026
+ const server = createServer6(async (request, response2) => {
28846
29027
  response2.setHeader("cache-control", "no-store");
28847
29028
  response2.setHeader("x-content-type-options", "nosniff");
28848
29029
  response2.setHeader("content-security-policy", "default-src 'self' data: blob:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'");
@@ -28892,37 +29073,37 @@ function pngDataUrl(png) {
28892
29073
  }
28893
29074
  async function detectD2cFramework(workspace, task) {
28894
29075
  try {
28895
- const pkg = JSON.parse(await readFile35(join41(d2cOutputDirectory(workspace, task), "package.json"), "utf8"));
29076
+ const pkg = JSON.parse(await readFile35(join42(d2cOutputDirectory(workspace, task), "package.json"), "utf8"));
28896
29077
  return pkg.dependencies?.react === void 0 ? "vue" : "react";
28897
29078
  } catch {
28898
29079
  return "vue";
28899
29080
  }
28900
29081
  }
28901
29082
  function integrationDirectory(workspace, task) {
28902
- return join41(workspace, ".flavor", "d2c", task, "integration");
29083
+ return join42(workspace, ".flavor", "d2c", task, "integration");
28903
29084
  }
28904
29085
  var D2C_BACKEND_SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".cfg", ".env", ".ini", ".js", ".json", ".lock", ".mjs", ".py", ".toml", ".txt", ".yaml", ".yml"]);
28905
29086
  var D2C_BACKEND_IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([".git", ".venv", "__pycache__", "data", "node_modules", "venv"]);
28906
29087
  async function d2cBackendSourceFingerprint(project) {
28907
- const runtimeManifest = join41(project, "server", "flavor-runtime.json");
29088
+ const runtimeManifest = join42(project, "server", "flavor-runtime.json");
28908
29089
  const realBackend = (await stat14(runtimeManifest).catch(() => void 0))?.isFile() === true;
28909
- const root = realBackend ? join41(project, "server") : join41(project, "mock");
29090
+ const root = realBackend ? join42(project, "server") : join42(project, "mock");
28910
29091
  if ((await stat14(root).catch(() => void 0))?.isDirectory() !== true) return void 0;
28911
29092
  const files = [];
28912
29093
  const visit = async (directory) => {
28913
29094
  const entries = await readdir12(directory, { withFileTypes: true });
28914
29095
  for (const entry2 of entries) {
28915
29096
  if (entry2.isDirectory()) {
28916
- if (!D2C_BACKEND_IGNORED_DIRECTORIES.has(entry2.name)) await visit(join41(directory, entry2.name));
29097
+ if (!D2C_BACKEND_IGNORED_DIRECTORIES.has(entry2.name)) await visit(join42(directory, entry2.name));
28917
29098
  continue;
28918
29099
  }
28919
29100
  if (!entry2.isFile()) continue;
28920
29101
  const extension2 = entry2.name.includes(".") ? `.${entry2.name.split(".").pop().toLowerCase()}` : "";
28921
- if (D2C_BACKEND_SOURCE_EXTENSIONS.has(extension2)) files.push(join41(directory, entry2.name));
29102
+ if (D2C_BACKEND_SOURCE_EXTENSIONS.has(extension2)) files.push(join42(directory, entry2.name));
28922
29103
  }
28923
29104
  };
28924
29105
  await visit(root);
28925
- const hash = createHash26("sha256");
29106
+ const hash = createHash27("sha256");
28926
29107
  for (const path of files.sort()) {
28927
29108
  hash.update(path.slice(root.length));
28928
29109
  hash.update("\0");
@@ -29468,7 +29649,7 @@ var DesktopRuntimeController = class {
29468
29649
  if (workflow === void 0 || !reviewProgress(workflow).complete || workflow.stage === "visual-review") {
29469
29650
  throw new Error("Complete visual review before importing OpenAPI");
29470
29651
  }
29471
- const moduleManifest = join41(d2cOutputDirectory(workspace, task), "d2c.modules.json");
29652
+ const moduleManifest = join42(d2cOutputDirectory(workspace, task), "d2c.modules.json");
29472
29653
  const moduleManifestInfo = await stat14(moduleManifest).catch(() => void 0);
29473
29654
  if (moduleManifestInfo === void 0 || !moduleManifestInfo.isFile()) {
29474
29655
  throw new Error("D2C implementation must write d2c.modules.json before API mapping; ask the agent to split the project into modules first");
@@ -29479,10 +29660,10 @@ var DesktopRuntimeController = class {
29479
29660
  const mappings = generated ? matched.map((mapping) => ({ ...mapping, status: "confirmed" })) : matched;
29480
29661
  const dir = integrationDirectory(workspace, task);
29481
29662
  await mkdir27(dir, { recursive: true });
29482
- const hash = createHash26("sha256").update(raw).digest("hex");
29663
+ const hash = createHash27("sha256").update(raw).digest("hex");
29483
29664
  await Promise.all([
29484
- writeFile17(join41(dir, "swagger.json"), raw),
29485
- writeFile17(join41(dir, "openapi.normalized.json"), `${JSON.stringify(document, null, 2)}
29665
+ writeFile17(join42(dir, "swagger.json"), raw),
29666
+ writeFile17(join42(dir, "openapi.normalized.json"), `${JSON.stringify(document, null, 2)}
29486
29667
  `)
29487
29668
  ]);
29488
29669
  const next = {
@@ -29517,7 +29698,7 @@ var DesktopRuntimeController = class {
29517
29698
  let workflow = await readWorkflow(workspace, task);
29518
29699
  if (workflow?.openapi === void 0 && workflow !== void 0 && reviewProgress(workflow).complete && await readD2cProductPlanView(workspace, task) !== void 0) {
29519
29700
  const modules = await readD2cModules(workspace, task);
29520
- const productOpenApiPath = join41(taskDir(workspace, task), "product", "openapi.json");
29701
+ const productOpenApiPath = join42(taskDir(workspace, task), "product", "openapi.json");
29521
29702
  const authored = await readFile35(productOpenApiPath, "utf8").catch(() => void 0);
29522
29703
  const generated = authored === void 0;
29523
29704
  const prepared = await this.#storeD2cOpenApi(
@@ -29530,7 +29711,7 @@ var DesktopRuntimeController = class {
29530
29711
  return prepared;
29531
29712
  }
29532
29713
  if (workflow?.openapi === void 0 || workflow.mappings === void 0) return void 0;
29533
- const document = JSON.parse(await readFile35(join41(integrationDirectory(workspace, task), "openapi.normalized.json"), "utf8"));
29714
+ const document = JSON.parse(await readFile35(join42(integrationDirectory(workspace, task), "openapi.normalized.json"), "utf8"));
29534
29715
  return { workflow, document, mappings: workflow.mappings };
29535
29716
  }
29536
29717
  async confirmD2cMapping(task, moduleId, operationKey) {
@@ -29597,7 +29778,7 @@ var DesktopRuntimeController = class {
29597
29778
  ].join("\n");
29598
29779
  const delivery = await readDeliveryRun(workspace, task);
29599
29780
  if (delivery?.nodes.api.status === "running") {
29600
- const apiArtifacts = await Promise.all(generated.files.map(async (file) => artifactRef(file, await readFile35(join41(project, file)))));
29781
+ const apiArtifacts = await Promise.all(generated.files.map(async (file) => artifactRef(file, await readFile35(join42(project, file)))));
29601
29782
  const completed = await updateDeliveryRun(
29602
29783
  workspace,
29603
29784
  task,
@@ -29624,7 +29805,7 @@ var DesktopRuntimeController = class {
29624
29805
  try {
29625
29806
  const fingerprint2 = await d2cBackendSourceFingerprint(project);
29626
29807
  if (fingerprint2 !== void 0) this.#d2cMockSourceFingerprints.set(task, fingerprint2);
29627
- const environmentPath = join41(project, ".env.local");
29808
+ const environmentPath = join42(project, ".env.local");
29628
29809
  const existingEnvironment = await readFile35(environmentPath, "utf8").catch(() => "");
29629
29810
  const environment = `${existingEnvironment.split(/\r?\n/).filter((line) => !/^\s*VITE_API_BASE_URL\s*=/.test(line)).join("\n").trim()}
29630
29811
  VITE_API_BASE_URL=${running.url}
@@ -29705,7 +29886,7 @@ VITE_API_BASE_URL=${running.url}
29705
29886
  const readyPreview = this.#d2cPreviews.get(task);
29706
29887
  const readyMock = this.#d2cMocks.get(task);
29707
29888
  if (readyPreview === void 0 || readyMock === void 0) throw new Error("D2C preview or backend service is unavailable after synchronization");
29708
- const manifestPath = join41(taskDir(workspace, task), "design", "interaction-manifest.json");
29889
+ const manifestPath = join42(taskDir(workspace, task), "design", "interaction-manifest.json");
29709
29890
  const manifest = parseInteractionManifest(await readFile35(manifestPath, "utf8"));
29710
29891
  const baseline = await this.#verifyAcceptanceBaseline(workspace, task);
29711
29892
  const coverage = baseline === void 0 ? void 0 : verifyRequirementCoverage(baseline.approvedPrd.criteria, manifest);
@@ -29717,7 +29898,7 @@ VITE_API_BASE_URL=${running.url}
29717
29898
  await mkdir27(planDir, { recursive: true });
29718
29899
  try {
29719
29900
  const observations = await this.#observeD2cPages(manifest, readyPreview.url);
29720
- const prd = await readFile35(join41(taskDir(workspace, task), "product", "prd.md"), "utf8").catch(() => void 0);
29901
+ const prd = await readFile35(join42(taskDir(workspace, task), "product", "prd.md"), "utf8").catch(() => void 0);
29721
29902
  const apiContext = JSON.stringify({ openapi: workflow.openapi, mappings: workflow.mappings }, null, 2);
29722
29903
  const plan = await this.#d2cJudge.planInteractions({ task, seed: manifest, observations, ...prd === void 0 ? {} : { prd }, apiContext });
29723
29904
  executableManifest = mergeInteractionManifests(manifest, plan.manifest);
@@ -29728,9 +29909,9 @@ VITE_API_BASE_URL=${running.url}
29728
29909
  plannedScenarios: executableManifest.pages.reduce((total, page) => total + page.scenarios.length, 0),
29729
29910
  pageAnalyses: plan.pageAnalyses
29730
29911
  };
29731
- await writeFile17(join41(planDir, "autonomous-interaction-plan.json"), `${JSON.stringify({ ...plan, manifest: executableManifest }, null, 2)}
29912
+ await writeFile17(join42(planDir, "autonomous-interaction-plan.json"), `${JSON.stringify({ ...plan, manifest: executableManifest }, null, 2)}
29732
29913
  `, { encoding: "utf8", mode: 384 });
29733
- await rm15(join41(planDir, "autonomous-interaction-diagnostic.json"), { force: true });
29914
+ await rm15(join42(planDir, "autonomous-interaction-diagnostic.json"), { force: true });
29734
29915
  } catch (cause) {
29735
29916
  const detail = message(cause);
29736
29917
  review = {
@@ -29738,8 +29919,8 @@ VITE_API_BASE_URL=${running.url}
29738
29919
  plannedScenarios: manifest.pages.reduce((total, page) => total + page.scenarios.length, 0),
29739
29920
  warning: `\u591A\u6A21\u6001\u81EA\u4E3B\u89C4\u5212\u5931\u8D25\uFF0C\u5DF2\u7EE7\u7EED\u6267\u884C\u5DF2\u786E\u8BA4\u7684\u8BBE\u8BA1\u5951\u7EA6\uFF1A${detail}`
29740
29921
  };
29741
- await rm15(join41(planDir, "autonomous-interaction-plan.json"), { force: true });
29742
- await writeFile17(join41(planDir, "autonomous-interaction-diagnostic.json"), `${JSON.stringify({
29922
+ await rm15(join42(planDir, "autonomous-interaction-plan.json"), { force: true });
29923
+ await writeFile17(join42(planDir, "autonomous-interaction-diagnostic.json"), `${JSON.stringify({
29743
29924
  schema: 1,
29744
29925
  stage: "planning",
29745
29926
  occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -29753,13 +29934,13 @@ VITE_API_BASE_URL=${running.url}
29753
29934
  let result = { ...rawResult, evidenceMode: review.mode };
29754
29935
  if (coverage !== void 0) {
29755
29936
  const evidence = createAcceptanceEvidence(coverage, result);
29756
- await writeFile17(join41(taskDir(workspace, task), "acceptance-evidence.json"), `${JSON.stringify({ ...evidence, baseline }, null, 2)}
29937
+ await writeFile17(join42(taskDir(workspace, task), "acceptance-evidence.json"), `${JSON.stringify({ ...evidence, baseline }, null, 2)}
29757
29938
  `, { encoding: "utf8", mode: 384 });
29758
29939
  if (!evidence.passed) result = { ...result, passed: false, failures: Math.max(1, result.failures) };
29759
29940
  }
29760
29941
  const dir = integrationDirectory(workspace, task);
29761
29942
  await mkdir27(dir, { recursive: true });
29762
- await writeFile17(join41(dir, "interaction-results.json"), `${JSON.stringify(result, null, 2)}
29943
+ await writeFile17(join42(dir, "interaction-results.json"), `${JSON.stringify(result, null, 2)}
29763
29944
  `);
29764
29945
  const next = await updateWorkflow(workspace, task, workflow.revision, (current) => applyInteractionRun(current, result));
29765
29946
  return { workflow: next, result, review };
@@ -29772,7 +29953,7 @@ VITE_API_BASE_URL=${running.url}
29772
29953
  if (mock === void 0 || !mock.exited() || result.failures === 0) return result;
29773
29954
  const output = mock.output().trim();
29774
29955
  try {
29775
- const dir = join41(d2cOutputDirectory(workspace, task), "mock-server.log");
29956
+ const dir = join42(d2cOutputDirectory(workspace, task), "mock-server.log");
29776
29957
  await writeFile17(dir, `${output}
29777
29958
  `);
29778
29959
  } catch {
@@ -29867,7 +30048,7 @@ VITE_API_BASE_URL=${running.url}
29867
30048
  if (current === void 0) throw new Error("D2C product plan is unavailable");
29868
30049
  if (current.plan.approvedPrd !== void 0) throw new Error("The approved PRD is immutable and cannot be edited");
29869
30050
  if (current.plan.phase !== "prd-review") throw new Error("PRD sections can only be edited during PRD review");
29870
- const path = join41(taskDir(workspace, task), "product", "prd.md");
30051
+ const path = join42(taskDir(workspace, task), "product", "prd.md");
29871
30052
  const updated = await updatePrdSectionFile(path, { sectionId, body, expectedHash });
29872
30053
  const now = (/* @__PURE__ */ new Date()).toISOString();
29873
30054
  await writeD2cProductPlan(workspace, {
@@ -29887,15 +30068,15 @@ VITE_API_BASE_URL=${running.url}
29887
30068
  async #assertProductPrdLocked(workspace, task) {
29888
30069
  const current = await readD2cProductPlanView(workspace, task);
29889
30070
  if (current?.plan.approvedPrd === void 0) return;
29890
- await assertApprovedPrd(join41(taskDir(workspace, task), "product", "prd.md"), current.plan.approvedPrd);
30071
+ await assertApprovedPrd(join42(taskDir(workspace, task), "product", "prd.md"), current.plan.approvedPrd);
29891
30072
  }
29892
30073
  async #acceptancePaths(workspace, task) {
29893
- const product = join41(taskDir(workspace, task), "product");
29894
- const openapi = join41(product, "openapi.json");
30074
+ const product = join42(taskDir(workspace, task), "product");
30075
+ const openapi = join42(product, "openapi.json");
29895
30076
  return {
29896
- prd: join41(product, "prd.md"),
29897
- prototype: join41(product, "prototype", "index.html"),
29898
- interaction: join41(product, "prototype", "interaction-manifest.json"),
30077
+ prd: join42(product, "prd.md"),
30078
+ prototype: join42(product, "prototype", "index.html"),
30079
+ interaction: join42(product, "prototype", "interaction-manifest.json"),
29899
30080
  ...await stat14(openapi).catch(() => void 0) === void 0 ? {} : { openapi }
29900
30081
  };
29901
30082
  }
@@ -29903,17 +30084,17 @@ VITE_API_BASE_URL=${running.url}
29903
30084
  const product = await readD2cProductPlanView(workspace, task);
29904
30085
  if (product?.plan.approvedPrd === void 0) return void 0;
29905
30086
  await this.#assertProductPrdLocked(workspace, task);
29906
- const baseline = JSON.parse(await readFile35(join41(taskDir(workspace, task), "acceptance-baseline.json"), "utf8"));
30087
+ const baseline = JSON.parse(await readFile35(join42(taskDir(workspace, task), "acceptance-baseline.json"), "utf8"));
29907
30088
  await verifyAcceptanceBaseline(await this.#acceptancePaths(workspace, task), baseline);
29908
- const design = join41(taskDir(workspace, task), "design");
30089
+ const design = join42(taskDir(workspace, task), "design");
29909
30090
  await Promise.all([
29910
- verifyAcceptanceArtifact(join41(design, "index.html"), baseline.artifacts.prototype, "runtime prototype"),
29911
- verifyAcceptanceArtifact(join41(design, "interaction-manifest.json"), baseline.artifacts.interaction, "runtime interaction contract")
30091
+ verifyAcceptanceArtifact(join42(design, "index.html"), baseline.artifacts.prototype, "runtime prototype"),
30092
+ verifyAcceptanceArtifact(join42(design, "interaction-manifest.json"), baseline.artifacts.interaction, "runtime interaction contract")
29912
30093
  ]);
29913
30094
  const workflow = await readWorkflow(workspace, task);
29914
30095
  if (workflow?.openapi !== void 0) {
29915
30096
  await verifyAcceptanceArtifact(
29916
- join41(taskDir(workspace, task), "integration", "swagger.json"),
30097
+ join42(taskDir(workspace, task), "integration", "swagger.json"),
29917
30098
  { hash: workflow.openapi.hash },
29918
30099
  "runtime OpenAPI contract"
29919
30100
  );
@@ -29934,14 +30115,14 @@ VITE_API_BASE_URL=${running.url}
29934
30115
  throw new Error("D2C PRD is empty and cannot be accepted");
29935
30116
  }
29936
30117
  if (stage === "design" && accepted) {
29937
- const manifest = join41(d2cProductPrototypeDirectory(workspace, task), "interaction-manifest.json");
30118
+ const manifest = join42(d2cProductPrototypeDirectory(workspace, task), "interaction-manifest.json");
29938
30119
  const normalizedManifest = parseInteractionManifest(await readFile35(manifest, "utf8"));
29939
30120
  if (current.plan.approvedPrd === void 0) throw new Error("Approve the PRD before confirming the design");
29940
30121
  verifyRequirementCoverage(current.plan.approvedPrd.criteria, normalizedManifest);
29941
30122
  await writeFile17(manifest, `${JSON.stringify(normalizedManifest, null, 2)}
29942
30123
  `, { encoding: "utf8", mode: 384 });
29943
30124
  const baseline = await captureAcceptanceBaseline(await this.#acceptancePaths(workspace, task), current.plan.approvedPrd);
29944
- await writeFile17(join41(taskDir(workspace, task), "acceptance-baseline.json"), `${JSON.stringify(baseline, null, 2)}
30125
+ await writeFile17(join42(taskDir(workspace, task), "acceptance-baseline.json"), `${JSON.stringify(baseline, null, 2)}
29945
30126
  `, { encoding: "utf8", mode: 384 });
29946
30127
  }
29947
30128
  const plan = await writeD2cProductPlan(
@@ -29975,8 +30156,8 @@ VITE_API_BASE_URL=${running.url}
29975
30156
  const imported = await this.importD2cDesign(task, d2cProductPrototypeDirectory(workspace, task));
29976
30157
  const delivery = await readDeliveryRun(workspace, task);
29977
30158
  if (delivery !== void 0) {
29978
- const prototype = await readFile35(join41(d2cProductPrototypeDirectory(workspace, task), "index.html"), "utf8");
29979
- const interaction = await readFile35(join41(d2cProductPrototypeDirectory(workspace, task), "interaction-manifest.json"), "utf8");
30159
+ const prototype = await readFile35(join42(d2cProductPrototypeDirectory(workspace, task), "index.html"), "utf8");
30160
+ const interaction = await readFile35(join42(d2cProductPrototypeDirectory(workspace, task), "interaction-manifest.json"), "utf8");
29980
30161
  const completed = await updateDeliveryRun(workspace, task, delivery.revision, (run) => completeDeliveryNode(run, "design", [
29981
30162
  artifactRef("product/prototype/index.html", prototype),
29982
30163
  artifactRef("product/prototype/interaction-manifest.json", interaction)
@@ -30060,10 +30241,10 @@ VITE_API_BASE_URL=${running.url}
30060
30241
  const next = await updateWorkflow(workspace, task, workflow.revision, (current) => applyQualityJudgment(current, judgment));
30061
30242
  const qualityContent = `${JSON.stringify(judgment, null, 2)}
30062
30243
  `;
30063
- await writeFile17(join41(taskDir(workspace, task), "quality-judge.json"), qualityContent, { encoding: "utf8", mode: 384 });
30244
+ await writeFile17(join42(taskDir(workspace, task), "quality-judge.json"), qualityContent, { encoding: "utf8", mode: 384 });
30064
30245
  const delivery = await readDeliveryRun(workspace, task);
30065
30246
  if (next.stage === "completed" && delivery?.nodes.acceptance.status === "running") {
30066
- const interactionContent = await readFile35(join41(integrationDirectory(workspace, task), "interaction-results.json"), "utf8");
30247
+ const interactionContent = await readFile35(join42(integrationDirectory(workspace, task), "interaction-results.json"), "utf8");
30067
30248
  const accepted = await updateDeliveryRun(workspace, task, delivery.revision, (run) => completeDeliveryNode(run, "acceptance", [
30068
30249
  artifactRef("integration/interaction-results.json", interactionContent),
30069
30250
  artifactRef("quality-judge.json", qualityContent)
@@ -30245,14 +30426,14 @@ function desktopWindowChrome(platform = process.platform) {
30245
30426
 
30246
30427
  // src/utils/crash-guard.ts
30247
30428
  import { mkdirSync as mkdirSync3, writeFileSync } from "fs";
30248
- import { join as join42 } from "path";
30429
+ import { join as join43 } from "path";
30249
30430
  var installed = false;
30250
30431
  function installCrashGuard(options = {}) {
30251
30432
  if (installed) return;
30252
30433
  installed = true;
30253
30434
  const crashLogDir = () => {
30254
30435
  try {
30255
- return join42((options.workspace ?? process.cwd)(), ".flavor");
30436
+ return join43((options.workspace ?? process.cwd)(), ".flavor");
30256
30437
  } catch {
30257
30438
  return process.cwd();
30258
30439
  }
@@ -30261,7 +30442,7 @@ function installCrashGuard(options = {}) {
30261
30442
  try {
30262
30443
  const dir = crashLogDir();
30263
30444
  mkdirSync3(dir, { recursive: true });
30264
- const path = join42(dir, `crash-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "")}-${process.pid}.log`);
30445
+ const path = join43(dir, `crash-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "")}-${process.pid}.log`);
30265
30446
  writeFileSync(path, [
30266
30447
  `kind: ${kind}`,
30267
30448
  `version: ${process.version}`,
@@ -30452,9 +30633,9 @@ function safeGitTarget(value) {
30452
30633
  }
30453
30634
 
30454
30635
  // src/desktop/worktree-manager.ts
30455
- import { randomUUID as randomUUID27 } from "crypto";
30636
+ import { randomUUID as randomUUID28 } from "crypto";
30456
30637
  import { mkdir as mkdir28, readFile as readFile37, readdir as readdir13, rm as rm17, stat as stat15, writeFile as writeFile18 } from "fs/promises";
30457
- import { basename as basename10, isAbsolute as isAbsolute19, join as join43, relative as relative27, resolve as resolve37, sep as sep27 } from "path";
30638
+ import { basename as basename10, isAbsolute as isAbsolute19, join as join44, relative as relative27, resolve as resolve37, sep as sep27 } from "path";
30458
30639
  var DesktopWorktreeManager = class {
30459
30640
  #repository;
30460
30641
  #storage;
@@ -30465,7 +30646,7 @@ var DesktopWorktreeManager = class {
30465
30646
  async create(label) {
30466
30647
  if (!await isGitRepository(this.#repository)) throw new Error("Task worktrees require a Git repository");
30467
30648
  const safe = label.trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 36) || "task";
30468
- const suffix = randomUUID27().slice(0, 8);
30649
+ const suffix = randomUUID28().slice(0, 8);
30469
30650
  const id = `worktree-${safe}-${suffix}`;
30470
30651
  const branch = `flavor/desktop-${safe}-${suffix}`;
30471
30652
  const path = this.#safeStoragePath(id);
@@ -30500,7 +30681,7 @@ var DesktopWorktreeManager = class {
30500
30681
  }
30501
30682
  const values = await Promise.all(names.filter((name) => name.endsWith(".json")).map(async (name) => {
30502
30683
  try {
30503
- const stored = validateStored(JSON.parse(await readFile37(join43(this.#storage, name), "utf8")), this.#repository, this.#storage);
30684
+ const stored = validateStored(JSON.parse(await readFile37(join44(this.#storage, name), "utf8")), this.#repository, this.#storage);
30504
30685
  if ((await stat15(stored.path).catch(() => void 0))?.isDirectory() !== true) return void 0;
30505
30686
  const status = await git2(stored.path, ["status", "--porcelain"]);
30506
30687
  const merged = await git2(this.#repository, ["merge-base", "--is-ancestor", stored.branch, "HEAD"]);
@@ -30564,7 +30745,7 @@ function validateStored(value, repository, storage) {
30564
30745
  // src/desktop/workbench-service.ts
30565
30746
  import { readFile as readFile38, readdir as readdir14, stat as stat16 } from "fs/promises";
30566
30747
  import { homedir as homedir5 } from "os";
30567
- import { join as join44, resolve as resolve38 } from "path";
30748
+ import { join as join45, resolve as resolve38 } from "path";
30568
30749
  var MAX_TEXT = 128e3;
30569
30750
  var MAX_ITEMS = 200;
30570
30751
  var DesktopWorkbenchService = class {
@@ -30597,11 +30778,11 @@ var DesktopWorkbenchService = class {
30597
30778
  return url.toString().replace(/\/$/, input.trim().endsWith("/") ? "/" : "");
30598
30779
  }
30599
30780
  async #goals() {
30600
- const root = join44(this.#workspace, ".flavor", "goals");
30781
+ const root = join45(this.#workspace, ".flavor", "goals");
30601
30782
  const names = await readdir14(root).catch((error) => error.code === "ENOENT" ? [] : Promise.reject(error));
30602
30783
  const values = await Promise.all(names.filter((name) => /^goal-[A-Za-z0-9._-]+\.json$/.test(name)).slice(0, MAX_ITEMS).map(async (name) => {
30603
30784
  try {
30604
- return GoalStateSchema.parse(JSON.parse(await boundedRead2(join44(root, name))));
30785
+ return GoalStateSchema.parse(JSON.parse(await boundedRead2(join45(root, name))));
30605
30786
  } catch {
30606
30787
  return void 0;
30607
30788
  }
@@ -30611,7 +30792,7 @@ var DesktopWorkbenchService = class {
30611
30792
  async #instructions() {
30612
30793
  const names = ["FLAVOR.md", "AGENTS.md", "CLAUDE.md", "AGENTS.local.md", "CLAUDE.local.md"];
30613
30794
  const items = await Promise.all(names.map(async (name) => {
30614
- const path = join44(this.#workspace, name);
30795
+ const path = join45(this.#workspace, name);
30615
30796
  try {
30616
30797
  return { name, path, content: redactErrorText(await boundedRead2(path)) };
30617
30798
  } catch (error) {
@@ -30624,9 +30805,9 @@ var DesktopWorkbenchService = class {
30624
30805
  async #permissionFiles() {
30625
30806
  const candidates = [
30626
30807
  ...process.env.FLAVOR_MANAGED_PERMISSIONS ? [{ tier: "managed", path: resolve38(process.env.FLAVOR_MANAGED_PERMISSIONS), content: "" }] : [],
30627
- { tier: "user", path: join44(this.#home, ".flavor-code", "permissions.json"), content: "" },
30628
- { tier: "project", path: join44(this.#workspace, ".flavor", "permissions.json"), content: "" },
30629
- { tier: "local", path: join44(this.#workspace, ".flavor", "permissions.local.json"), content: "" }
30808
+ { tier: "user", path: join45(this.#home, ".flavor-code", "permissions.json"), content: "" },
30809
+ { tier: "project", path: join45(this.#workspace, ".flavor", "permissions.json"), content: "" },
30810
+ { tier: "local", path: join45(this.#workspace, ".flavor", "permissions.local.json"), content: "" }
30630
30811
  ];
30631
30812
  const values = await Promise.all(candidates.map(async (item) => {
30632
30813
  try {
@@ -30641,7 +30822,7 @@ var DesktopWorkbenchService = class {
30641
30822
  async #audit() {
30642
30823
  let raw;
30643
30824
  try {
30644
- raw = await boundedRead2(join44(this.#workspace, ".flavor", "audit.jsonl"));
30825
+ raw = await boundedRead2(join45(this.#workspace, ".flavor", "audit.jsonl"));
30645
30826
  } catch (error) {
30646
30827
  if (error.code === "ENOENT") return [];
30647
30828
  throw error;
@@ -30656,7 +30837,7 @@ var DesktopWorkbenchService = class {
30656
30837
  }).reverse();
30657
30838
  }
30658
30839
  async #context(sessionId) {
30659
- const usage = await readJsonLines2(join44(this.#workspace, ".flavor", "usage.jsonl"));
30840
+ const usage = await readJsonLines2(join45(this.#workspace, ".flavor", "usage.jsonl"));
30660
30841
  if (sessionId === void 0) return { visibility: [], usage };
30661
30842
  try {
30662
30843
  const document = await new SessionStore({ workspace: this.#workspace }).load(sessionId);
@@ -30697,12 +30878,12 @@ function redact2(value, key = "") {
30697
30878
  // src/desktop/astgraph-service.ts
30698
30879
  import { stat as stat17 } from "fs/promises";
30699
30880
  import { createRequire as nodeCreateRequire2 } from "module";
30700
- import { join as join45, resolve as resolve39 } from "path";
30881
+ import { join as join46, resolve as resolve39 } from "path";
30701
30882
  var FIELDS = "id, kind, name, qualified_name, file_path, language, start_line, end_line, signature";
30702
30883
  var DesktopAstGraphService = class {
30703
30884
  #path;
30704
30885
  constructor(workspace) {
30705
- this.#path = join45(resolve39(workspace), ".flavor", "astgraph", "index.db");
30886
+ this.#path = join46(resolve39(workspace), ".flavor", "astgraph", "index.db");
30706
30887
  }
30707
30888
  async status() {
30708
30889
  if ((await stat17(this.#path).catch(() => void 0))?.isFile() !== true) {
@@ -30779,7 +30960,7 @@ var appMenu;
30779
30960
  var quitting = false;
30780
30961
  function logStartup(step, detail) {
30781
30962
  try {
30782
- const logPath = join46(dirname24(process.execPath), "flavor-code-startup.log");
30963
+ const logPath = join47(dirname24(process.execPath), "flavor-code-startup.log");
30783
30964
  const ts = (/* @__PURE__ */ new Date()).toISOString();
30784
30965
  appendFileSync(logPath, `[${ts}] ${step}${detail ? ` | ${detail}` : ""}
30785
30966
  `);
@@ -30804,7 +30985,7 @@ var d2cEmbedded = createEmbeddedD2cAutomation(() => {
30804
30985
  };
30805
30986
  });
30806
30987
  var d2cJudgeClient = createD2cJudgeClient();
30807
- var judgeStore = () => createD2cJudgeConfigStore(join46(app.getPath("userData"), "d2c-judge.json"));
30988
+ var judgeStore = () => createD2cJudgeConfigStore(join47(app.getPath("userData"), "d2c-judge.json"));
30808
30989
  function judgeImage(png) {
30809
30990
  const image = nativeImage.createFromBuffer(png);
30810
30991
  const size = image.getSize();
@@ -30829,8 +31010,8 @@ function sessionMetaKey(workspace, sessionId) {
30829
31010
  return `${workspace}\0${sessionId}`;
30830
31011
  }
30831
31012
  function worktreeManager(workspace) {
30832
- const key = createHash27("sha256").update(resolve40(workspace)).digest("hex").slice(0, 20);
30833
- return new DesktopWorktreeManager({ repository: workspace, storage: join46(app.getPath("userData"), "task-worktrees", key) });
31013
+ const key = createHash28("sha256").update(resolve40(workspace)).digest("hex").slice(0, 20);
31014
+ return new DesktopWorktreeManager({ repository: workspace, storage: join47(app.getPath("userData"), "task-worktrees", key) });
30834
31015
  }
30835
31016
  function activeWorkingDirectory() {
30836
31017
  if (activeWorkspace === void 0) throw new Error("\u8BF7\u5148\u6253\u5F00\u9879\u76EE");
@@ -30929,7 +31110,7 @@ function emitManagedDesktopEvent(workspace, owner2, event) {
30929
31110
  }
30930
31111
  }
30931
31112
  function createDesktopController(workspace, owner2) {
30932
- const collaborationId = randomUUID28();
31113
+ const collaborationId = randomUUID29();
30933
31114
  return new DesktopRuntimeController({
30934
31115
  emit: (event) => emitManagedDesktopEvent(workspace, owner2, event),
30935
31116
  runD2cInteractionTests: (manifest, baseUrl, mockUrl) => d2cEmbedded.run(manifest, baseUrl, mockUrl),
@@ -30961,12 +31142,21 @@ function createDesktopController(workspace, owner2) {
30961
31142
  },
30962
31143
  createRuntime: async (runtimeOptions) => createProductionRuntime({
30963
31144
  ...runtimeOptions,
31145
+ islandControl: {
31146
+ focus: () => {
31147
+ const target = mainWindow;
31148
+ if (target === void 0 || target.isDestroyed()) return;
31149
+ if (target.isMinimized()) target.restore();
31150
+ target.show();
31151
+ target.focus();
31152
+ }
31153
+ },
30964
31154
  collaboration: {
30965
31155
  instanceId: collaborationId,
30966
31156
  alias: `desktop-${basename11(workspace ?? runtimeOptions.workspace ?? "flavor")}`.slice(0, 64),
30967
31157
  optional: true,
30968
31158
  startBroker: (address) => {
30969
- const entry2 = app.isPackaged ? join46(process.resourcesPath, "app.asar.unpacked", "dist", "desktop", "pals-broker-entry.js") : join46(moduleDirectory, "pals-broker-entry.js");
31159
+ const entry2 = app.isPackaged ? join47(process.resourcesPath, "app.asar.unpacked", "dist", "desktop", "pals-broker-entry.js") : join47(moduleDirectory, "pals-broker-entry.js");
30970
31160
  return spawnPalBrokerProcess({
30971
31161
  address,
30972
31162
  executable: process.execPath,
@@ -30988,7 +31178,7 @@ function createDesktopController(workspace, owner2) {
30988
31178
  var detachedController = createDesktopController();
30989
31179
  var controller = detachedController;
30990
31180
  function statePath() {
30991
- return join46(app.getPath("userData"), "desktop-state.json");
31181
+ return join47(app.getPath("userData"), "desktop-state.json");
30992
31182
  }
30993
31183
  async function loadPersistedProjects() {
30994
31184
  try {
@@ -31161,7 +31351,7 @@ async function chooseAndOpenWorkspace() {
31161
31351
  var cachedAppIconDataUrl;
31162
31352
  function appIconDataUrl() {
31163
31353
  if (cachedAppIconDataUrl !== void 0) return cachedAppIconDataUrl;
31164
- const icon = nativeImage.createFromPath(join46(app.getAppPath(), "assets", "icon.png"));
31354
+ const icon = nativeImage.createFromPath(join47(app.getAppPath(), "assets", "icon.png"));
31165
31355
  if (icon.isEmpty()) return void 0;
31166
31356
  cachedAppIconDataUrl = icon.toDataURL();
31167
31357
  return cachedAppIconDataUrl;
@@ -31579,7 +31769,7 @@ function applicationMenu() {
31579
31769
  ]);
31580
31770
  }
31581
31771
  async function createWindow() {
31582
- const rendererPath = join46(app.getAppPath(), "dist", "desktop-renderer", "index.html");
31772
+ const rendererPath = join47(app.getAppPath(), "dist", "desktop-renderer", "index.html");
31583
31773
  mainWindow = new BrowserWindow2({
31584
31774
  title: "Flavor Code",
31585
31775
  width: 1280,
@@ -31590,14 +31780,14 @@ async function createWindow() {
31590
31780
  show: false,
31591
31781
  ...desktopWindowChrome(),
31592
31782
  webPreferences: {
31593
- preload: join46(moduleDirectory, "preload.cjs"),
31783
+ preload: join47(moduleDirectory, "preload.cjs"),
31594
31784
  contextIsolation: true,
31595
31785
  nodeIntegration: false,
31596
31786
  sandbox: false,
31597
31787
  webSecurity: true
31598
31788
  }
31599
31789
  });
31600
- const iconPath = join46(app.getAppPath(), "assets", "icon.png");
31790
+ const iconPath = join47(app.getAppPath(), "assets", "icon.png");
31601
31791
  const icon = nativeImage.createFromPath(iconPath);
31602
31792
  if (!icon.isEmpty()) {
31603
31793
  mainWindow.setIcon(icon);