flavor-code 1.2.15 → 1.2.17
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/dist/agent/types.d.ts +1 -1
- package/dist/{app-3KW2FTVJ.js → app-F4P7RV2X.js} +1 -1
- package/dist/auth/store.d.ts +7 -0
- package/dist/{chunk-5TG3E2EJ.js → chunk-QQCXJC4U.js} +96 -15
- package/dist/{chunk-BKARQJQZ.js → chunk-YRIPE5K5.js} +1 -1
- package/dist/cli.js +3 -3
- package/dist/desktop/main.js +107 -16
- package/dist/desktop/preload.cjs +2 -0
- package/dist/desktop-renderer/assets/index-BmXr_vX3.js +151 -0
- package/dist/desktop-renderer/assets/{index-CPxt3vFY.css → index-DEL8gXBO.css} +1 -1
- package/dist/desktop-renderer/index.html +2 -2
- package/dist/sdk/index.js +2 -2
- package/dist/tools/shell.d.ts +11 -0
- package/dist/ui/commands.d.ts +1 -1
- package/dist/ui/session.d.ts +1 -0
- package/package.json +1 -1
- package/dist/desktop-renderer/assets/index-BCJjMvbX.js +0 -151
package/dist/agent/types.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export interface AgentRunRequest {
|
|
|
15
15
|
/** Messages supplied while a tool batch is running, injected before the next model call. */
|
|
16
16
|
getSteeringMessages?(): readonly string[];
|
|
17
17
|
}
|
|
18
|
-
export type AgentErrorCode = ProviderErrorCode | "iteration_limit" | "incomplete_stream";
|
|
18
|
+
export type AgentErrorCode = ProviderErrorCode | "iteration_limit" | "incomplete_stream" | "empty_response";
|
|
19
19
|
export interface AgentError {
|
|
20
20
|
code: AgentErrorCode;
|
|
21
21
|
message: string;
|
package/dist/auth/store.d.ts
CHANGED
|
@@ -12,4 +12,11 @@ export interface OAuthTokenStore {
|
|
|
12
12
|
load(): Promise<Record<string, StoredToken>>;
|
|
13
13
|
save(tokens: Record<string, StoredToken>): Promise<void>;
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Reduce the token store to a single credential. `/login` is a switch-to
|
|
17
|
+
* operation: keeping tokens from earlier services made the runtime pick the
|
|
18
|
+
* active provider by registration order, so the welcome card could show a
|
|
19
|
+
* stale service (e.g. a previous "Token Plan") instead of the one just logged in.
|
|
20
|
+
*/
|
|
21
|
+
export declare function retainOnlyCredentials(store: OAuthTokenStore, keepCredentialId: string): Promise<void>;
|
|
15
22
|
export declare function createFileTokenStore(filePath: string): OAuthTokenStore;
|
|
@@ -2900,6 +2900,7 @@ var MVP_COMMANDS = [
|
|
|
2900
2900
|
"init",
|
|
2901
2901
|
"config",
|
|
2902
2902
|
"login",
|
|
2903
|
+
"logout",
|
|
2903
2904
|
"permissions",
|
|
2904
2905
|
"skills",
|
|
2905
2906
|
"plugins",
|
|
@@ -2937,6 +2938,7 @@ var COMMAND_DESCRIPTIONS = {
|
|
|
2937
2938
|
init: "Initialize Flavor project files",
|
|
2938
2939
|
config: "Show the resolved configuration",
|
|
2939
2940
|
login: "Authenticate via OAuth PKCE",
|
|
2941
|
+
logout: "Clear stored OAuth credentials and restore configured models",
|
|
2940
2942
|
permissions: "Change the tool permission mode",
|
|
2941
2943
|
skills: "List discovered skills",
|
|
2942
2944
|
plugins: "List loaded plugins",
|
|
@@ -3214,6 +3216,7 @@ var HELP = [
|
|
|
3214
3216
|
"/model <main|subagent> <provider:model> switch any configured model",
|
|
3215
3217
|
"/permissions <default|acceptEdits|plan|bypassPermissions|auto|bubble>",
|
|
3216
3218
|
"/login authenticate via OAuth PKCE",
|
|
3219
|
+
"/logout clear stored OAuth credentials",
|
|
3217
3220
|
"/init /config /skills /plugins /hooks /tasks",
|
|
3218
3221
|
"/memory /remember [type] <text> /forget <text-or-id> /forget-cold /finish",
|
|
3219
3222
|
"/checkpoint [label] /tree /rewind <node> /unrevert /fork <node>",
|
|
@@ -3628,6 +3631,8 @@ var FlavorSession = class {
|
|
|
3628
3631
|
} else if (command.name === "login") {
|
|
3629
3632
|
this.#notice("Opening browser for authentication...");
|
|
3630
3633
|
this.#notice(await this.#services.login());
|
|
3634
|
+
} else if (command.name === "logout") {
|
|
3635
|
+
this.#notice(await this.#services.logout());
|
|
3631
3636
|
} else if (command.name === "help") this.#notice(HELP);
|
|
3632
3637
|
else if (command.name === "exit") this.#services.output({ type: "exit" });
|
|
3633
3638
|
}
|
|
@@ -6534,7 +6539,8 @@ var RECOVERABLE_MODEL_ERRORS = /* @__PURE__ */ new Set([
|
|
|
6534
6539
|
"network",
|
|
6535
6540
|
"rate_limit",
|
|
6536
6541
|
"unknown",
|
|
6537
|
-
"incomplete_stream"
|
|
6542
|
+
"incomplete_stream",
|
|
6543
|
+
"empty_response"
|
|
6538
6544
|
]);
|
|
6539
6545
|
function envMaxIterations() {
|
|
6540
6546
|
const raw = process.env["FLAVOR_MAX_ITERATIONS"];
|
|
@@ -6728,6 +6734,12 @@ var AgentLoop = class {
|
|
|
6728
6734
|
} finally {
|
|
6729
6735
|
if (!completed && terminalError === void 0) {
|
|
6730
6736
|
terminalError = { code: "incomplete_stream", message: "Provider stream ended without a done or error event" };
|
|
6737
|
+
} else if (completed && assistantText.trim().length === 0 && collectedToolCalls.length === 0) {
|
|
6738
|
+
completed = false;
|
|
6739
|
+
terminalError = {
|
|
6740
|
+
code: "empty_response",
|
|
6741
|
+
message: "Provider completed without visible text or tool calls"
|
|
6742
|
+
};
|
|
6731
6743
|
}
|
|
6732
6744
|
providerError = terminalError !== void 0;
|
|
6733
6745
|
try {
|
|
@@ -6767,7 +6779,7 @@ var AgentLoop = class {
|
|
|
6767
6779
|
totalCacheCreationTokens += usage.cacheCreationTokens ?? 0;
|
|
6768
6780
|
yield { type: "usage", ...usage, totalInputTokens, totalOutputTokens };
|
|
6769
6781
|
}
|
|
6770
|
-
const providerProducedOutput = assistantText.length > 0 || collectedToolCalls.length > 0;
|
|
6782
|
+
const providerProducedOutput = assistantText.trim().length > 0 || collectedToolCalls.length > 0;
|
|
6771
6783
|
if (terminalError?.code === "context_overflow" && !reactiveRetried && !providerProducedOutput && attempt < maxAttempts) {
|
|
6772
6784
|
let compacted = false;
|
|
6773
6785
|
try {
|
|
@@ -10646,7 +10658,7 @@ import { readFile as readFile11 } from "fs/promises";
|
|
|
10646
10658
|
import { join as join16 } from "path";
|
|
10647
10659
|
|
|
10648
10660
|
// src/tools/shell.ts
|
|
10649
|
-
import { spawn as spawn6 } from "child_process";
|
|
10661
|
+
import { spawn as spawn6, spawnSync } from "child_process";
|
|
10650
10662
|
import { isAbsolute as isAbsolute6, relative as relative11, resolve as resolve13, sep as sep10 } from "path";
|
|
10651
10663
|
import { z as z16 } from "zod";
|
|
10652
10664
|
|
|
@@ -10776,6 +10788,29 @@ function tokenizeCommandLine(command) {
|
|
|
10776
10788
|
function unquoteToken(token) {
|
|
10777
10789
|
return token.length >= 2 && token.startsWith('"') && token.endsWith('"') ? token.slice(1, -1) : token;
|
|
10778
10790
|
}
|
|
10791
|
+
var cachedWindowsShell;
|
|
10792
|
+
function hasExecutable(name) {
|
|
10793
|
+
try {
|
|
10794
|
+
return spawnSync("where", [name], { stdio: "ignore", windowsHide: true }).status === 0;
|
|
10795
|
+
} catch {
|
|
10796
|
+
return false;
|
|
10797
|
+
}
|
|
10798
|
+
}
|
|
10799
|
+
function detectWindowsShell() {
|
|
10800
|
+
if (cachedWindowsShell !== void 0) return cachedWindowsShell;
|
|
10801
|
+
cachedWindowsShell = hasExecutable("pwsh") ? "pwsh" : hasExecutable("powershell") ? "powershell" : "cmd";
|
|
10802
|
+
return cachedWindowsShell;
|
|
10803
|
+
}
|
|
10804
|
+
function psQuote(token) {
|
|
10805
|
+
return `'${token.replace(/'/g, "''")}'`;
|
|
10806
|
+
}
|
|
10807
|
+
function buildWindowsCommandLine(kind, commandLine, command, args) {
|
|
10808
|
+
if (kind === "cmd") return `chcp 65001>nul & ${commandLine}`;
|
|
10809
|
+
const executable = kind === "pwsh" ? "pwsh" : "powershell";
|
|
10810
|
+
const script = `& ${psQuote(command)}${args.length > 0 ? ` ${args.map(psQuote).join(" ")}` : ""}; exit $LASTEXITCODE`;
|
|
10811
|
+
const encoded = Buffer.from(script, "utf16le").toString("base64");
|
|
10812
|
+
return `chcp 65001>nul & ${executable} -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand ${encoded}`;
|
|
10813
|
+
}
|
|
10779
10814
|
function createShellTool(workspace, options = {}) {
|
|
10780
10815
|
const root = resolve13(workspace);
|
|
10781
10816
|
const maxBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES2;
|
|
@@ -10896,7 +10931,7 @@ async function executeShell(root, input, cancellation, maxBytes, onOutput) {
|
|
|
10896
10931
|
const quoteArg = (s) => s.includes(" ") ? `"${s.replace(/"/g, '""')}"` : s;
|
|
10897
10932
|
const quoted = input.args.map(quoteArg).join(" ");
|
|
10898
10933
|
const commandLine = quoted.length > 0 ? `${quoteArg(input.command)} ${quoted}` : quoteArg(input.command);
|
|
10899
|
-
const shellCommandLine = process.platform === "win32" ?
|
|
10934
|
+
const shellCommandLine = process.platform === "win32" ? buildWindowsCommandLine(detectWindowsShell(), commandLine, input.command, input.args) : commandLine;
|
|
10900
10935
|
const child = spawn6(shellCommandLine, {
|
|
10901
10936
|
cwd,
|
|
10902
10937
|
shell: true,
|
|
@@ -12435,6 +12470,11 @@ function escapeHtml(text) {
|
|
|
12435
12470
|
|
|
12436
12471
|
// src/auth/store.ts
|
|
12437
12472
|
import { dirname as dirname13 } from "path";
|
|
12473
|
+
async function retainOnlyCredentials(store, keepCredentialId) {
|
|
12474
|
+
const tokens = await store.load();
|
|
12475
|
+
const retained = Object.fromEntries(Object.entries(tokens).filter(([id]) => id === keepCredentialId));
|
|
12476
|
+
await store.save(retained);
|
|
12477
|
+
}
|
|
12438
12478
|
function createFileTokenStore(filePath) {
|
|
12439
12479
|
let baseline = {};
|
|
12440
12480
|
const store = {
|
|
@@ -19464,7 +19504,10 @@ async function createProductionRuntime(options) {
|
|
|
19464
19504
|
states: { ...taskStates },
|
|
19465
19505
|
results: { ...taskResults }
|
|
19466
19506
|
},
|
|
19467
|
-
|
|
19507
|
+
// Persist the resolved decision, not the harness snapshot: after logout the
|
|
19508
|
+
// harness may still hold the old login model, and resuming from that stale
|
|
19509
|
+
// value is what made the welcome card show a previous service.
|
|
19510
|
+
models: { main: mainModel, subagent: childModel },
|
|
19468
19511
|
permissionMode: harness.permissionMode,
|
|
19469
19512
|
memory: memoryLifecycle,
|
|
19470
19513
|
timeline: { version: 1, state: timelineState }
|
|
@@ -19719,7 +19762,7 @@ async function createProductionRuntime(options) {
|
|
|
19719
19762
|
const messages = allMessages.slice(memoryLifecycle.messageStart ?? 0);
|
|
19720
19763
|
const transcriptHash = memoryTranscriptHash(messages);
|
|
19721
19764
|
if (memoryLifecycle.status === "completed" && memoryLifecycle.transcriptHash === transcriptHash) {
|
|
19722
|
-
return "
|
|
19765
|
+
return "This conversation segment was already evaluated for long-term memory.";
|
|
19723
19766
|
}
|
|
19724
19767
|
if (!manual && memoryBehavior.autoExtractPaused) {
|
|
19725
19768
|
return "Automatic long-term-memory extraction is paused after repeated dismissals; use /finish, /remember, or an explicit \u201Cremember\u201D request to store memory manually.";
|
|
@@ -19727,7 +19770,7 @@ async function createProductionRuntime(options) {
|
|
|
19727
19770
|
autoStoredContents.length = 0;
|
|
19728
19771
|
const finalization = memoryCoordinator === void 0 || !config.memory.autoExtract || options.approvalPolicy === "deny" ? { evaluated: true, candidates: false, stored: 0 } : await memoryCoordinator.finalize(memoryLifecycle.taskId ?? sessionId, messages);
|
|
19729
19772
|
if (!finalization.evaluated) {
|
|
19730
|
-
return "
|
|
19773
|
+
return "Long-term-memory evaluation failed; retry /finish after checking diagnostics.";
|
|
19731
19774
|
}
|
|
19732
19775
|
memoryLifecycle = {
|
|
19733
19776
|
status: "completed",
|
|
@@ -19739,9 +19782,9 @@ async function createProductionRuntime(options) {
|
|
|
19739
19782
|
await persist();
|
|
19740
19783
|
if (finalization.candidates && finalization.stored > 0) {
|
|
19741
19784
|
const storedText = autoStoredContents[0] ?? "a high-confidence memory";
|
|
19742
|
-
return `
|
|
19785
|
+
return `Long-term memory updated. Stored high-confidence entry: "${storedText}". Run /forget to remove it if undesired.`;
|
|
19743
19786
|
}
|
|
19744
|
-
return finalization.candidates ? "
|
|
19787
|
+
return finalization.candidates ? "Long-term-memory evaluation completed. Review the generated candidates before anything is stored." : "Long-term-memory evaluation completed; no durable candidates passed the threshold.";
|
|
19745
19788
|
};
|
|
19746
19789
|
let explicitMemoryRequest;
|
|
19747
19790
|
let automaticMemoryTask = false;
|
|
@@ -19752,10 +19795,10 @@ async function createProductionRuntime(options) {
|
|
|
19752
19795
|
timelineState = transcriptReducer(timelineState, { type: "submit", prompt });
|
|
19753
19796
|
automaticMemoryTask = !prompt.startsWith("/") && harness.permissionProfile !== "d2c";
|
|
19754
19797
|
if (automaticMemoryTask) memoryReviews.dismissAll();
|
|
19755
|
-
if (!prompt.startsWith("/")
|
|
19798
|
+
if (!prompt.startsWith("/")) {
|
|
19756
19799
|
memoryLifecycle = {
|
|
19757
19800
|
status: "active",
|
|
19758
|
-
taskId: createMemoryTaskId(),
|
|
19801
|
+
taskId: memoryLifecycle.status === "completed" ? createMemoryTaskId() : memoryLifecycle.taskId ?? createMemoryTaskId(),
|
|
19759
19802
|
messageStart: harness.main.context.snapshot().messages.length
|
|
19760
19803
|
};
|
|
19761
19804
|
}
|
|
@@ -19797,9 +19840,9 @@ async function createProductionRuntime(options) {
|
|
|
19797
19840
|
}
|
|
19798
19841
|
if (explicit === void 0 && automatic && event.payload.outcome === "completed" && memoryCoordinator !== void 0 && config.memory.autoExtract && options.approvalPolicy !== "deny" && !memoryBehavior.autoExtractPaused) {
|
|
19799
19842
|
const result = await finalizeMemoryTask();
|
|
19800
|
-
if (result.startsWith("
|
|
19843
|
+
if (result.startsWith("Long-term-memory evaluation failed")) {
|
|
19801
19844
|
emitOutput({ type: "notice", message: "Automatic long-term-memory evaluation failed; use /finish to retry after checking diagnostics." });
|
|
19802
|
-
} else if (result.startsWith("
|
|
19845
|
+
} else if (result.startsWith("Long-term-memory evaluation completed. Review") || result.startsWith("Long-term memory updated.")) {
|
|
19803
19846
|
emitOutput({ type: "notice", message: result });
|
|
19804
19847
|
}
|
|
19805
19848
|
}
|
|
@@ -20105,8 +20148,8 @@ async function createProductionRuntime(options) {
|
|
|
20105
20148
|
const services = {
|
|
20106
20149
|
hooks,
|
|
20107
20150
|
workspace,
|
|
20108
|
-
mainModel: () =>
|
|
20109
|
-
subagentModel: () =>
|
|
20151
|
+
mainModel: () => mainModel,
|
|
20152
|
+
subagentModel: () => childModel,
|
|
20110
20153
|
llmServiceName: () => effectiveLlm?.serviceName,
|
|
20111
20154
|
permissionMode: () => harness.permissionMode,
|
|
20112
20155
|
...palServices === void 0 ? {} : { pals: palServices },
|
|
@@ -20180,6 +20223,8 @@ async function createProductionRuntime(options) {
|
|
|
20180
20223
|
}
|
|
20181
20224
|
}
|
|
20182
20225
|
harness.setModel(role, id);
|
|
20226
|
+
if (role === "main") mainModel = id;
|
|
20227
|
+
else childModel = id;
|
|
20183
20228
|
await persist();
|
|
20184
20229
|
},
|
|
20185
20230
|
setPermissionMode: async (mode) => {
|
|
@@ -20426,12 +20471,48 @@ ${renderMemoryDocument(entries)}`;
|
|
|
20426
20471
|
goalOrchestrator.setModels(mainModel, mainModel);
|
|
20427
20472
|
delete selectedModels.mainError;
|
|
20428
20473
|
delete selectedModels.childError;
|
|
20474
|
+
await retainOnlyCredentials(tokenStore, credentialId);
|
|
20429
20475
|
if (!secrets.includes(next.accessToken)) secrets.push(next.accessToken);
|
|
20430
20476
|
await persist();
|
|
20431
20477
|
return `Authenticated to "${next.serviceName}". Main model ${mainModel}; subagent ${childModel}; gateway ${next.baseURL}. Configuration is active now.`;
|
|
20432
20478
|
} catch (error) {
|
|
20433
20479
|
return `Login failed: ${message(error)}`;
|
|
20434
20480
|
}
|
|
20481
|
+
},
|
|
20482
|
+
async logout() {
|
|
20483
|
+
const tokenStore = createFileTokenStore(join22(home, ".flavor-code", "auth.json"));
|
|
20484
|
+
const tokens = await tokenStore.load();
|
|
20485
|
+
const hadCredentials = Object.keys(tokens).length > 0 || effectiveLlm !== void 0;
|
|
20486
|
+
if (!hadCredentials) {
|
|
20487
|
+
return "Not authenticated \u2014 no stored OAuth credentials to clear.";
|
|
20488
|
+
}
|
|
20489
|
+
for (let i = registeredProviders.length - 1; i >= 0; i -= 1) {
|
|
20490
|
+
const provider = registeredProviders[i];
|
|
20491
|
+
if (provider !== void 0 && provider.pkceManaged === true) {
|
|
20492
|
+
registry.unregister(provider.name);
|
|
20493
|
+
registeredProviders.splice(i, 1);
|
|
20494
|
+
}
|
|
20495
|
+
}
|
|
20496
|
+
if (effectiveLlm !== void 0) {
|
|
20497
|
+
registry.unregister(effectiveLlm.providerId);
|
|
20498
|
+
effectiveLlm = void 0;
|
|
20499
|
+
}
|
|
20500
|
+
await tokenStore.save({});
|
|
20501
|
+
const fallback = selectModels(config, registeredProviders, diagnostics);
|
|
20502
|
+
mainModel = fallback.main;
|
|
20503
|
+
childModel = fallback.child;
|
|
20504
|
+
if (fallback.mainError === void 0) delete selectedModels.mainError;
|
|
20505
|
+
else selectedModels.mainError = fallback.mainError;
|
|
20506
|
+
if (fallback.childError === void 0) delete selectedModels.childError;
|
|
20507
|
+
else selectedModels.childError = fallback.childError;
|
|
20508
|
+
if (fallback.mainError === void 0 && registry.has(safeProvider(mainModel)) && registry.has(safeProvider(childModel))) {
|
|
20509
|
+
harness.setModel("main", mainModel);
|
|
20510
|
+
harness.setModel("subagent", childModel);
|
|
20511
|
+
hallucinationGuard.setModel(childModel);
|
|
20512
|
+
goalOrchestrator.setModels(mainModel, mainModel);
|
|
20513
|
+
}
|
|
20514
|
+
await persist();
|
|
20515
|
+
return fallback.mainError === void 0 ? `Logged out. Cleared OAuth credentials. Main model ${mainModel}; subagent ${childModel}.` : `Logged out. Cleared OAuth credentials. ${fallback.mainError}`;
|
|
20435
20516
|
}
|
|
20436
20517
|
};
|
|
20437
20518
|
if (config.sleep) {
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from "node:module"; const require = createRequire(impor
|
|
|
3
3
|
import {
|
|
4
4
|
FlavorRpcServer,
|
|
5
5
|
TraceRecorder
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-YRIPE5K5.js";
|
|
7
7
|
import {
|
|
8
8
|
staticTaskLines
|
|
9
9
|
} from "./chunk-KKIBYDJI.js";
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
packageVersion,
|
|
23
23
|
redactErrorText,
|
|
24
24
|
runPalBroker
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-QQCXJC4U.js";
|
|
26
26
|
import {
|
|
27
27
|
McpServerConfigSchema,
|
|
28
28
|
McpServerNameSchema,
|
|
@@ -861,7 +861,7 @@ async function runInteractiveCli(props) {
|
|
|
861
861
|
const [{ render, AlternateScreen }, { createElement }, { App }] = await Promise.all([
|
|
862
862
|
import("./claude-ink-ORUA7GWG.js"),
|
|
863
863
|
import("react"),
|
|
864
|
-
import("./app-
|
|
864
|
+
import("./app-F4P7RV2X.js")
|
|
865
865
|
]);
|
|
866
866
|
const instance = await render(createElement(
|
|
867
867
|
AlternateScreen,
|
package/dist/desktop/main.js
CHANGED
|
@@ -505,6 +505,7 @@ var DESKTOP_CHANNELS = {
|
|
|
505
505
|
d2cRunQualityJudge: "desktop:d2c-run-quality-judge",
|
|
506
506
|
d2cResolveQualityIssue: "desktop:d2c-resolve-quality-issue",
|
|
507
507
|
d2cSetManualAcceptance: "desktop:d2c-set-manual-acceptance",
|
|
508
|
+
e2eGetDeliveryRun: "desktop:e2e-get-delivery-run",
|
|
508
509
|
event: "desktop:event"
|
|
509
510
|
};
|
|
510
511
|
|
|
@@ -6127,7 +6128,8 @@ var RECOVERABLE_MODEL_ERRORS = /* @__PURE__ */ new Set([
|
|
|
6127
6128
|
"network",
|
|
6128
6129
|
"rate_limit",
|
|
6129
6130
|
"unknown",
|
|
6130
|
-
"incomplete_stream"
|
|
6131
|
+
"incomplete_stream",
|
|
6132
|
+
"empty_response"
|
|
6131
6133
|
]);
|
|
6132
6134
|
function envMaxIterations() {
|
|
6133
6135
|
const raw = process.env["FLAVOR_MAX_ITERATIONS"];
|
|
@@ -6321,6 +6323,12 @@ var AgentLoop = class {
|
|
|
6321
6323
|
} finally {
|
|
6322
6324
|
if (!completed && terminalError === void 0) {
|
|
6323
6325
|
terminalError = { code: "incomplete_stream", message: "Provider stream ended without a done or error event" };
|
|
6326
|
+
} else if (completed && assistantText.trim().length === 0 && collectedToolCalls.length === 0) {
|
|
6327
|
+
completed = false;
|
|
6328
|
+
terminalError = {
|
|
6329
|
+
code: "empty_response",
|
|
6330
|
+
message: "Provider completed without visible text or tool calls"
|
|
6331
|
+
};
|
|
6324
6332
|
}
|
|
6325
6333
|
providerError = terminalError !== void 0;
|
|
6326
6334
|
try {
|
|
@@ -6360,7 +6368,7 @@ var AgentLoop = class {
|
|
|
6360
6368
|
totalCacheCreationTokens += usage.cacheCreationTokens ?? 0;
|
|
6361
6369
|
yield { type: "usage", ...usage, totalInputTokens, totalOutputTokens };
|
|
6362
6370
|
}
|
|
6363
|
-
const providerProducedOutput = assistantText.length > 0 || collectedToolCalls.length > 0;
|
|
6371
|
+
const providerProducedOutput = assistantText.trim().length > 0 || collectedToolCalls.length > 0;
|
|
6364
6372
|
if (terminalError?.code === "context_overflow" && !reactiveRetried && !providerProducedOutput && attempt < maxAttempts) {
|
|
6365
6373
|
let compacted = false;
|
|
6366
6374
|
try {
|
|
@@ -11210,7 +11218,7 @@ import { readFile as readFile12 } from "fs/promises";
|
|
|
11210
11218
|
import { join as join17 } from "path";
|
|
11211
11219
|
|
|
11212
11220
|
// src/tools/shell.ts
|
|
11213
|
-
import { spawn as spawn3 } from "child_process";
|
|
11221
|
+
import { spawn as spawn3, spawnSync } from "child_process";
|
|
11214
11222
|
import { isAbsolute as isAbsolute8, relative as relative11, resolve as resolve13, sep as sep10 } from "path";
|
|
11215
11223
|
import { z as z21 } from "zod";
|
|
11216
11224
|
|
|
@@ -11340,6 +11348,29 @@ function tokenizeCommandLine(command) {
|
|
|
11340
11348
|
function unquoteToken(token) {
|
|
11341
11349
|
return token.length >= 2 && token.startsWith('"') && token.endsWith('"') ? token.slice(1, -1) : token;
|
|
11342
11350
|
}
|
|
11351
|
+
var cachedWindowsShell;
|
|
11352
|
+
function hasExecutable(name) {
|
|
11353
|
+
try {
|
|
11354
|
+
return spawnSync("where", [name], { stdio: "ignore", windowsHide: true }).status === 0;
|
|
11355
|
+
} catch {
|
|
11356
|
+
return false;
|
|
11357
|
+
}
|
|
11358
|
+
}
|
|
11359
|
+
function detectWindowsShell() {
|
|
11360
|
+
if (cachedWindowsShell !== void 0) return cachedWindowsShell;
|
|
11361
|
+
cachedWindowsShell = hasExecutable("pwsh") ? "pwsh" : hasExecutable("powershell") ? "powershell" : "cmd";
|
|
11362
|
+
return cachedWindowsShell;
|
|
11363
|
+
}
|
|
11364
|
+
function psQuote(token) {
|
|
11365
|
+
return `'${token.replace(/'/g, "''")}'`;
|
|
11366
|
+
}
|
|
11367
|
+
function buildWindowsCommandLine(kind, commandLine, command, args) {
|
|
11368
|
+
if (kind === "cmd") return `chcp 65001>nul & ${commandLine}`;
|
|
11369
|
+
const executable = kind === "pwsh" ? "pwsh" : "powershell";
|
|
11370
|
+
const script = `& ${psQuote(command)}${args.length > 0 ? ` ${args.map(psQuote).join(" ")}` : ""}; exit $LASTEXITCODE`;
|
|
11371
|
+
const encoded = Buffer.from(script, "utf16le").toString("base64");
|
|
11372
|
+
return `chcp 65001>nul & ${executable} -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand ${encoded}`;
|
|
11373
|
+
}
|
|
11343
11374
|
function createShellTool(workspace, options = {}) {
|
|
11344
11375
|
const root = resolve13(workspace);
|
|
11345
11376
|
const maxBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES2;
|
|
@@ -11460,7 +11491,7 @@ async function executeShell(root, input, cancellation, maxBytes, onOutput) {
|
|
|
11460
11491
|
const quoteArg = (s) => s.includes(" ") ? `"${s.replace(/"/g, '""')}"` : s;
|
|
11461
11492
|
const quoted = input.args.map(quoteArg).join(" ");
|
|
11462
11493
|
const commandLine = quoted.length > 0 ? `${quoteArg(input.command)} ${quoted}` : quoteArg(input.command);
|
|
11463
|
-
const shellCommandLine = process.platform === "win32" ?
|
|
11494
|
+
const shellCommandLine = process.platform === "win32" ? buildWindowsCommandLine(detectWindowsShell(), commandLine, input.command, input.args) : commandLine;
|
|
11464
11495
|
const child = spawn3(shellCommandLine, {
|
|
11465
11496
|
cwd,
|
|
11466
11497
|
shell: true,
|
|
@@ -13090,6 +13121,11 @@ function escapeHtml(text) {
|
|
|
13090
13121
|
|
|
13091
13122
|
// src/auth/store.ts
|
|
13092
13123
|
import { dirname as dirname13 } from "path";
|
|
13124
|
+
async function retainOnlyCredentials(store, keepCredentialId) {
|
|
13125
|
+
const tokens2 = await store.load();
|
|
13126
|
+
const retained = Object.fromEntries(Object.entries(tokens2).filter(([id]) => id === keepCredentialId));
|
|
13127
|
+
await store.save(retained);
|
|
13128
|
+
}
|
|
13093
13129
|
function createFileTokenStore(filePath) {
|
|
13094
13130
|
let baseline = {};
|
|
13095
13131
|
const store = {
|
|
@@ -18789,6 +18825,7 @@ var MVP_COMMANDS = [
|
|
|
18789
18825
|
"init",
|
|
18790
18826
|
"config",
|
|
18791
18827
|
"login",
|
|
18828
|
+
"logout",
|
|
18792
18829
|
"permissions",
|
|
18793
18830
|
"skills",
|
|
18794
18831
|
"plugins",
|
|
@@ -19066,6 +19103,7 @@ var HELP = [
|
|
|
19066
19103
|
"/model <main|subagent> <provider:model> switch any configured model",
|
|
19067
19104
|
"/permissions <default|acceptEdits|plan|bypassPermissions|auto|bubble>",
|
|
19068
19105
|
"/login authenticate via OAuth PKCE",
|
|
19106
|
+
"/logout clear stored OAuth credentials",
|
|
19069
19107
|
"/init /config /skills /plugins /hooks /tasks",
|
|
19070
19108
|
"/memory /remember [type] <text> /forget <text-or-id> /forget-cold /finish",
|
|
19071
19109
|
"/checkpoint [label] /tree /rewind <node> /unrevert /fork <node>",
|
|
@@ -19480,6 +19518,8 @@ var FlavorSession = class {
|
|
|
19480
19518
|
} else if (command.name === "login") {
|
|
19481
19519
|
this.#notice("Opening browser for authentication...");
|
|
19482
19520
|
this.#notice(await this.#services.login());
|
|
19521
|
+
} else if (command.name === "logout") {
|
|
19522
|
+
this.#notice(await this.#services.logout());
|
|
19483
19523
|
} else if (command.name === "help") this.#notice(HELP);
|
|
19484
19524
|
else if (command.name === "exit") this.#services.output({ type: "exit" });
|
|
19485
19525
|
}
|
|
@@ -23167,7 +23207,10 @@ async function createProductionRuntime(options) {
|
|
|
23167
23207
|
states: { ...taskStates },
|
|
23168
23208
|
results: { ...taskResults }
|
|
23169
23209
|
},
|
|
23170
|
-
|
|
23210
|
+
// Persist the resolved decision, not the harness snapshot: after logout the
|
|
23211
|
+
// harness may still hold the old login model, and resuming from that stale
|
|
23212
|
+
// value is what made the welcome card show a previous service.
|
|
23213
|
+
models: { main: mainModel, subagent: childModel },
|
|
23171
23214
|
permissionMode: harness.permissionMode,
|
|
23172
23215
|
memory: memoryLifecycle,
|
|
23173
23216
|
timeline: { version: 1, state: timelineState }
|
|
@@ -23422,7 +23465,7 @@ async function createProductionRuntime(options) {
|
|
|
23422
23465
|
const messages = allMessages.slice(memoryLifecycle.messageStart ?? 0);
|
|
23423
23466
|
const transcriptHash = memoryTranscriptHash(messages);
|
|
23424
23467
|
if (memoryLifecycle.status === "completed" && memoryLifecycle.transcriptHash === transcriptHash) {
|
|
23425
|
-
return "
|
|
23468
|
+
return "This conversation segment was already evaluated for long-term memory.";
|
|
23426
23469
|
}
|
|
23427
23470
|
if (!manual && memoryBehavior.autoExtractPaused) {
|
|
23428
23471
|
return "Automatic long-term-memory extraction is paused after repeated dismissals; use /finish, /remember, or an explicit \u201Cremember\u201D request to store memory manually.";
|
|
@@ -23430,7 +23473,7 @@ async function createProductionRuntime(options) {
|
|
|
23430
23473
|
autoStoredContents.length = 0;
|
|
23431
23474
|
const finalization = memoryCoordinator === void 0 || !config.memory.autoExtract || options.approvalPolicy === "deny" ? { evaluated: true, candidates: false, stored: 0 } : await memoryCoordinator.finalize(memoryLifecycle.taskId ?? sessionId, messages);
|
|
23432
23475
|
if (!finalization.evaluated) {
|
|
23433
|
-
return "
|
|
23476
|
+
return "Long-term-memory evaluation failed; retry /finish after checking diagnostics.";
|
|
23434
23477
|
}
|
|
23435
23478
|
memoryLifecycle = {
|
|
23436
23479
|
status: "completed",
|
|
@@ -23442,9 +23485,9 @@ async function createProductionRuntime(options) {
|
|
|
23442
23485
|
await persist();
|
|
23443
23486
|
if (finalization.candidates && finalization.stored > 0) {
|
|
23444
23487
|
const storedText = autoStoredContents[0] ?? "a high-confidence memory";
|
|
23445
|
-
return `
|
|
23488
|
+
return `Long-term memory updated. Stored high-confidence entry: "${storedText}". Run /forget to remove it if undesired.`;
|
|
23446
23489
|
}
|
|
23447
|
-
return finalization.candidates ? "
|
|
23490
|
+
return finalization.candidates ? "Long-term-memory evaluation completed. Review the generated candidates before anything is stored." : "Long-term-memory evaluation completed; no durable candidates passed the threshold.";
|
|
23448
23491
|
};
|
|
23449
23492
|
let explicitMemoryRequest;
|
|
23450
23493
|
let automaticMemoryTask = false;
|
|
@@ -23455,10 +23498,10 @@ async function createProductionRuntime(options) {
|
|
|
23455
23498
|
timelineState = transcriptReducer(timelineState, { type: "submit", prompt });
|
|
23456
23499
|
automaticMemoryTask = !prompt.startsWith("/") && harness.permissionProfile !== "d2c";
|
|
23457
23500
|
if (automaticMemoryTask) memoryReviews.dismissAll();
|
|
23458
|
-
if (!prompt.startsWith("/")
|
|
23501
|
+
if (!prompt.startsWith("/")) {
|
|
23459
23502
|
memoryLifecycle = {
|
|
23460
23503
|
status: "active",
|
|
23461
|
-
taskId: createMemoryTaskId(),
|
|
23504
|
+
taskId: memoryLifecycle.status === "completed" ? createMemoryTaskId() : memoryLifecycle.taskId ?? createMemoryTaskId(),
|
|
23462
23505
|
messageStart: harness.main.context.snapshot().messages.length
|
|
23463
23506
|
};
|
|
23464
23507
|
}
|
|
@@ -23500,9 +23543,9 @@ async function createProductionRuntime(options) {
|
|
|
23500
23543
|
}
|
|
23501
23544
|
if (explicit === void 0 && automatic && event.payload.outcome === "completed" && memoryCoordinator !== void 0 && config.memory.autoExtract && options.approvalPolicy !== "deny" && !memoryBehavior.autoExtractPaused) {
|
|
23502
23545
|
const result = await finalizeMemoryTask();
|
|
23503
|
-
if (result.startsWith("
|
|
23546
|
+
if (result.startsWith("Long-term-memory evaluation failed")) {
|
|
23504
23547
|
emitOutput({ type: "notice", message: "Automatic long-term-memory evaluation failed; use /finish to retry after checking diagnostics." });
|
|
23505
|
-
} else if (result.startsWith("
|
|
23548
|
+
} else if (result.startsWith("Long-term-memory evaluation completed. Review") || result.startsWith("Long-term memory updated.")) {
|
|
23506
23549
|
emitOutput({ type: "notice", message: result });
|
|
23507
23550
|
}
|
|
23508
23551
|
}
|
|
@@ -23808,8 +23851,8 @@ async function createProductionRuntime(options) {
|
|
|
23808
23851
|
const services = {
|
|
23809
23852
|
hooks,
|
|
23810
23853
|
workspace,
|
|
23811
|
-
mainModel: () =>
|
|
23812
|
-
subagentModel: () =>
|
|
23854
|
+
mainModel: () => mainModel,
|
|
23855
|
+
subagentModel: () => childModel,
|
|
23813
23856
|
llmServiceName: () => effectiveLlm?.serviceName,
|
|
23814
23857
|
permissionMode: () => harness.permissionMode,
|
|
23815
23858
|
...palServices === void 0 ? {} : { pals: palServices },
|
|
@@ -23883,6 +23926,8 @@ async function createProductionRuntime(options) {
|
|
|
23883
23926
|
}
|
|
23884
23927
|
}
|
|
23885
23928
|
harness.setModel(role, id);
|
|
23929
|
+
if (role === "main") mainModel = id;
|
|
23930
|
+
else childModel = id;
|
|
23886
23931
|
await persist();
|
|
23887
23932
|
},
|
|
23888
23933
|
setPermissionMode: async (mode) => {
|
|
@@ -24129,12 +24174,48 @@ ${renderMemoryDocument(entries)}`;
|
|
|
24129
24174
|
goalOrchestrator.setModels(mainModel, mainModel);
|
|
24130
24175
|
delete selectedModels.mainError;
|
|
24131
24176
|
delete selectedModels.childError;
|
|
24177
|
+
await retainOnlyCredentials(tokenStore, credentialId);
|
|
24132
24178
|
if (!secrets.includes(next.accessToken)) secrets.push(next.accessToken);
|
|
24133
24179
|
await persist();
|
|
24134
24180
|
return `Authenticated to "${next.serviceName}". Main model ${mainModel}; subagent ${childModel}; gateway ${next.baseURL}. Configuration is active now.`;
|
|
24135
24181
|
} catch (error) {
|
|
24136
24182
|
return `Login failed: ${message(error)}`;
|
|
24137
24183
|
}
|
|
24184
|
+
},
|
|
24185
|
+
async logout() {
|
|
24186
|
+
const tokenStore = createFileTokenStore(join29(home, ".flavor-code", "auth.json"));
|
|
24187
|
+
const tokens2 = await tokenStore.load();
|
|
24188
|
+
const hadCredentials = Object.keys(tokens2).length > 0 || effectiveLlm !== void 0;
|
|
24189
|
+
if (!hadCredentials) {
|
|
24190
|
+
return "Not authenticated \u2014 no stored OAuth credentials to clear.";
|
|
24191
|
+
}
|
|
24192
|
+
for (let i = registeredProviders.length - 1; i >= 0; i -= 1) {
|
|
24193
|
+
const provider = registeredProviders[i];
|
|
24194
|
+
if (provider !== void 0 && provider.pkceManaged === true) {
|
|
24195
|
+
registry.unregister(provider.name);
|
|
24196
|
+
registeredProviders.splice(i, 1);
|
|
24197
|
+
}
|
|
24198
|
+
}
|
|
24199
|
+
if (effectiveLlm !== void 0) {
|
|
24200
|
+
registry.unregister(effectiveLlm.providerId);
|
|
24201
|
+
effectiveLlm = void 0;
|
|
24202
|
+
}
|
|
24203
|
+
await tokenStore.save({});
|
|
24204
|
+
const fallback = selectModels(config, registeredProviders, diagnostics);
|
|
24205
|
+
mainModel = fallback.main;
|
|
24206
|
+
childModel = fallback.child;
|
|
24207
|
+
if (fallback.mainError === void 0) delete selectedModels.mainError;
|
|
24208
|
+
else selectedModels.mainError = fallback.mainError;
|
|
24209
|
+
if (fallback.childError === void 0) delete selectedModels.childError;
|
|
24210
|
+
else selectedModels.childError = fallback.childError;
|
|
24211
|
+
if (fallback.mainError === void 0 && registry.has(safeProvider(mainModel)) && registry.has(safeProvider(childModel))) {
|
|
24212
|
+
harness.setModel("main", mainModel);
|
|
24213
|
+
harness.setModel("subagent", childModel);
|
|
24214
|
+
hallucinationGuard.setModel(childModel);
|
|
24215
|
+
goalOrchestrator.setModels(mainModel, mainModel);
|
|
24216
|
+
}
|
|
24217
|
+
await persist();
|
|
24218
|
+
return fallback.mainError === void 0 ? `Logged out. Cleared OAuth credentials. Main model ${mainModel}; subagent ${childModel}.` : `Logged out. Cleared OAuth credentials. ${fallback.mainError}`;
|
|
24138
24219
|
}
|
|
24139
24220
|
};
|
|
24140
24221
|
if (config.sleep) {
|
|
@@ -27738,11 +27819,12 @@ var DesktopRuntimeController = class {
|
|
|
27738
27819
|
].join("\n");
|
|
27739
27820
|
const delivery = await readDeliveryRun(workspace, task);
|
|
27740
27821
|
if (delivery?.nodes.api.status === "running") {
|
|
27822
|
+
const apiArtifacts = await Promise.all(generated.files.map(async (file) => artifactRef(file, await readFile33(join39(project, file)))));
|
|
27741
27823
|
const completed = await updateDeliveryRun(
|
|
27742
27824
|
workspace,
|
|
27743
27825
|
task,
|
|
27744
27826
|
delivery.revision,
|
|
27745
|
-
(run) => completeDeliveryNode(run, "api",
|
|
27827
|
+
(run) => completeDeliveryNode(run, "api", apiArtifacts)
|
|
27746
27828
|
);
|
|
27747
27829
|
await updateDeliveryRun(
|
|
27748
27830
|
workspace,
|
|
@@ -28018,6 +28100,12 @@ VITE_API_BASE_URL=${running.url}
|
|
|
28018
28100
|
});
|
|
28019
28101
|
return readD2cProductPlanView(workspace, task).then((view) => view);
|
|
28020
28102
|
}
|
|
28103
|
+
/** Read-only snapshot of the seven-node E2E delivery run; undefined when the task never started a delivery. */
|
|
28104
|
+
async getE2eDeliveryRun(task) {
|
|
28105
|
+
const workspace = this.#workspace;
|
|
28106
|
+
if (workspace === void 0) return void 0;
|
|
28107
|
+
return readDeliveryRun(workspace, task);
|
|
28108
|
+
}
|
|
28021
28109
|
async #assertProductPrdLocked(workspace, task) {
|
|
28022
28110
|
const current = await readD2cProductPlanView(workspace, task);
|
|
28023
28111
|
if (current?.plan.approvedPrd === void 0) return;
|
|
@@ -28742,6 +28830,9 @@ function installIpcHandlers() {
|
|
|
28742
28830
|
const input = D2cQualityIssueDecisionInputSchema.parse(value);
|
|
28743
28831
|
return controller.resolveD2cQualityIssue(input.task, input.issueId, input.decision);
|
|
28744
28832
|
});
|
|
28833
|
+
ipcMain.handle(DESKTOP_CHANNELS.e2eGetDeliveryRun, async (_event, value) => {
|
|
28834
|
+
return controller.getE2eDeliveryRun(D2cTaskActionInputSchema.parse(value).task);
|
|
28835
|
+
});
|
|
28745
28836
|
}
|
|
28746
28837
|
function applicationMenu() {
|
|
28747
28838
|
return Menu.buildFromTemplate([
|
package/dist/desktop/preload.cjs
CHANGED
|
@@ -65,6 +65,7 @@ var DESKTOP_CHANNELS = {
|
|
|
65
65
|
d2cRunQualityJudge: "desktop:d2c-run-quality-judge",
|
|
66
66
|
d2cResolveQualityIssue: "desktop:d2c-resolve-quality-issue",
|
|
67
67
|
d2cSetManualAcceptance: "desktop:d2c-set-manual-acceptance",
|
|
68
|
+
e2eGetDeliveryRun: "desktop:e2e-get-delivery-run",
|
|
68
69
|
event: "desktop:event"
|
|
69
70
|
};
|
|
70
71
|
|
|
@@ -158,6 +159,7 @@ var api = {
|
|
|
158
159
|
saveD2cJudgeConfig: (input) => import_electron.ipcRenderer.invoke(DESKTOP_CHANNELS.d2cSaveJudgeConfig, input),
|
|
159
160
|
runD2cQualityJudge: (task) => import_electron.ipcRenderer.invoke(DESKTOP_CHANNELS.d2cRunQualityJudge, { task }),
|
|
160
161
|
resolveD2cQualityIssue: (task, issueId, decision) => import_electron.ipcRenderer.invoke(DESKTOP_CHANNELS.d2cResolveQualityIssue, { task, issueId, decision }),
|
|
162
|
+
getE2eDeliveryRun: (task) => import_electron.ipcRenderer.invoke(DESKTOP_CHANNELS.e2eGetDeliveryRun, { task }),
|
|
161
163
|
onEvent(listener) {
|
|
162
164
|
const handler = (_event, value) => listener(value);
|
|
163
165
|
import_electron.ipcRenderer.on(DESKTOP_CHANNELS.event, handler);
|