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.
- package/README.md +22 -19
- package/README.zh-CN.md +22 -19
- package/dist/{app-CJSBYZAD.js → app-NHRRG3YA.js} +1 -1
- package/dist/{chunk-BR3CWUYR.js → chunk-K2AOT2BI.js} +334 -153
- package/dist/{chunk-ZCEUFSHA.js → chunk-VPJ7KY3T.js} +1 -1
- package/dist/cli.js +3 -3
- package/dist/desktop/main.js +560 -370
- package/dist/island/control-server.d.ts +21 -0
- package/dist/production.d.ts +4 -0
- package/dist/sdk/index.js +2 -2
- package/package.json +1 -1
|
@@ -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({
|
|
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
|
|
5010
|
-
import { homedir as homedir2, release as osRelease, tmpdir as
|
|
5011
|
-
import { basename as basename6, join as
|
|
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
|
|
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
|
|
8784
|
-
import { join as
|
|
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
|
|
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 =
|
|
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 =
|
|
9508
|
-
var VERSIONS_DIR =
|
|
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 =
|
|
9553
|
-
const entryPath =
|
|
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(
|
|
9729
|
+
const sandbox = await mkdtemp(join10(tmpdir3(), "flavor-evolve-verify-"));
|
|
9574
9730
|
try {
|
|
9575
|
-
await cp(pluginRoot,
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
9731
|
-
this.signalsFile =
|
|
9732
|
-
this.reflectionsFile =
|
|
9733
|
-
this.doneFile =
|
|
9734
|
-
this.verifiedFile =
|
|
9735
|
-
this.rulesFile =
|
|
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(
|
|
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(
|
|
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
|
|
10942
|
+
import { createHash as createHash11 } from "crypto";
|
|
10787
10943
|
import { writeFile as writeFile9, mkdir as mkdir10 } from "fs/promises";
|
|
10788
|
-
import { join as
|
|
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
|
|
11107
|
+
import { createHash as createHash10 } from "crypto";
|
|
10952
11108
|
import { readFile as readFile9 } from "fs/promises";
|
|
10953
|
-
import { join as
|
|
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
|
|
11282
|
+
return createHash10("sha256").update(content).digest("hex").slice(0, 16);
|
|
11127
11283
|
}
|
|
11128
|
-
async function collectEvidence(workspace, objective, finalResponse, priorGaps, contractHash2 =
|
|
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 =
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
11536
|
+
return createHash11("sha256").update(JSON.stringify({ objective, plan })).digest("hex");
|
|
11381
11537
|
}
|
|
11382
11538
|
async function writePlanFile(workspace, plan) {
|
|
11383
|
-
const dir =
|
|
11384
|
-
const planPath =
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
11549
|
-
const path =
|
|
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 =
|
|
11580
|
-
const excludePath =
|
|
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
|
|
11597
|
-
import { randomUUID as
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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()}-${
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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 = `__${
|
|
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
|
|
13239
|
-
import { createServer as
|
|
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
|
|
13399
|
+
import { createHash as createHash13 } from "crypto";
|
|
13244
13400
|
function oauthCredentialId(tokenUrl, clientId) {
|
|
13245
|
-
const digest =
|
|
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 =
|
|
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
|
|
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
|
|
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:
|
|
13651
|
-
{ tier: "project", path:
|
|
13652
|
-
{ tier: "local", path:
|
|
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
|
|
14422
|
-
import { randomUUID as
|
|
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 =
|
|
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 =
|
|
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(
|
|
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(
|
|
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()}-${
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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}.${
|
|
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
|
|
17375
|
-
import { link as link2, lstat as lstat11, mkdir as mkdir17, readFile as readFile19, readdir as readdir8, unlink as
|
|
17376
|
-
import { dirname as dirname18, join as
|
|
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 =
|
|
17420
|
-
this.#globalRoot =
|
|
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 =
|
|
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
|
|
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 [
|
|
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 =
|
|
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}.${
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
18528
|
-
this.path =
|
|
18529
|
-
this.#behaviorPath =
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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-${
|
|
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
|
|
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-${
|
|
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
|
|
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 =
|
|
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
|
|
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:
|
|
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 =
|
|
19922
|
-
const data2 = await this.request({ version: 1, type: "task", requestId:
|
|
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 =
|
|
19926
|
-
const data2 = await this.request({ version: 1, type: "chat", requestId:
|
|
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:
|
|
19934
|
-
coWorkId: input.coWorkId ??
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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: [
|
|
20694
|
-
projectPluginDirs: [
|
|
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:
|
|
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: [
|
|
20913
|
-
projectRoots: [
|
|
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(
|
|
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)}-${
|
|
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(
|
|
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)}-${
|
|
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)}-${
|
|
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)}-${
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
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
|
|
23105
|
+
return createHash18("sha256").update(visible, "utf8").digest("hex");
|
|
22925
23106
|
}
|
|
22926
23107
|
function createMemoryTaskId() {
|
|
22927
|
-
return `memory-${
|
|
23108
|
+
return `memory-${randomUUID20()}`;
|
|
22928
23109
|
}
|
|
22929
23110
|
|
|
22930
23111
|
export {
|