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.
@@ -3517,6 +3517,8 @@ var FlavorSession = class {
3517
3517
  this.#activeSubmission = submission;
3518
3518
  this.#interrupted = false;
3519
3519
  let outcome = "completed";
3520
+ let assistantSummary = "";
3521
+ let deliverables = [];
3520
3522
  try {
3521
3523
  const decision = await this.#services.hooks.emit({
3522
3524
  version: 1,
@@ -3543,6 +3545,8 @@ var FlavorSession = class {
3543
3545
  ...submission.initialUserMessage === void 0 ? {} : { initialUserMessage: submission.initialUserMessage }
3544
3546
  })) {
3545
3547
  this.#services.output(event);
3548
+ if (event.type === "text") assistantSummary = `${assistantSummary}${event.text}`.slice(-2e3);
3549
+ if (event.type === "deliverables") deliverables = event.files.slice(0, 100);
3546
3550
  if (event.type === "error") outcome = "failed";
3547
3551
  }
3548
3552
  if (controller.signal.aborted) outcome = "cancelled";
@@ -3567,7 +3571,15 @@ var FlavorSession = class {
3567
3571
  this.#activeSubmission = void 0;
3568
3572
  if (submission.coWorkPlanningKey !== void 0) this.#finishActivePlanning(submission.coWorkPlanningKey);
3569
3573
  try {
3570
- await this.#services.hooks.emit({ version: 1, type: "Stop", payload: { outcome } });
3574
+ await this.#services.hooks.emit({
3575
+ version: 1,
3576
+ type: "Stop",
3577
+ payload: {
3578
+ outcome,
3579
+ ...assistantSummary.trim() ? { summary: assistantSummary.trim() } : {},
3580
+ ...deliverables.length === 0 ? {} : { deliverables }
3581
+ }
3582
+ });
3571
3583
  } catch (error) {
3572
3584
  try {
3573
3585
  this.#services.output({ type: "error", error: { code: "unknown", message: message(error) } });
@@ -5006,9 +5018,9 @@ async function ensureOnce(options) {
5006
5018
 
5007
5019
  // src/production.ts
5008
5020
  import { readFile as readFile22 } from "fs/promises";
5009
- import { createHash as createHash17, randomUUID as randomUUID19 } from "crypto";
5010
- import { homedir as homedir2, release as osRelease, tmpdir as tmpdir3, version as osVersion } from "os";
5011
- import { basename as basename6, join as join24, relative as relative20, resolve as resolve27, sep as sep20 } from "path";
5021
+ import { createHash as createHash18, randomUUID as randomUUID20 } from "crypto";
5022
+ import { homedir as homedir2, release as osRelease, tmpdir as tmpdir4, version as osVersion } from "os";
5023
+ import { basename as basename6, join as join25, relative as relative20, resolve as resolve27, sep as sep20 } from "path";
5012
5024
 
5013
5025
  // src/agent/subagents.ts
5014
5026
  import { z as z5 } from "zod";
@@ -6973,6 +6985,7 @@ var AgentLoop = class {
6973
6985
  attempt,
6974
6986
  messages: modelRequest.messages
6975
6987
  });
6988
+ const modelStartedAt = Date.now();
6976
6989
  yield { type: "model-start", id: modelCallId };
6977
6990
  try {
6978
6991
  for await (const event of adapter.stream(modelRequest)) {
@@ -7031,6 +7044,13 @@ var AgentLoop = class {
7031
7044
  completed,
7032
7045
  agent: this.#options.agent,
7033
7046
  providerError,
7047
+ durationMs: Math.max(0, Date.now() - modelStartedAt),
7048
+ ...usage === void 0 ? {} : {
7049
+ inputTokens: usage.inputTokens,
7050
+ outputTokens: usage.outputTokens,
7051
+ ...usage.cacheReadTokens === void 0 ? {} : { cacheReadTokens: usage.cacheReadTokens },
7052
+ ...usage.cacheCreationTokens === void 0 ? {} : { cacheCreationTokens: usage.cacheCreationTokens }
7053
+ },
7034
7054
  ...terminalError === void 0 ? {} : {
7035
7055
  errorCode: terminalError.code,
7036
7056
  errorMessage: terminalError.message
@@ -8772,19 +8792,155 @@ function createIncidentReporter(options) {
8772
8792
  };
8773
8793
  }
8774
8794
 
8795
+ // src/island/control-server.ts
8796
+ import { createHash as createHash7, randomUUID as randomUUID10 } from "crypto";
8797
+ import { chmod as chmod3, unlink as unlink4 } from "fs/promises";
8798
+ import { tmpdir as tmpdir2 } from "os";
8799
+ import { join as join9 } from "path";
8800
+ import { createServer as createServer2 } from "net";
8801
+ var MAX_REQUEST_BYTES = 64 * 1024;
8802
+ var SOCKET_TIMEOUT_MS = 1e4;
8803
+ function islandControlEndpoint(sessionId, platform = process.platform) {
8804
+ const digest = createHash7("sha256").update(`${process.pid}\0${sessionId}`).digest("hex").slice(0, 20);
8805
+ if (platform === "win32") return `\\\\.\\pipe\\flavor-island-control-${digest}`;
8806
+ const uid = typeof process.getuid === "function" ? process.getuid() : 0;
8807
+ return join9(tmpdir2(), `flavor-island-control-${uid}-${digest}.sock`);
8808
+ }
8809
+ async function createIslandControlServer(options) {
8810
+ const platform = options.platform ?? process.platform;
8811
+ const endpoint = options.endpoint ?? islandControlEndpoint(options.sessionId, platform);
8812
+ const token = options.token ?? randomUUID10();
8813
+ const capabilities = [
8814
+ "abort",
8815
+ "steer",
8816
+ "follow_up",
8817
+ ...options.focus === void 0 ? [] : ["focus"]
8818
+ ];
8819
+ if (platform !== "win32") await unlink4(endpoint).catch(() => void 0);
8820
+ const sockets = /* @__PURE__ */ new Set();
8821
+ const server = createServer2((socket) => {
8822
+ sockets.add(socket);
8823
+ socket.setTimeout(SOCKET_TIMEOUT_MS, () => socket.destroy());
8824
+ socket.on("close", () => sockets.delete(socket));
8825
+ socket.on("error", () => void 0);
8826
+ let buffer = Buffer.alloc(0);
8827
+ let handled = false;
8828
+ socket.on("data", (chunk) => {
8829
+ if (handled) return;
8830
+ const bytes = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
8831
+ if (buffer.length + bytes.length > MAX_REQUEST_BYTES) {
8832
+ handled = true;
8833
+ write(socket, { ok: false, error: "request_too_large" });
8834
+ return;
8835
+ }
8836
+ buffer = Buffer.concat([buffer, bytes]);
8837
+ const newline = buffer.indexOf(10);
8838
+ if (newline < 0) return;
8839
+ handled = true;
8840
+ const line = buffer.subarray(0, newline).toString("utf8");
8841
+ void dispatch(line, socket, options, token);
8842
+ });
8843
+ });
8844
+ await new Promise((resolve28, reject) => {
8845
+ const onError = (error) => {
8846
+ server.removeListener("listening", onListening);
8847
+ reject(error);
8848
+ };
8849
+ const onListening = () => {
8850
+ server.removeListener("error", onError);
8851
+ resolve28();
8852
+ };
8853
+ server.once("error", onError);
8854
+ server.once("listening", onListening);
8855
+ server.listen(endpoint);
8856
+ });
8857
+ if (platform !== "win32") await chmod3(endpoint, 384).catch(() => void 0);
8858
+ let closed = false;
8859
+ return {
8860
+ endpoint,
8861
+ token,
8862
+ capabilities,
8863
+ async close() {
8864
+ if (closed) return;
8865
+ closed = true;
8866
+ for (const socket of sockets) socket.destroy();
8867
+ await closeServer(server);
8868
+ if (platform !== "win32") await unlink4(endpoint).catch(() => void 0);
8869
+ }
8870
+ };
8871
+ }
8872
+ async function dispatch(line, socket, options, token) {
8873
+ let request;
8874
+ try {
8875
+ const parsed = JSON.parse(line);
8876
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new Error("invalid request");
8877
+ request = parsed;
8878
+ } catch {
8879
+ write(socket, { ok: false, error: "invalid_json" });
8880
+ return;
8881
+ }
8882
+ if (request.token !== token) {
8883
+ write(socket, { ok: false, error: "unauthorized" });
8884
+ return;
8885
+ }
8886
+ const command = request.command;
8887
+ try {
8888
+ if (command === "abort") {
8889
+ write(socket, { ok: true, result: options.session.interrupt() });
8890
+ } else if (command === "steer" || command === "follow_up") {
8891
+ const message2 = typeof request.message === "string" ? request.message.trim() : "";
8892
+ if (!message2 || message2.length > 1e5) {
8893
+ write(socket, { ok: false, error: "invalid_message" });
8894
+ return;
8895
+ }
8896
+ if (command === "steer") options.session.steer(message2);
8897
+ else options.session.followUp(message2);
8898
+ write(socket, { ok: true });
8899
+ } else if (command === "focus") {
8900
+ if (options.focus === void 0) {
8901
+ write(socket, { ok: false, error: "focus_unavailable" });
8902
+ return;
8903
+ }
8904
+ await options.focus();
8905
+ write(socket, { ok: true });
8906
+ } else {
8907
+ write(socket, { ok: false, error: "unknown_command" });
8908
+ }
8909
+ } catch (error) {
8910
+ write(socket, { ok: false, error: error instanceof Error ? error.message : String(error) });
8911
+ }
8912
+ }
8913
+ function write(socket, payload) {
8914
+ try {
8915
+ socket.end(`${JSON.stringify(payload)}
8916
+ `);
8917
+ } catch {
8918
+ socket.destroy();
8919
+ }
8920
+ }
8921
+ function closeServer(server) {
8922
+ return new Promise((resolve28) => {
8923
+ try {
8924
+ server.close(() => resolve28());
8925
+ } catch {
8926
+ resolve28();
8927
+ }
8928
+ });
8929
+ }
8930
+
8775
8931
  // src/evolve/service.ts
8776
8932
  import { spawn as spawn5 } from "child_process";
8777
8933
  import { writeFile as writeFile8 } from "fs/promises";
8778
- import { join as join11 } from "path";
8934
+ import { join as join12 } from "path";
8779
8935
  import { z as z14 } from "zod";
8780
8936
 
8781
8937
  // src/evolve/loader.ts
8782
8938
  import { cp, mkdir as mkdir8, mkdtemp, readdir as readdir4, rm as rm2, stat as stat4, writeFile as writeFile6 } from "fs/promises";
8783
- import { tmpdir as tmpdir2 } from "os";
8784
- import { join as join9, resolve as resolve10 } from "path";
8939
+ import { tmpdir as tmpdir3 } from "os";
8940
+ import { join as join10, resolve as resolve10 } from "path";
8785
8941
 
8786
8942
  // src/plugins/host.ts
8787
- import { createHash as createHash7 } from "crypto";
8943
+ import { createHash as createHash8 } from "crypto";
8788
8944
  import { lstatSync, realpathSync as realpathSync3 } from "fs";
8789
8945
  import { lstat as lstat5, open as open5, readFile as readFile7, readdir as readdir3, realpath as realpath4, stat as stat3, writeFile as writeFile5 } from "fs/promises";
8790
8946
  import { isAbsolute as isAbsolute5, relative as relative8, resolve as resolve9, sep as sep8 } from "path";
@@ -9145,7 +9301,7 @@ var PluginHost = class {
9145
9301
  const manifest = PluginManifestSchema.parse(rawManifest);
9146
9302
  const entry2 = resolveContained(root, manifest.main, "Plugin entry");
9147
9303
  const entrySnapshot = await snapshotEntry(root, entry2);
9148
- const fingerprint2 = createHash7("sha256").update(JSON.stringify(manifest)).update(await readFile7(entrySnapshot.physicalPath)).digest("hex");
9304
+ const fingerprint2 = createHash8("sha256").update(JSON.stringify(manifest)).update(await readFile7(entrySnapshot.physicalPath)).digest("hex");
9149
9305
  return { manifest, root, source, entry: entry2, entrySnapshot, fingerprint: fingerprint2 };
9150
9306
  } catch (error) {
9151
9307
  this.#diagnose(diagnosticLabel, error, inputRoot);
@@ -9504,8 +9660,8 @@ function compare(left, right) {
9504
9660
  }
9505
9661
 
9506
9662
  // src/evolve/loader.ts
9507
- var PLUGIN_DIR = join9(".flavor", "plugins");
9508
- var VERSIONS_DIR = join9(".flavor", "plugins", ".versions");
9663
+ var PLUGIN_DIR = join10(".flavor", "plugins");
9664
+ var VERSIONS_DIR = join10(".flavor", "plugins", ".versions");
9509
9665
  function sanitizePluginName(tool) {
9510
9666
  const base = String(tool ?? "fix").replace(/[^a-z0-9-]/gi, "-").toLowerCase();
9511
9667
  return base.startsWith("fix-") ? base : `fix-${base}`;
@@ -9549,8 +9705,8 @@ export function activate(ctx) {
9549
9705
  async function scaffoldFixPlugin(workspace, name) {
9550
9706
  const dir = fixPluginDir(workspace, name);
9551
9707
  await mkdir8(dir, { recursive: true });
9552
- const manifestPath = join9(dir, "flavor-plugin.json");
9553
- const entryPath = join9(dir, "index.js");
9708
+ const manifestPath = join10(dir, "flavor-plugin.json");
9709
+ const entryPath = join10(dir, "index.js");
9554
9710
  try {
9555
9711
  await writeFile6(manifestPath, SCAFFOLD_MANIFEST(name), { encoding: "utf8", flag: "wx" });
9556
9712
  await writeFile6(entryPath, SCAFFOLD_ENTRY(name), { encoding: "utf8", flag: "wx" });
@@ -9570,9 +9726,9 @@ async function verifyFixPlugin(workspace, name) {
9570
9726
  return { ok: false, provided: [], tools: [], commands: [], error: `Plugin "${name}" not found.` };
9571
9727
  }
9572
9728
  const collected = { tools: [], commands: [] };
9573
- const sandbox = await mkdtemp(join9(tmpdir2(), "flavor-evolve-verify-"));
9729
+ const sandbox = await mkdtemp(join10(tmpdir3(), "flavor-evolve-verify-"));
9574
9730
  try {
9575
- await cp(pluginRoot, join9(sandbox, name), { recursive: true });
9731
+ await cp(pluginRoot, join10(sandbox, name), { recursive: true });
9576
9732
  const host = new PluginHost({
9577
9733
  projectPluginDirs: [sandbox],
9578
9734
  sandbox: true,
@@ -9623,7 +9779,7 @@ async function verifyFixPlugin(workspace, name) {
9623
9779
  }
9624
9780
  async function snapshotFixPlugin(workspace, name) {
9625
9781
  const pluginRoot = fixPluginDir(workspace, name);
9626
- const snapshotRoot = join9(versionsDirFor(workspace, name), timestamp());
9782
+ const snapshotRoot = join10(versionsDirFor(workspace, name), timestamp());
9627
9783
  await mkdir8(snapshotRoot, { recursive: true });
9628
9784
  await cp(pluginRoot, snapshotRoot, { recursive: true });
9629
9785
  return snapshotRoot;
@@ -9644,7 +9800,7 @@ async function revertFixPlugin(workspace, name) {
9644
9800
  }
9645
9801
  const snapshots = entries.filter((entry2) => !entry2.startsWith(".")).sort();
9646
9802
  if (snapshots.length === 0) throw new Error(`Plugin "${name}" has no snapshot to restore.`);
9647
- const latest = join9(versionsRoot, snapshots[snapshots.length - 1]);
9803
+ const latest = join10(versionsRoot, snapshots[snapshots.length - 1]);
9648
9804
  await rm2(pluginRoot, { recursive: true, force: true });
9649
9805
  await mkdir8(pluginRoot, { recursive: true });
9650
9806
  await cp(latest, pluginRoot, { recursive: true });
@@ -9652,14 +9808,14 @@ async function revertFixPlugin(workspace, name) {
9652
9808
  }
9653
9809
 
9654
9810
  // src/evolve/store.ts
9655
- import { createHash as createHash8 } from "crypto";
9811
+ import { createHash as createHash9 } from "crypto";
9656
9812
  import { appendFile, mkdir as mkdir9, readFile as readFile8, rm as rm3, writeFile as writeFile7 } from "fs/promises";
9657
- import { dirname as dirname11, join as join10 } from "path";
9813
+ import { dirname as dirname11, join as join11 } from "path";
9658
9814
  function normalizeError(message2) {
9659
9815
  return String(message2 ?? "").replace(/\s+/g, " ").replace(/"[^"]*"/g, '"\u2026"').replace(/`[^`]*`/g, '"\u2026"').trim().slice(0, 160);
9660
9816
  }
9661
9817
  function fingerprint(tool, errorCode, error) {
9662
- return createHash8("sha1").update(`${tool}::${errorCode ?? ""}::${normalizeError(error)}`).digest("hex").slice(0, 12);
9818
+ return createHash9("sha1").update(`${tool}::${errorCode ?? ""}::${normalizeError(error)}`).digest("hex").slice(0, 12);
9663
9819
  }
9664
9820
  function argKeys(args) {
9665
9821
  if (args === null || typeof args !== "object") return [];
@@ -9727,12 +9883,12 @@ var EvolveStore = class {
9727
9883
  #queue = Promise.resolve();
9728
9884
  constructor(options) {
9729
9885
  const { workspace, maxSignals = 400, maxRules = 20 } = options;
9730
- this.dir = join10(workspace, ".flavor", "evolve");
9731
- this.signalsFile = join10(this.dir, "signals.jsonl");
9732
- this.reflectionsFile = join10(this.dir, "reflections.jsonl");
9733
- this.doneFile = join10(this.dir, "done.json");
9734
- this.verifiedFile = join10(this.dir, "verified.json");
9735
- this.rulesFile = join10(this.dir, "rules.json");
9886
+ this.dir = join11(workspace, ".flavor", "evolve");
9887
+ this.signalsFile = join11(this.dir, "signals.jsonl");
9888
+ this.reflectionsFile = join11(this.dir, "reflections.jsonl");
9889
+ this.doneFile = join11(this.dir, "done.json");
9890
+ this.verifiedFile = join11(this.dir, "verified.json");
9891
+ this.rulesFile = join11(this.dir, "rules.json");
9736
9892
  this.maxSignals = maxSignals;
9737
9893
  this.maxRules = maxRules;
9738
9894
  }
@@ -10271,7 +10427,7 @@ function createEvolveService(options) {
10271
10427
  if (suggestion === void 0) return `No open suggestion with id "${suggestionId}". Use /evolve suggest to list them.`;
10272
10428
  const name = sanitizePluginName(suggestion.tool);
10273
10429
  const dir = await scaffoldFixPlugin(workspace, name);
10274
- await writeFile8(join11(dir, "PLAN.md"), buildPlan(suggestion, name, "See the repeated failure below; describe your fix in PLAN.md."), "utf8");
10430
+ await writeFile8(join12(dir, "PLAN.md"), buildPlan(suggestion, name, "See the repeated failure below; describe your fix in PLAN.md."), "utf8");
10275
10431
  await snapshotFixPlugin(workspace, name);
10276
10432
  return [
10277
10433
  `suggestion ${suggestion.id}: ${suggestion.tool} x${suggestion.count} \u2014 ${suggestion.error}`,
@@ -10362,7 +10518,7 @@ ${result.stderr.slice(-4e3)}` : ""}`;
10362
10518
  }
10363
10519
  const name = sanitizePluginName(suggestion.tool);
10364
10520
  const dir = await scaffoldFixPlugin(workspace, name);
10365
- await writeFile8(join11(dir, "PLAN.md"), buildPlan(suggestion, name, implementation), "utf8");
10521
+ await writeFile8(join12(dir, "PLAN.md"), buildPlan(suggestion, name, implementation), "utf8");
10366
10522
  await snapshotFixPlugin(workspace, name);
10367
10523
  return [
10368
10524
  `Scaffolded fix plugin at ${dir} for suggestion [${suggestion.id}] (${suggestion.tool} x${suggestion.count}).`,
@@ -10783,9 +10939,9 @@ ${evidence.summary}`;
10783
10939
  };
10784
10940
 
10785
10941
  // src/goal/orchestrator.ts
10786
- import { createHash as createHash10 } from "crypto";
10942
+ import { createHash as createHash11 } from "crypto";
10787
10943
  import { writeFile as writeFile9, mkdir as mkdir10 } from "fs/promises";
10788
- import { join as join13 } from "path";
10944
+ import { join as join14 } from "path";
10789
10945
 
10790
10946
  // src/goal/types.ts
10791
10947
  import { z as z16 } from "zod";
@@ -10948,9 +11104,9 @@ function extractJson(text) {
10948
11104
  }
10949
11105
 
10950
11106
  // src/goal/classifier.ts
10951
- import { createHash as createHash9 } from "crypto";
11107
+ import { createHash as createHash10 } from "crypto";
10952
11108
  import { readFile as readFile9 } from "fs/promises";
10953
- import { join as join12 } from "path";
11109
+ import { join as join13 } from "path";
10954
11110
  function buildSkepticPrompt(evidence, plan, index) {
10955
11111
  const criteriaList = plan.criteria.map((c) => ` ${c.id}. [${c.type}] ${c.description}`).join("\n");
10956
11112
  return [
@@ -11123,11 +11279,11 @@ function deduplicateGaps(gaps) {
11123
11279
  }
11124
11280
  function computeFingerprint(gaps) {
11125
11281
  const content = gaps.map((g) => `${g.criterion}:${g.description}`).sort().join("\n");
11126
- return createHash9("sha256").update(content).digest("hex").slice(0, 16);
11282
+ return createHash10("sha256").update(content).digest("hex").slice(0, 16);
11127
11283
  }
11128
- async function collectEvidence(workspace, objective, finalResponse, priorGaps, contractHash2 = createHash9("sha256").update(objective).digest("hex"), hostVerification) {
11284
+ async function collectEvidence(workspace, objective, finalResponse, priorGaps, contractHash2 = createHash10("sha256").update(objective).digest("hex"), hostVerification) {
11129
11285
  const workspaceState = await collectWorkspaceState(workspace);
11130
- const planPath = join12(workspace, ".flavor", "goal-plan.md");
11286
+ const planPath = join13(workspace, ".flavor", "goal-plan.md");
11131
11287
  let planFile = null;
11132
11288
  try {
11133
11289
  planFile = await readFile9(planPath, "utf8");
@@ -11154,7 +11310,7 @@ async function collectWorkspaceState(workspace) {
11154
11310
  return {
11155
11311
  changedFiles: [],
11156
11312
  status: ["not-a-git-worktree"],
11157
- diffHash: createHash9("sha256").update("not-a-git-worktree").digest("hex")
11313
+ diffHash: createHash10("sha256").update("not-a-git-worktree").digest("hex")
11158
11314
  };
11159
11315
  }
11160
11316
  const status = statusResult.stdout.split(/\r?\n/).map((line) => line.trimEnd()).filter(Boolean);
@@ -11171,7 +11327,7 @@ async function collectWorkspaceState(workspace) {
11171
11327
  return {
11172
11328
  changedFiles,
11173
11329
  status,
11174
- diffHash: createHash9("sha256").update(diff.stdout).update("\nUNTRACKED\n").update(untracked).digest("hex")
11330
+ diffHash: createHash10("sha256").update(diff.stdout).update("\nUNTRACKED\n").update(untracked).digest("hex")
11175
11331
  };
11176
11332
  }
11177
11333
 
@@ -11303,7 +11459,7 @@ var GoalOrchestrator = class {
11303
11459
  type: "not_achieved",
11304
11460
  gaps,
11305
11461
  summary: hostVerification.summary,
11306
- fingerprint: createHash10("sha256").update(hostVerification.summary).digest("hex").slice(0, 16)
11462
+ fingerprint: createHash11("sha256").update(hostVerification.summary).digest("hex").slice(0, 16)
11307
11463
  };
11308
11464
  }
11309
11465
  } else try {
@@ -11377,11 +11533,11 @@ var GoalOrchestrator = class {
11377
11533
  }
11378
11534
  };
11379
11535
  function contractHash(objective, plan) {
11380
- return createHash10("sha256").update(JSON.stringify({ objective, plan })).digest("hex");
11536
+ return createHash11("sha256").update(JSON.stringify({ objective, plan })).digest("hex");
11381
11537
  }
11382
11538
  async function writePlanFile(workspace, plan) {
11383
- const dir = join13(workspace, ".flavor");
11384
- const planPath = join13(dir, "goal-plan.md");
11539
+ const dir = join14(workspace, ".flavor");
11540
+ const planPath = join14(dir, "goal-plan.md");
11385
11541
  await mkdir10(dir, { recursive: true });
11386
11542
  const criteriaText = plan.criteria.map((c) => `- [${c.type}] AC-${c.id}: ${c.description}`).join("\n");
11387
11543
  const content = [
@@ -11457,9 +11613,9 @@ function formatPriorGaps(gaps) {
11457
11613
 
11458
11614
  // src/goal/store.ts
11459
11615
  import { constants as constants2 } from "fs";
11460
- import { randomUUID as randomUUID10 } from "crypto";
11616
+ import { randomUUID as randomUUID11 } from "crypto";
11461
11617
  import { lstat as lstat6, mkdir as mkdir11, open as open6, rename as rename4, rm as rm4 } from "fs/promises";
11462
- import { dirname as dirname12, join as join14, relative as relative9, resolve as resolve11, sep as sep9 } from "path";
11618
+ import { dirname as dirname12, join as join15, relative as relative9, resolve as resolve11, sep as sep9 } from "path";
11463
11619
  var DEFAULT_MAX_BYTES = 1024 * 1024;
11464
11620
  var GoalStore = class {
11465
11621
  #workspace;
@@ -11467,7 +11623,7 @@ var GoalStore = class {
11467
11623
  #maxBytes;
11468
11624
  constructor(options) {
11469
11625
  this.#workspace = resolve11(options.workspace);
11470
- this.#root = join14(this.#workspace, ".flavor", "goals");
11626
+ this.#root = join15(this.#workspace, ".flavor", "goals");
11471
11627
  this.#maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
11472
11628
  }
11473
11629
  async save(input) {
@@ -11475,13 +11631,13 @@ var GoalStore = class {
11475
11631
  await assertNoSymlink(this.#workspace, dirname12(this.#root));
11476
11632
  await mkdir11(this.#root, { recursive: true, mode: 448 });
11477
11633
  await assertNoSymlink(this.#workspace, this.#root);
11478
- const target = join14(this.#root, `${state.id}.json`);
11634
+ const target = join15(this.#root, `${state.id}.json`);
11479
11635
  const body = `${JSON.stringify(state, null, 2)}
11480
11636
  `;
11481
11637
  if (Buffer.byteLength(body) > this.#maxBytes) {
11482
11638
  throw new Error(`Goal state exceeds maximum size of ${this.#maxBytes} bytes`);
11483
11639
  }
11484
- const temporary = join14(this.#root, `.${state.id}.${process.pid}.${randomUUID10()}.tmp`);
11640
+ const temporary = join15(this.#root, `.${state.id}.${process.pid}.${randomUUID11()}.tmp`);
11485
11641
  let handle;
11486
11642
  try {
11487
11643
  handle = await open6(temporary, constants2.O_CREAT | constants2.O_EXCL | constants2.O_WRONLY, 384);
@@ -11522,7 +11678,7 @@ function isCode3(error, code) {
11522
11678
 
11523
11679
  // src/loop/isolation.ts
11524
11680
  import { appendFile as appendFile2, mkdir as mkdir12, readFile as readFile10 } from "fs/promises";
11525
- import { join as join15, resolve as resolve12 } from "path";
11681
+ import { join as join16, resolve as resolve12 } from "path";
11526
11682
  var CODE_CHANGE = /\b(?:fix|implement|add|update|change|modify|refactor|build|create|remove|delete|write|migrate)\b|修复|实现|添加|更新|修改|重构|创建|删除|迁移/i;
11527
11683
  var READ_ONLY = /\b(?:review|analy[sz]e|inspect|explain|research|investigate|audit|summari[sz]e|report)\b|调研|分析|审查|检查|解释|研究|总结|报告/i;
11528
11684
  function inferGoalIntent(goal) {
@@ -11545,8 +11701,8 @@ async function prepareLoopWorkspace(options) {
11545
11701
  return { kind: "needs_human", reason: "The workspace has uncommitted changes that a new worktree would omit." };
11546
11702
  }
11547
11703
  options.signal?.throwIfAborted();
11548
- const worktrees = join15(root, ".worktrees");
11549
- const path = join15(worktrees, `loop-${options.loopId}`);
11704
+ const worktrees = join16(root, ".worktrees");
11705
+ const path = join16(worktrees, `loop-${options.loopId}`);
11550
11706
  const branch = `loop/${options.loopId}`;
11551
11707
  try {
11552
11708
  await ensureWorktreeDirectoryIgnored(root);
@@ -11576,8 +11732,8 @@ async function ensureWorktreeDirectoryIgnored(root) {
11576
11732
  const commonDirectory = await git(root, ["rev-parse", "--git-common-dir"]);
11577
11733
  if (commonDirectory.code !== 0) throw new Error(commonDirectory.stderr.trim() || "Git common directory is unavailable");
11578
11734
  const gitDirectory = resolve12(root, commonDirectory.stdout.trim());
11579
- const infoDirectory = join15(gitDirectory, "info");
11580
- const excludePath = join15(infoDirectory, "exclude");
11735
+ const infoDirectory = join16(gitDirectory, "info");
11736
+ const excludePath = join16(infoDirectory, "exclude");
11581
11737
  await mkdir12(infoDirectory, { recursive: true });
11582
11738
  let existing = "";
11583
11739
  try {
@@ -11593,8 +11749,8 @@ async function ensureWorktreeDirectoryIgnored(root) {
11593
11749
  // src/loop/store.ts
11594
11750
  import { constants as constants3 } from "fs";
11595
11751
  import { lstat as lstat7, mkdir as mkdir13, open as open7, readFile as readFile11, realpath as realpath5, rename as rename5, rm as rm5, stat as stat5 } from "fs/promises";
11596
- import { dirname as dirname13, join as join16, relative as relative10, resolve as resolve13, sep as sep10 } from "path";
11597
- import { randomUUID as randomUUID11 } from "crypto";
11752
+ import { dirname as dirname13, join as join17, relative as relative10, resolve as resolve13, sep as sep10 } from "path";
11753
+ import { randomUUID as randomUUID12 } from "crypto";
11598
11754
  var LOOP_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
11599
11755
  var DEFAULT_MAX_BYTES2 = 5 * 1024 * 1024;
11600
11756
  var LoopStore = class {
@@ -11604,7 +11760,7 @@ var LoopStore = class {
11604
11760
  #appendTails = /* @__PURE__ */ new Map();
11605
11761
  constructor(options) {
11606
11762
  this.#workspace = resolve13(options.workspace);
11607
- this.#root = join16(this.#workspace, ".flavor", "loops");
11763
+ this.#root = join17(this.#workspace, ".flavor", "loops");
11608
11764
  this.#maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES2;
11609
11765
  }
11610
11766
  async create(state) {
@@ -11621,11 +11777,11 @@ var LoopStore = class {
11621
11777
  const state = LoopStateSchema.parse(input);
11622
11778
  await this.#assertWorkspace(state.workspace);
11623
11779
  const directory = await this.#prepare(state.loopId);
11624
- const target = join16(directory, "state.json");
11780
+ const target = join17(directory, "state.json");
11625
11781
  const body = `${JSON.stringify(state, null, 2)}
11626
11782
  `;
11627
11783
  if (Buffer.byteLength(body) > this.#maxBytes) throw new Error(`Loop state exceeds maximum size of ${this.#maxBytes} bytes`);
11628
- const temporary = join16(directory, `.state.${process.pid}.${randomUUID11()}.tmp`);
11784
+ const temporary = join17(directory, `.state.${process.pid}.${randomUUID12()}.tmp`);
11629
11785
  let handle;
11630
11786
  try {
11631
11787
  handle = await open7(temporary, constants3.O_CREAT | constants3.O_EXCL | constants3.O_WRONLY, 384);
@@ -11641,7 +11797,7 @@ var LoopStore = class {
11641
11797
  }
11642
11798
  async load(loopId) {
11643
11799
  const directory = await this.#safeExisting(loopId);
11644
- const target = join16(directory, "state.json");
11800
+ const target = join17(directory, "state.json");
11645
11801
  try {
11646
11802
  const metadata = await stat5(target);
11647
11803
  if (!metadata.isFile() || metadata.size > this.#maxBytes) throw new Error("Loop state is not a bounded regular file");
@@ -11651,7 +11807,7 @@ var LoopStore = class {
11651
11807
  return state;
11652
11808
  } catch (error) {
11653
11809
  if (isCode4(error, "ENOENT")) throw new Error(`Loop "${loopId}" was not found`);
11654
- const quarantine = `${target}.corrupt-${Date.now()}-${randomUUID11().slice(0, 8)}`;
11810
+ const quarantine = `${target}.corrupt-${Date.now()}-${randomUUID12().slice(0, 8)}`;
11655
11811
  await rename5(target, quarantine).catch(() => void 0);
11656
11812
  throw new Error(`Loop "${loopId}" is corrupt and was quarantined: ${message(error)}`);
11657
11813
  }
@@ -11661,7 +11817,7 @@ var LoopStore = class {
11661
11817
  const previous = this.#appendTails.get(event.loopId) ?? Promise.resolve();
11662
11818
  const next = previous.catch(() => void 0).then(async () => {
11663
11819
  const directory = await this.#prepare(event.loopId);
11664
- const path = join16(directory, "events.jsonl");
11820
+ const path = join17(directory, "events.jsonl");
11665
11821
  const handle = await open7(path, constants3.O_CREAT | constants3.O_APPEND | constants3.O_WRONLY, 384);
11666
11822
  try {
11667
11823
  await handle.writeFile(`${JSON.stringify(event)}
@@ -11678,7 +11834,7 @@ var LoopStore = class {
11678
11834
  await assertNoSymlink2(this.#workspace, dirname13(this.#root));
11679
11835
  await mkdir13(this.#root, { recursive: true, mode: 448 });
11680
11836
  await assertNoSymlink2(this.#workspace, this.#root);
11681
- const directory = join16(this.#root, loopId);
11837
+ const directory = join17(this.#root, loopId);
11682
11838
  await mkdir13(directory, { recursive: true, mode: 448 });
11683
11839
  await assertNoSymlink2(this.#workspace, directory);
11684
11840
  return directory;
@@ -11686,7 +11842,7 @@ var LoopStore = class {
11686
11842
  async #safeExisting(loopId) {
11687
11843
  validateId(loopId);
11688
11844
  await assertNoSymlink2(this.#workspace, this.#root);
11689
- const directory = join16(this.#root, loopId);
11845
+ const directory = join17(this.#root, loopId);
11690
11846
  await assertNoSymlink2(this.#workspace, directory);
11691
11847
  return directory;
11692
11848
  }
@@ -11735,7 +11891,7 @@ function isCode4(error, code) {
11735
11891
 
11736
11892
  // src/loop/verifier.ts
11737
11893
  import { readFile as readFile12 } from "fs/promises";
11738
- import { join as join17 } from "path";
11894
+ import { join as join18 } from "path";
11739
11895
 
11740
11896
  // src/tools/shell.ts
11741
11897
  import { spawn as spawn6, spawnSync } from "child_process";
@@ -12293,13 +12449,13 @@ var SCRIPT_PRIORITY = ["test", "typecheck", "lint", "build", "smoke:install"];
12293
12449
  async function inferVerificationPlan(workspace) {
12294
12450
  const commands = [];
12295
12451
  const seen = /* @__PURE__ */ new Set();
12296
- const packageJson = await optionalJson(join17(workspace, "package.json"));
12452
+ const packageJson = await optionalJson(join18(workspace, "package.json"));
12297
12453
  const scripts = isRecord2(packageJson?.scripts) ? packageJson.scripts : {};
12298
12454
  for (const name of SCRIPT_PRIORITY) {
12299
12455
  if (typeof scripts[name] !== "string" || isUnconditionalPassThrough(scripts[name])) continue;
12300
12456
  add(commands, seen, npmScript(name));
12301
12457
  }
12302
- const flavor = await optionalText(join17(workspace, "FLAVOR.md"));
12458
+ const flavor = await optionalText(join18(workspace, "FLAVOR.md"));
12303
12459
  if (flavor !== void 0) {
12304
12460
  for (const match of flavor.matchAll(/^- `([^`]+)`\s*$/gm)) {
12305
12461
  const parsed = parseTrustedCommand(match[1] ?? "");
@@ -13002,7 +13158,7 @@ var ModelRegistry = class {
13002
13158
  };
13003
13159
 
13004
13160
  // src/mcp/client.ts
13005
- import { createHash as createHash11 } from "crypto";
13161
+ import { createHash as createHash12 } from "crypto";
13006
13162
  import { z as z19 } from "zod";
13007
13163
  var McpManager = class {
13008
13164
  #workspace;
@@ -13169,7 +13325,7 @@ function mcpToolName(serverName, remoteName) {
13169
13325
  const safe = remoteName.replace(/[^A-Za-z0-9_-]/g, "_") || "tool";
13170
13326
  const direct = `${prefix}${safe}`;
13171
13327
  if (direct.length <= 64 && safe === remoteName) return direct;
13172
- const suffix = `__${createHash11("sha256").update(remoteName).digest("hex").slice(0, 8)}`;
13328
+ const suffix = `__${createHash12("sha256").update(remoteName).digest("hex").slice(0, 8)}`;
13173
13329
  return `${prefix}${safe.slice(0, Math.max(1, 64 - prefix.length - suffix.length))}${suffix}`;
13174
13330
  }
13175
13331
  function mcpErrorText(content) {
@@ -13235,14 +13391,14 @@ async function connectSdkMcpClient(input, dependencies = DEFAULT_DEPENDENCIES) {
13235
13391
  }
13236
13392
 
13237
13393
  // src/auth/oauth.ts
13238
- import { randomBytes as randomBytes2, createHash as createHash13 } from "crypto";
13239
- import { createServer as createServer2 } from "http";
13394
+ import { randomBytes as randomBytes2, createHash as createHash14 } from "crypto";
13395
+ import { createServer as createServer3 } from "http";
13240
13396
  import { URL as URL2, URLSearchParams } from "url";
13241
13397
 
13242
13398
  // src/auth/oauth-config.ts
13243
- import { createHash as createHash12 } from "crypto";
13399
+ import { createHash as createHash13 } from "crypto";
13244
13400
  function oauthCredentialId(tokenUrl, clientId) {
13245
- const digest = createHash12("sha256").update(`${tokenUrl}\0${clientId}`, "utf8").digest("base64url");
13401
+ const digest = createHash13("sha256").update(`${tokenUrl}\0${clientId}`, "utf8").digest("base64url");
13246
13402
  return `oauth:${digest}`;
13247
13403
  }
13248
13404
  function parseOAuthLlmConfig(value) {
@@ -13419,7 +13575,7 @@ var OAuthCallbackAuthProvider = class {
13419
13575
  serverResolve = resolve28;
13420
13576
  serverReject = reject;
13421
13577
  });
13422
- const server = createServer2((req, res) => {
13578
+ const server = createServer3((req, res) => {
13423
13579
  const url = new URL2(req.url ?? "/", `http://${this.#callbackHost}:${server.address().port}`);
13424
13580
  if (url.searchParams.has("error")) {
13425
13581
  const error = url.searchParams.get("error") ?? "access_denied";
@@ -13499,7 +13655,7 @@ var OAuthCallbackAuthProvider = class {
13499
13655
  return randomBytes2(32).toString("base64url");
13500
13656
  }
13501
13657
  #computeCodeChallenge(verifier) {
13502
- return createHash13("sha256").update(verifier).digest("base64url");
13658
+ return createHash14("sha256").update(verifier).digest("base64url");
13503
13659
  }
13504
13660
  #generateState() {
13505
13661
  return randomBytes2(32).toString("base64url");
@@ -13610,7 +13766,7 @@ function isStoredToken(value) {
13610
13766
 
13611
13767
  // src/permissions/policy.ts
13612
13768
  import { readFile as readFile15 } from "fs/promises";
13613
- import { join as join18, resolve as resolve16 } from "path";
13769
+ import { join as join19, resolve as resolve16 } from "path";
13614
13770
  import { z as z20 } from "zod";
13615
13771
  var DecisionSchema2 = z20.enum(["allow", "ask", "deny"]);
13616
13772
  var PrefixSchema = z20.array(z20.string().min(1).max(1024)).min(1).max(64);
@@ -13647,9 +13803,9 @@ var CompiledPermissionPolicy = class {
13647
13803
  async function loadPermissionPolicy(options) {
13648
13804
  const sources = [
13649
13805
  ...options.managedPath === void 0 ? [] : [{ tier: "managed", path: resolve16(options.managedPath) }],
13650
- { tier: "user", path: join18(resolve16(options.home), ".flavor-code", "permissions.json") },
13651
- { tier: "project", path: join18(resolve16(options.workspace), ".flavor", "permissions.json") },
13652
- { tier: "local", path: join18(resolve16(options.workspace), ".flavor", "permissions.local.json") }
13806
+ { tier: "user", path: join19(resolve16(options.home), ".flavor-code", "permissions.json") },
13807
+ { tier: "project", path: join19(resolve16(options.workspace), ".flavor", "permissions.json") },
13808
+ { tier: "local", path: join19(resolve16(options.workspace), ".flavor", "permissions.local.json") }
13653
13809
  ];
13654
13810
  const rules = [];
13655
13811
  for (const source of sources) {
@@ -14418,8 +14574,8 @@ function createSkillResourceTool(registry) {
14418
14574
  // src/session/store.ts
14419
14575
  import { constants as constants5 } from "fs";
14420
14576
  import { lstat as lstat9, mkdir as mkdir14, open as open8, readFile as readFile16, readdir as readdir6, realpath as realpath7, rename as rename6, rm as rm6, stat as stat6 } from "fs/promises";
14421
- import { basename as basename3, dirname as dirname15, join as join19, relative as relative13, resolve as resolve18, sep as sep13 } from "path";
14422
- import { randomUUID as randomUUID12 } from "crypto";
14577
+ import { basename as basename3, dirname as dirname15, join as join20, relative as relative13, resolve as resolve18, sep as sep13 } from "path";
14578
+ import { randomUUID as randomUUID13 } from "crypto";
14423
14579
  import { z as z22 } from "zod";
14424
14580
  var SESSION_VERSION = 4;
14425
14581
  var DEFAULT_MAX_SESSION_BYTES = 5 * 1024 * 1024;
@@ -14545,7 +14701,7 @@ var SessionStore = class {
14545
14701
  #maxSessions;
14546
14702
  constructor(options) {
14547
14703
  this.#workspace = resolve18(options.workspace);
14548
- this.#sessions = join19(this.#workspace, ".flavor", "sessions");
14704
+ this.#sessions = join20(this.#workspace, ".flavor", "sessions");
14549
14705
  this.#maxBytes = options.maxBytes ?? DEFAULT_MAX_SESSION_BYTES;
14550
14706
  if (!Number.isSafeInteger(this.#maxBytes) || this.#maxBytes < 256) throw new Error("maxBytes must be an integer of at least 256");
14551
14707
  this.#maxSessions = options.maxSessions ?? 50;
@@ -14577,7 +14733,7 @@ var SessionStore = class {
14577
14733
  const body = `${lines.join("\n")}
14578
14734
  `;
14579
14735
  if (Buffer.byteLength(body) > this.#maxBytes) throw new Error(`Session exceeds maximum size of ${this.#maxBytes} bytes`);
14580
- const temporary = join19(this.#sessions, `.${document.sessionId}.${process.pid}.${randomUUID12()}.tmp`);
14736
+ const temporary = join20(this.#sessions, `.${document.sessionId}.${process.pid}.${randomUUID13()}.tmp`);
14581
14737
  let handle;
14582
14738
  try {
14583
14739
  handle = await open8(temporary, constants5.O_CREAT | constants5.O_EXCL | constants5.O_WRONLY, 384);
@@ -14694,7 +14850,7 @@ var SessionStore = class {
14694
14850
  const metadata = await lstat9(path);
14695
14851
  if (!metadata.isFile()) throw new Error("Session path is not a regular file");
14696
14852
  await rm6(path);
14697
- await rm6(join19(this.#sessions, `${sessionId}.events.jsonl`), { force: true }).catch(() => void 0);
14853
+ await rm6(join20(this.#sessions, `${sessionId}.events.jsonl`), { force: true }).catch(() => void 0);
14698
14854
  } catch (error) {
14699
14855
  if (!isCode7(error, "ENOENT")) throw error;
14700
14856
  }
@@ -14711,7 +14867,7 @@ var SessionStore = class {
14711
14867
  const excess = entries.slice(this.#maxSessions);
14712
14868
  for (const entry2 of excess) {
14713
14869
  await rm6(this.#path(entry2.sessionId), { force: true }).catch(() => void 0);
14714
- await rm6(join19(this.#sessions, `${entry2.sessionId}.events.jsonl`), { force: true }).catch(() => void 0);
14870
+ await rm6(join20(this.#sessions, `${entry2.sessionId}.events.jsonl`), { force: true }).catch(() => void 0);
14715
14871
  }
14716
14872
  }
14717
14873
  async #assertWorkspace(stored) {
@@ -14733,7 +14889,7 @@ var SessionStore = class {
14733
14889
  if (!isWithin5(canonicalRoot, canonicalSessions)) throw new Error("Session directory escapes the workspace");
14734
14890
  }
14735
14891
  async #quarantine(path) {
14736
- const target = `${path}.corrupt-${Date.now()}-${randomUUID12().slice(0, 8)}`;
14892
+ const target = `${path}.corrupt-${Date.now()}-${randomUUID13().slice(0, 8)}`;
14737
14893
  await rename6(path, target);
14738
14894
  return target;
14739
14895
  }
@@ -14953,9 +15109,9 @@ function sanitize2(input, seen = /* @__PURE__ */ new WeakSet()) {
14953
15109
 
14954
15110
  // src/sleep/organizer.ts
14955
15111
  import { constants as constants6 } from "fs";
14956
- import { randomUUID as randomUUID13 } from "crypto";
15112
+ import { randomUUID as randomUUID14 } from "crypto";
14957
15113
  import { lstat as lstat10, mkdir as mkdir15, open as open9, readdir as readdir7, realpath as realpath8, rename as rename7, rm as rm7 } from "fs/promises";
14958
- import { isAbsolute as isAbsolute8, join as join20, relative as relative14, resolve as resolve19, sep as sep14 } from "path";
15114
+ import { isAbsolute as isAbsolute8, join as join21, relative as relative14, resolve as resolve19, sep as sep14 } from "path";
14959
15115
  import { z as z23 } from "zod";
14960
15116
  var DateKeySchema = z23.string().regex(/^\d{4}-\d{2}-\d{2}$/);
14961
15117
  var ReviewSchema = z23.object({
@@ -15010,7 +15166,7 @@ var ProjectSleepOrganizer = class {
15010
15166
  #generate;
15011
15167
  constructor(options) {
15012
15168
  this.#workspace = resolve19(options.workspace);
15013
- this.#sleepDirectory = join20(this.#workspace, ".flavor", "sleep");
15169
+ this.#sleepDirectory = join21(this.#workspace, ".flavor", "sleep");
15014
15170
  this.#sessions = options.sessions ?? new SessionStore({ workspace: this.#workspace });
15015
15171
  this.#generate = options.generate;
15016
15172
  }
@@ -15019,7 +15175,7 @@ var ProjectSleepOrganizer = class {
15019
15175
  signal.throwIfAborted();
15020
15176
  await this.#prepareDirectory();
15021
15177
  if (await this.#hasReport(date)) return { status: "exists", date };
15022
- const lockPath = join20(this.#sleepDirectory, `.${date}.lock`);
15178
+ const lockPath = join21(this.#sleepDirectory, `.${date}.lock`);
15023
15179
  let lock;
15024
15180
  try {
15025
15181
  lock = await open9(lockPath, constants6.O_CREAT | constants6.O_EXCL | constants6.O_WRONLY, 384);
@@ -15054,7 +15210,7 @@ Previous output was invalid. Repair it and return strict JSON only.`;
15054
15210
  }
15055
15211
  if (review === void 0) throw lastError;
15056
15212
  const filename2 = `${date}-${filenameSummary(review.title)}.md`;
15057
- const path = join20(this.#sleepDirectory, filename2);
15213
+ const path = join21(this.#sleepDirectory, filename2);
15058
15214
  const markdown = renderSleepReport(date, review, documents);
15059
15215
  await this.#atomicWrite(path, markdown);
15060
15216
  return { status: "written", date, path, sessionCount: documents.length };
@@ -15096,7 +15252,7 @@ Previous output was invalid. Repair it and return strict JSON only.`;
15096
15252
  });
15097
15253
  }
15098
15254
  async #prepareDirectory() {
15099
- const flavorDirectory = join20(this.#workspace, ".flavor");
15255
+ const flavorDirectory = join21(this.#workspace, ".flavor");
15100
15256
  await assertNotSymlink(flavorDirectory);
15101
15257
  await mkdir15(flavorDirectory, { recursive: true, mode: 448 });
15102
15258
  await assertNotSymlink(this.#sleepDirectory);
@@ -15110,7 +15266,7 @@ Previous output was invalid. Repair it and return strict JSON only.`;
15110
15266
  return (await readdir7(this.#sleepDirectory, { withFileTypes: true })).some((entry2) => entry2.isFile() && entry2.name.startsWith(prefix) && entry2.name.endsWith(".md"));
15111
15267
  }
15112
15268
  async #atomicWrite(path, content) {
15113
- const temporary = join20(this.#sleepDirectory, `.${randomUUID13()}.tmp`);
15269
+ const temporary = join21(this.#sleepDirectory, `.${randomUUID14()}.tmp`);
15114
15270
  let handle;
15115
15271
  try {
15116
15272
  handle = await open9(temporary, constants6.O_CREAT | constants6.O_EXCL | constants6.O_WRONLY, 384);
@@ -15486,7 +15642,7 @@ function computeSessionStats(documents) {
15486
15642
  import { constants as constants7 } from "fs";
15487
15643
  import { mkdir as mkdir16, open as open10, readFile as readFile17, realpath as realpath9, rename as rename8, rm as rm8, stat as stat7 } from "fs/promises";
15488
15644
  import { dirname as dirname16, isAbsolute as isAbsolute9, relative as relative15, resolve as resolve20, sep as sep15 } from "path";
15489
- import { randomUUID as randomUUID14 } from "crypto";
15645
+ import { randomUUID as randomUUID15 } from "crypto";
15490
15646
  import { z as z24 } from "zod";
15491
15647
 
15492
15648
  // src/tools/file-diff.ts
@@ -15839,7 +15995,7 @@ function createPathGuard(workspace) {
15839
15995
  async function atomicWrite(path, content, signal, expectedVersion) {
15840
15996
  abortIfNeeded(signal);
15841
15997
  await mkdir16(dirname16(path), { recursive: true });
15842
- const temporary = `${path}.${randomUUID14()}.tmp`;
15998
+ const temporary = `${path}.${randomUUID15()}.tmp`;
15843
15999
  try {
15844
16000
  const handle = await open10(temporary, constants7.O_CREAT | constants7.O_EXCL | constants7.O_WRONLY, 384);
15845
16001
  try {
@@ -17371,9 +17527,9 @@ function createTodoWriteTool() {
17371
17527
  }
17372
17528
 
17373
17529
  // src/tools/managed.ts
17374
- import { randomUUID as randomUUID15 } from "crypto";
17375
- import { link as link2, lstat as lstat11, mkdir as mkdir17, readFile as readFile19, readdir as readdir8, unlink as unlink4, writeFile as writeFile10 } from "fs/promises";
17376
- import { dirname as dirname18, join as join21, resolve as resolve22 } from "path";
17530
+ import { randomUUID as randomUUID16 } from "crypto";
17531
+ import { link as link2, lstat as lstat11, mkdir as mkdir17, readFile as readFile19, readdir as readdir8, unlink as unlink5, writeFile as writeFile10 } from "fs/promises";
17532
+ import { dirname as dirname18, join as join22, resolve as resolve22 } from "path";
17377
17533
  import { z as z31 } from "zod";
17378
17534
  var MANAGED_TOOL_VERSION = 1;
17379
17535
  var MAX_RECORD_BYTES = 256 * 1024;
@@ -17416,8 +17572,8 @@ var ManagedToolStore = class {
17416
17572
  #diagnostics = [];
17417
17573
  constructor(options) {
17418
17574
  this.#workspace = resolve22(options.workspace);
17419
- this.#projectRoot = join21(this.#workspace, ".flavor", "tools");
17420
- this.#globalRoot = join21(resolve22(options.home), ".flavor-code", "tools");
17575
+ this.#projectRoot = join22(this.#workspace, ".flavor", "tools");
17576
+ this.#globalRoot = join22(resolve22(options.home), ".flavor-code", "tools");
17421
17577
  this.#now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
17422
17578
  }
17423
17579
  get diagnostics() {
@@ -17464,7 +17620,7 @@ var ManagedToolStore = class {
17464
17620
  version: MANAGED_TOOL_VERSION,
17465
17621
  createdAt: this.#now()
17466
17622
  });
17467
- const path = join21(this.directory(input.scope), filename(input.name));
17623
+ const path = join22(this.directory(input.scope), filename(input.name));
17468
17624
  const definition = compileDefinition(record, input.scope, this.#workspace);
17469
17625
  await writeExclusive(path, `${JSON.stringify(record, void 0, 2)}
17470
17626
  `);
@@ -17480,7 +17636,7 @@ var ManagedToolStore = class {
17480
17636
  const entry2 = matches[0];
17481
17637
  const info = await lstat11(entry2.path);
17482
17638
  if (!info.isFile() || info.isSymbolicLink()) throw new Error(`Managed tool path is no longer a regular file: ${entry2.path}`);
17483
- await unlink4(entry2.path);
17639
+ await unlink5(entry2.path);
17484
17640
  this.#entries.delete(scopedKey(entry2.scope, entry2.record.name));
17485
17641
  return summary(entry2, false);
17486
17642
  }
@@ -17489,7 +17645,7 @@ var ManagedToolStore = class {
17489
17645
  if (!parsed.success) return [];
17490
17646
  const matches = this.#matching(parsed.data.name).filter((entry2) => parsed.data.scope === void 0 || entry2.scope === parsed.data.scope);
17491
17647
  if (matches.length > 0) return matches.map((entry2) => entry2.path);
17492
- return [join21(this.directory(parsed.data.scope ?? "project"), filename(parsed.data.name))];
17648
+ return [join22(this.directory(parsed.data.scope ?? "project"), filename(parsed.data.name))];
17493
17649
  }
17494
17650
  async #loadDirectory(scope2) {
17495
17651
  const root = this.directory(scope2);
@@ -17502,7 +17658,7 @@ var ManagedToolStore = class {
17502
17658
  return;
17503
17659
  }
17504
17660
  for (const name of names) {
17505
- const path = join21(root, name);
17661
+ const path = join22(root, name);
17506
17662
  try {
17507
17663
  const info = await lstat11(path);
17508
17664
  if (!info.isFile() || info.isSymbolicLink()) throw new Error("Managed tool record must be a regular file");
@@ -17658,13 +17814,13 @@ ${sourceUrl}`
17658
17814
  }
17659
17815
  async function writeExclusive(path, content) {
17660
17816
  await mkdir17(dirname18(path), { recursive: true });
17661
- const temporary = `${path}.${randomUUID15()}.tmp`;
17817
+ const temporary = `${path}.${randomUUID16()}.tmp`;
17662
17818
  try {
17663
17819
  await writeFile10(temporary, content, { encoding: "utf8", flag: "wx", mode: 384 });
17664
17820
  await link2(temporary, path);
17665
17821
  } finally {
17666
17822
  try {
17667
- await unlink4(temporary);
17823
+ await unlink5(temporary);
17668
17824
  } catch {
17669
17825
  }
17670
17826
  }
@@ -18048,7 +18204,7 @@ function buildWarningMessages(report, languageTag) {
18048
18204
  }
18049
18205
 
18050
18206
  // src/hallucination/sliding-window.ts
18051
- import { createHash as createHash14 } from "crypto";
18207
+ import { createHash as createHash15 } from "crypto";
18052
18208
  var SlidingWindow = class {
18053
18209
  #windowSize;
18054
18210
  #threshold;
@@ -18064,7 +18220,7 @@ var SlidingWindow = class {
18064
18220
  }
18065
18221
  hash(toolName, params) {
18066
18222
  const sorted = JSON.stringify(params, sortedKeys(params));
18067
- return createHash14("sha256").update(`${toolName}:${sorted}`).digest("hex");
18223
+ return createHash15("sha256").update(`${toolName}:${sorted}`).digest("hex");
18068
18224
  }
18069
18225
  push(toolName, params) {
18070
18226
  const hash = this.hash(toolName, params);
@@ -18419,9 +18575,9 @@ ${total}`;
18419
18575
  }
18420
18576
 
18421
18577
  // src/memory/store.ts
18422
- import { createHash as createHash15 } from "crypto";
18578
+ import { createHash as createHash16 } from "crypto";
18423
18579
  import { readFile as readFile20, rm as rm9 } from "fs/promises";
18424
- import { resolve as resolve23, join as join22, relative as relative17, sep as sep17 } from "path";
18580
+ import { resolve as resolve23, join as join23, relative as relative17, sep as sep17 } from "path";
18425
18581
 
18426
18582
  // src/memory/similarity.ts
18427
18583
  function normalizeForSimilarity(value) {
@@ -18524,9 +18680,9 @@ var MemoryStore = class {
18524
18680
  if (!Number.isSafeInteger(options.maxEntries) || options.maxEntries < 1) throw new Error("maxEntries must be an integer of at least 1");
18525
18681
  if (!Number.isSafeInteger(options.maxEntryChars) || options.maxEntryChars < 1) throw new Error("maxEntryChars must be an integer of at least 1");
18526
18682
  this.workspace = resolve23(options.workspace);
18527
- this.#memoryRoot = join22(this.workspace, ".flavor", "memory");
18528
- this.path = join22(this.#memoryRoot, "MEMORY.md");
18529
- this.#behaviorPath = join22(this.#memoryRoot, "behavior.json");
18683
+ this.#memoryRoot = join23(this.workspace, ".flavor", "memory");
18684
+ this.path = join23(this.#memoryRoot, "MEMORY.md");
18685
+ this.#behaviorPath = join23(this.#memoryRoot, "behavior.json");
18530
18686
  this.#maxEntries = options.maxEntries;
18531
18687
  this.#maxEntryChars = options.maxEntryChars;
18532
18688
  }
@@ -18905,7 +19061,7 @@ function sanitizeTopicKey(value) {
18905
19061
  return value.normalize("NFKC").toLocaleLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 128);
18906
19062
  }
18907
19063
  function memoryId(type, content) {
18908
- return createHash15("sha256").update(`${type}\0${normalizeMemoryContent(content).toLocaleLowerCase()}`, "utf8").digest("hex").slice(0, 12);
19064
+ return createHash16("sha256").update(`${type}\0${normalizeMemoryContent(content).toLocaleLowerCase()}`, "utf8").digest("hex").slice(0, 12);
18909
19065
  }
18910
19066
  function assertTaskId(taskId) {
18911
19067
  if (!TASK_ID.test(taskId)) throw new Error(`Invalid memory task id: ${taskId}`);
@@ -19221,7 +19377,7 @@ function createExecutionEnvironment(workspace, config) {
19221
19377
 
19222
19378
  // src/ide/client.ts
19223
19379
  import { readFile as readFile21, readdir as readdir9, stat as stat8 } from "fs/promises";
19224
- import { basename as basename5, join as join23, relative as relative18, resolve as resolve24, sep as sep18 } from "path";
19380
+ import { basename as basename5, join as join24, relative as relative18, resolve as resolve24, sep as sep18 } from "path";
19225
19381
  var FlavorIdeClient = class {
19226
19382
  #workspace;
19227
19383
  #home;
@@ -19317,7 +19473,7 @@ var FlavorIdeClient = class {
19317
19473
  };
19318
19474
  if (await this.#healthy(configured)) return configured;
19319
19475
  }
19320
- const directory = join23(this.#home, ".flavor-code", "ide");
19476
+ const directory = join24(this.#home, ".flavor-code", "ide");
19321
19477
  let entries;
19322
19478
  try {
19323
19479
  entries = (await readdir9(directory)).filter((name) => name.endsWith(".lock"));
@@ -19325,7 +19481,7 @@ var FlavorIdeClient = class {
19325
19481
  return void 0;
19326
19482
  }
19327
19483
  const candidates = (await Promise.all(entries.map(async (name) => {
19328
- const path = join23(directory, name);
19484
+ const path = join24(directory, name);
19329
19485
  try {
19330
19486
  const [contents, info] = await Promise.all([readFile21(path, "utf8"), stat8(path)]);
19331
19487
  const lock = parseLockfile(contents);
@@ -19445,7 +19601,7 @@ function relativeDisplay(workspace, filePath) {
19445
19601
  }
19446
19602
 
19447
19603
  // src/jobs/registry.ts
19448
- import { randomUUID as randomUUID16 } from "crypto";
19604
+ import { randomUUID as randomUUID17 } from "crypto";
19449
19605
  var JobRegistry = class {
19450
19606
  #jobs = /* @__PURE__ */ new Map();
19451
19607
  #maxOutputChars;
@@ -19459,7 +19615,7 @@ var JobRegistry = class {
19459
19615
  }
19460
19616
  create(input) {
19461
19617
  this.#pruneCompleted();
19462
- const id = `job-${randomUUID16().slice(0, 12)}`;
19618
+ const id = `job-${randomUUID17().slice(0, 12)}`;
19463
19619
  const now = (/* @__PURE__ */ new Date()).toISOString();
19464
19620
  let settle;
19465
19621
  const done = new Promise((resolve28) => {
@@ -19585,7 +19741,7 @@ function snapshot2(job) {
19585
19741
  }
19586
19742
 
19587
19743
  // src/terminal/service.ts
19588
- import { randomUUID as randomUUID17 } from "crypto";
19744
+ import { randomUUID as randomUUID18 } from "crypto";
19589
19745
  import { createRequire as nodeCreateRequire } from "module";
19590
19746
  import { isAbsolute as isAbsolute11, relative as relative19, resolve as resolve25, sep as sep19 } from "path";
19591
19747
  var TerminalService = class {
@@ -19603,7 +19759,7 @@ var TerminalService = class {
19603
19759
  open(input) {
19604
19760
  const cwd = workspacePath(this.#root, input.cwd ?? ".");
19605
19761
  const shell = input.shell ?? defaultShell();
19606
- const id = `term-${randomUUID17().slice(0, 12)}`;
19762
+ const id = `term-${randomUUID18().slice(0, 12)}`;
19607
19763
  const pty = this.#factory(shell, input.args ?? [], {
19608
19764
  cwd,
19609
19765
  cols: input.columns ?? 100,
@@ -19813,10 +19969,10 @@ function createTerminalTools(terminals, workspace = process.cwd()) {
19813
19969
  }
19814
19970
 
19815
19971
  // src/pals/address.ts
19816
- import { createHash as createHash16 } from "crypto";
19972
+ import { createHash as createHash17 } from "crypto";
19817
19973
  function opaqueUserScope(userScope) {
19818
19974
  if (userScope.length === 0) throw new Error("User scope must not be empty");
19819
- const digest = createHash16("sha256").update(userScope, "utf8").digest("hex").slice(0, 16);
19975
+ const digest = createHash17("sha256").update(userScope, "utf8").digest("hex").slice(0, 16);
19820
19976
  return `u-${digest}`;
19821
19977
  }
19822
19978
  function palSocketAddress(options) {
@@ -19829,7 +19985,7 @@ function palSocketAddress(options) {
19829
19985
  }
19830
19986
 
19831
19987
  // src/pals/client.ts
19832
- import { randomUUID as randomUUID18 } from "crypto";
19988
+ import { randomUUID as randomUUID19 } from "crypto";
19833
19989
  import { Socket as Socket3 } from "net";
19834
19990
  var DEFAULT_REQUEST_TIMEOUT_MS = 5e3;
19835
19991
  var DEFAULT_HEARTBEAT_INTERVAL_MS = 1e4;
@@ -19905,7 +20061,7 @@ var PalClient = class {
19905
20061
  return this.starting;
19906
20062
  }
19907
20063
  async list() {
19908
- const data2 = await this.request({ version: 1, type: "list", requestId: randomUUID18() });
20064
+ const data2 = await this.request({ version: 1, type: "list", requestId: randomUUID19() });
19909
20065
  return PalPresenceListSchema.parse(data2);
19910
20066
  }
19911
20067
  async rename(alias) {
@@ -19918,38 +20074,38 @@ var PalClient = class {
19918
20074
  throw error;
19919
20075
  }
19920
20076
  }
19921
- async sendTask(target, message2, messageId = randomUUID18()) {
19922
- const data2 = await this.request({ version: 1, type: "task", requestId: randomUUID18(), messageId, target, goal: message2 });
20077
+ async sendTask(target, message2, messageId = randomUUID19()) {
20078
+ const data2 = await this.request({ version: 1, type: "task", requestId: randomUUID19(), messageId, target, goal: message2 });
19923
20079
  return DeliveryReceiptSchema.parse(data2);
19924
20080
  }
19925
- async sendChat(target, message2, messageId = randomUUID18()) {
19926
- const data2 = await this.request({ version: 1, type: "chat", requestId: randomUUID18(), messageId, target, message: message2 });
20081
+ async sendChat(target, message2, messageId = randomUUID19()) {
20082
+ const data2 = await this.request({ version: 1, type: "chat", requestId: randomUUID19(), messageId, target, message: message2 });
19927
20083
  return DeliveryReceiptSchema.parse(data2);
19928
20084
  }
19929
20085
  async startCoWork(input) {
19930
20086
  const data2 = await this.request({
19931
20087
  version: 1,
19932
20088
  type: "cowork-propose",
19933
- requestId: randomUUID18(),
19934
- coWorkId: input.coWorkId ?? randomUUID18(),
20089
+ requestId: randomUUID19(),
20090
+ coWorkId: input.coWorkId ?? randomUUID19(),
19935
20091
  goal: input.goal,
19936
20092
  participants: input.participants
19937
20093
  });
19938
20094
  return CoWorkSnapshotSchema.parse(data2);
19939
20095
  }
19940
20096
  async coWorkAction(action) {
19941
- const request = { version: 1, requestId: randomUUID18(), ...action };
20097
+ const request = { version: 1, requestId: randomUUID19(), ...action };
19942
20098
  return CoWorkSnapshotSchema.parse(await this.request(request));
19943
20099
  }
19944
20100
  async coWorkStatus(coWorkId) {
19945
- const data2 = await this.request({ version: 1, type: "cowork-get", requestId: randomUUID18(), coWorkId });
20101
+ const data2 = await this.request({ version: 1, type: "cowork-get", requestId: randomUUID19(), coWorkId });
19946
20102
  return CoWorkSnapshotSchema.parse(data2);
19947
20103
  }
19948
20104
  async integrateCoWork(input) {
19949
20105
  return this.coWorkAction({ type: "cowork-integration", ...input });
19950
20106
  }
19951
20107
  async cancelCoWork(coWorkId, reason) {
19952
- const data2 = await this.request({ version: 1, type: "cowork-cancel", requestId: randomUUID18(), coWorkId, reason });
20108
+ const data2 = await this.request({ version: 1, type: "cowork-cancel", requestId: randomUUID19(), coWorkId, reason });
19953
20109
  return CoWorkSnapshotSchema.parse(data2);
19954
20110
  }
19955
20111
  subscribe(listener) {
@@ -19961,7 +20117,7 @@ var PalClient = class {
19961
20117
  if (this.registered && this.socket !== void 0) {
19962
20118
  let disconnectTimer;
19963
20119
  await Promise.race([
19964
- this.request({ version: 1, type: "disconnect", requestId: randomUUID18() }).catch(() => void 0),
20120
+ this.request({ version: 1, type: "disconnect", requestId: randomUUID19() }).catch(() => void 0),
19965
20121
  new Promise((resolve28) => {
19966
20122
  disconnectTimer = setTimeout(resolve28, Math.min(this.requestTimeoutMs, 250));
19967
20123
  })
@@ -20052,7 +20208,7 @@ var PalClient = class {
20052
20208
  const data2 = await this.request({
20053
20209
  version: 1,
20054
20210
  type: "register",
20055
- requestId: randomUUID18(),
20211
+ requestId: randomUUID19(),
20056
20212
  authToken: this.authToken,
20057
20213
  presence: { version: 1, ...this.registration, connectedAt: now, lastSeenAt: now }
20058
20214
  });
@@ -20164,7 +20320,7 @@ var PalClient = class {
20164
20320
  if (!this.registered) return;
20165
20321
  if (this.heartbeatPending) return;
20166
20322
  this.heartbeatPending = true;
20167
- void this.request({ version: 1, type: "heartbeat", requestId: randomUUID18() }).catch(() => void 0).finally(() => {
20323
+ void this.request({ version: 1, type: "heartbeat", requestId: randomUUID19() }).catch(() => void 0).finally(() => {
20168
20324
  this.heartbeatPending = false;
20169
20325
  });
20170
20326
  }, this.heartbeatIntervalMs);
@@ -20451,7 +20607,7 @@ var ApprovalBridge = class {
20451
20607
  request(request, signal = new AbortController().signal) {
20452
20608
  if (this.#settle !== void 0) return Promise.resolve("deny");
20453
20609
  if (signal.aborted) return Promise.resolve("deny");
20454
- this.#pending = { id: randomUUID19(), ...request };
20610
+ this.#pending = { id: randomUUID20(), ...request };
20455
20611
  this.#onChange?.();
20456
20612
  return new Promise((resolvePromise) => {
20457
20613
  this.#settle = resolvePromise;
@@ -20571,11 +20727,17 @@ async function createProductionRuntime(options) {
20571
20727
  environment.ANTHROPIC_API_KEY
20572
20728
  ].filter((value) => typeof value === "string" && value.length > 0);
20573
20729
  let hookSessionId;
20730
+ let islandControlMetadata;
20574
20731
  const hooks = new HookBus({
20575
20732
  eventContext: () => ({
20576
20733
  protocolVersion: 2,
20577
20734
  workspace,
20578
- ...hookSessionId === void 0 ? {} : { sessionId: hookSessionId }
20735
+ ...hookSessionId === void 0 ? {} : { sessionId: hookSessionId },
20736
+ ...islandControlMetadata === void 0 ? {} : {
20737
+ islandControlEndpoint: islandControlMetadata.endpoint,
20738
+ islandControlToken: islandControlMetadata.token,
20739
+ islandControlCapabilities: islandControlMetadata.capabilities
20740
+ }
20579
20741
  })
20580
20742
  });
20581
20743
  hooks.on(
@@ -20690,8 +20852,8 @@ async function createProductionRuntime(options) {
20690
20852
  const registeredProviders = registration.registered;
20691
20853
  let effectiveLlm = registration.effectiveLlm;
20692
20854
  const pluginHost = new PluginHost({
20693
- globalPluginDirs: [join24(home, ".flavor-code", "plugins")],
20694
- projectPluginDirs: [join24(workspace, ".flavor", "plugins")],
20855
+ globalPluginDirs: [join25(home, ".flavor-code", "plugins")],
20856
+ projectPluginDirs: [join25(workspace, ".flavor", "plugins")],
20695
20857
  config,
20696
20858
  // Existing project plugins (including astgraph and superharness) use Node.js
20697
20859
  // built-ins. The Worker/vm sandbox deliberately blocks those imports, so it
@@ -20765,6 +20927,7 @@ async function createProductionRuntime(options) {
20765
20927
  const pendingCollaborationEvents = [];
20766
20928
  let collaborationEventPump;
20767
20929
  let collaborationEventsOpen = true;
20930
+ let islandControlServer;
20768
20931
  const pumpCollaborationEvents = () => {
20769
20932
  if (collaborationEventPump !== void 0 || collaborationSession === void 0 || deliverCollaborationEvent === void 0) return;
20770
20933
  collaborationEventPump = (async () => {
@@ -20798,7 +20961,7 @@ async function createProductionRuntime(options) {
20798
20961
  const address = palSocketAddress({
20799
20962
  platform: process.platform,
20800
20963
  userScope: home,
20801
- runtimeDir: join24(tmpdir3(), `flavor-code-pals-${createHash17("sha256").update(home).digest("hex").slice(0, 16)}`)
20964
+ runtimeDir: join25(tmpdir4(), `flavor-code-pals-${createHash18("sha256").update(home).digest("hex").slice(0, 16)}`)
20802
20965
  });
20803
20966
  const baseCollaborationClient = collaboration.client ?? collaboration.createClient?.({
20804
20967
  instanceId: collaboration.instanceId,
@@ -20909,8 +21072,8 @@ async function createProductionRuntime(options) {
20909
21072
  diagnostics.push(`MCP servers could not start: ${message(error)}`);
20910
21073
  });
20911
21074
  const skills = new SkillRegistry({
20912
- globalRoots: [join24(home, ".flavor-code", "skills")],
20913
- projectRoots: [join24(workspace, ".flavor", "skills"), ...pluginSkillRoots],
21075
+ globalRoots: [join25(home, ".flavor-code", "skills")],
21076
+ projectRoots: [join25(workspace, ".flavor", "skills"), ...pluginSkillRoots],
20914
21077
  authorizeResource: async () => true,
20915
21078
  disabledNames: config.skills.disabled
20916
21079
  });
@@ -20918,7 +21081,7 @@ async function createProductionRuntime(options) {
20918
21081
  skillsReady.catch(() => void 0);
20919
21082
  tools.push(createSkillTool(skills), createSkillResourceTool(skills));
20920
21083
  if (options.extraTools !== void 0) tools.push(...options.extraTools);
20921
- const flavor = await optionalText2(join24(workspace, "FLAVOR.md"));
21084
+ const flavor = await optionalText2(join25(workspace, "FLAVOR.md"));
20922
21085
  const instructionBaseline = await workspaceInstructions.baseline();
20923
21086
  let memoryContext;
20924
21087
  if (memoryStore !== void 0) {
@@ -20942,7 +21105,7 @@ async function createProductionRuntime(options) {
20942
21105
  let taskResults = { ...recovered?.tasks.results ?? {} };
20943
21106
  const subagentStartedAt = {};
20944
21107
  const subagentElapsedMs = {};
20945
- let sessionId = recovered?.sessionId ?? `session-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "").slice(0, 17)}-${randomUUID19().slice(0, 8)}`;
21108
+ let sessionId = recovered?.sessionId ?? `session-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "").slice(0, 17)}-${randomUUID20().slice(0, 8)}`;
20946
21109
  hookSessionId = sessionId;
20947
21110
  let harnessJournal = new HarnessJournal({ workspace, sessionId });
20948
21111
  const harnessRecovery = harnessJournal.recover();
@@ -21452,7 +21615,7 @@ async function createProductionRuntime(options) {
21452
21615
  evolveService.toolDefinition(),
21453
21616
  ...mcpTools
21454
21617
  ];
21455
- const loopFlavor = await optionalText2(join24(input.workspace, "FLAVOR.md"));
21618
+ const loopFlavor = await optionalText2(join25(input.workspace, "FLAVOR.md"));
21456
21619
  const loopInstructionBaseline = await loopInstructions.baseline();
21457
21620
  const loopEnvironment = createPromptEnvironment({
21458
21621
  now: /* @__PURE__ */ new Date(),
@@ -21591,7 +21754,7 @@ async function createProductionRuntime(options) {
21591
21754
  return answers[0] === "Continue" ? "approved" : "rejected";
21592
21755
  },
21593
21756
  fingerprint: workspaceFingerprint,
21594
- idFactory: () => `loop-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "").slice(0, 17)}-${randomUUID19().slice(0, 8)}`
21757
+ idFactory: () => `loop-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "").slice(0, 17)}-${randomUUID20().slice(0, 8)}`
21595
21758
  });
21596
21759
  const goalStore = new GoalStore({ workspace });
21597
21760
  const goalOrchestrator = new GoalOrchestrator({
@@ -21610,7 +21773,7 @@ async function createProductionRuntime(options) {
21610
21773
  executionEnvironment
21611
21774
  ),
21612
21775
  now: () => (/* @__PURE__ */ new Date()).toISOString(),
21613
- idFactory: () => `goal-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "").slice(0, 17)}-${randomUUID19().slice(0, 8)}`,
21776
+ idFactory: () => `goal-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "").slice(0, 17)}-${randomUUID20().slice(0, 8)}`,
21614
21777
  runWorker: ({ workspace: goalWorkspace, prompt, signal }) => runLoopWorker({ workspace: goalWorkspace, prompt, signal })
21615
21778
  });
21616
21779
  let sessionHistory = await SessionHistory.open({
@@ -21881,7 +22044,7 @@ ${summary2}`;
21881
22044
  for (const key of Object.keys(subagentStartedAt)) delete subagentStartedAt[key];
21882
22045
  for (const key of Object.keys(subagentElapsedMs)) delete subagentElapsedMs[key];
21883
22046
  const previousIdeSessionId = ideSessionId;
21884
- sessionId = `session-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "").slice(0, 17)}-${randomUUID19().slice(0, 8)}`;
22047
+ sessionId = `session-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "").slice(0, 17)}-${randomUUID20().slice(0, 8)}`;
21885
22048
  hookSessionId = sessionId;
21886
22049
  harnessJournal = new HarnessJournal({ workspace, sessionId });
21887
22050
  setUsageSession(sessionId);
@@ -21982,7 +22145,7 @@ ${renderMemoryDocument(entries)}`;
21982
22145
  return `Provider "${providerName}" is missing authorizationUrl, tokenUrl, or clientId.`;
21983
22146
  }
21984
22147
  try {
21985
- const tokenStore = createFileTokenStore(join24(home, ".flavor-code", "auth.json"));
22148
+ const tokenStore = createFileTokenStore(join25(home, ".flavor-code", "auth.json"));
21986
22149
  const credentialId = oauthCredentialId(oauthConfig.tokenUrl, oauthConfig.clientId);
21987
22150
  await migrateLegacyOAuthToken(tokenStore, providerName, credentialId);
21988
22151
  const oauth = new OAuthCallbackAuthProvider({
@@ -22025,7 +22188,7 @@ ${renderMemoryDocument(entries)}`;
22025
22188
  }
22026
22189
  },
22027
22190
  async logout() {
22028
- const tokenStore = createFileTokenStore(join24(home, ".flavor-code", "auth.json"));
22191
+ const tokenStore = createFileTokenStore(join25(home, ".flavor-code", "auth.json"));
22029
22192
  const tokens = await tokenStore.load();
22030
22193
  const hadCredentials = Object.keys(tokens).length > 0 || effectiveLlm !== void 0;
22031
22194
  if (!hadCredentials) {
@@ -22082,6 +22245,22 @@ ${renderMemoryDocument(entries)}`;
22082
22245
  sleepScheduler.start();
22083
22246
  }
22084
22247
  const session = new FlavorSession(services);
22248
+ if (pluginHost.loadedPlugins.some((plugin) => plugin.name === "flavor-island")) {
22249
+ try {
22250
+ islandControlServer = await createIslandControlServer({
22251
+ sessionId,
22252
+ session,
22253
+ ...options.islandControl?.focus === void 0 ? {} : { focus: options.islandControl.focus }
22254
+ });
22255
+ islandControlMetadata = {
22256
+ endpoint: islandControlServer.endpoint,
22257
+ token: islandControlServer.token,
22258
+ capabilities: islandControlServer.capabilities
22259
+ };
22260
+ } catch (error) {
22261
+ diagnostics.push(`Flavor Island control channel unavailable: ${message(error)}`);
22262
+ }
22263
+ }
22085
22264
  collaborationSession = session;
22086
22265
  pumpCollaborationEvents();
22087
22266
  const authorization = {
@@ -22117,6 +22296,7 @@ ${renderMemoryDocument(entries)}`;
22117
22296
  if (persistTail !== void 0) await boundedStep(stepTimeoutMs, diagnostics, "persist-tail", persistTail);
22118
22297
  if (ideSessionId !== void 0) await boundedStep(stepTimeoutMs, diagnostics, "ide-end-session", ide.endSession(ideSessionId));
22119
22298
  if (executionEnvironment !== void 0) await boundedStep(stepTimeoutMs, diagnostics, "execution-environment", executionEnvironment.dispose());
22299
+ if (islandControlServer !== void 0) await boundedStep(stepTimeoutMs, diagnostics, "island-control", islandControlServer.close());
22120
22300
  terminals.dispose();
22121
22301
  await boundedStep(stepTimeoutMs, diagnostics, "jobs", jobs.dispose());
22122
22302
  auditLogger.close();
@@ -22130,6 +22310,7 @@ ${renderMemoryDocument(entries)}`;
22130
22310
  collaborationEventsOpen = false;
22131
22311
  mcpDiscarded = true;
22132
22312
  memoryReviews.dispose();
22313
+ await islandControlServer?.close().catch(() => void 0);
22133
22314
  try {
22134
22315
  const stepTimeoutMs = options.shutdownStepTimeoutMs ?? DEFAULT_SHUTDOWN_STEP_TIMEOUT_MS;
22135
22316
  if (ideSessionId !== void 0) await boundedStep(stepTimeoutMs, diagnostics, "ide-end-session", ide.endSession(ideSessionId));
@@ -22267,7 +22448,7 @@ function terminalProgressState(status) {
22267
22448
  return "failed";
22268
22449
  }
22269
22450
  async function workspaceFingerprint(workspace) {
22270
- const hash = createHash17("sha256");
22451
+ const hash = createHash18("sha256");
22271
22452
  const diff = await execFileNoThrow(
22272
22453
  "git",
22273
22454
  ["-C", workspace, "diff", "--no-ext-diff", "--binary", "HEAD"],
@@ -22502,7 +22683,7 @@ async function registerConfiguredAdapters(providers, registry, environment, diag
22502
22683
  const configured = { ...providers };
22503
22684
  if (configured.openai === void 0 && environment.OPENAI_API_KEY) configured.openai = { type: "openai", apiKey: environment.OPENAI_API_KEY };
22504
22685
  if (configured.anthropic === void 0 && environment.ANTHROPIC_API_KEY) configured.anthropic = { type: "anthropic", apiKey: environment.ANTHROPIC_API_KEY };
22505
- const oauthTokenStore = createFileTokenStore(join24(home, ".flavor-code", "auth.json"));
22686
+ const oauthTokenStore = createFileTokenStore(join25(home, ".flavor-code", "auth.json"));
22506
22687
  const registered = [];
22507
22688
  let effectiveLlm;
22508
22689
  for (const [name, provider] of Object.entries(configured)) {
@@ -22921,10 +23102,10 @@ async function* runGoalSession(orchestrator, goal, signal) {
22921
23102
  }
22922
23103
  function memoryTranscriptHash(messages) {
22923
23104
  const visible = messages.filter((item) => item.role === "user" || item.role === "assistant").map((item) => `${item.role}\0${modelContentText(item.content).trim()}`).join("\n");
22924
- return createHash17("sha256").update(visible, "utf8").digest("hex");
23105
+ return createHash18("sha256").update(visible, "utf8").digest("hex");
22925
23106
  }
22926
23107
  function createMemoryTaskId() {
22927
- return `memory-${randomUUID19()}`;
23108
+ return `memory-${randomUUID20()}`;
22928
23109
  }
22929
23110
 
22930
23111
  export {