@trydecember/cli 0.3.28 → 0.3.29
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/december.js +480 -143
- package/package.json +1 -1
package/dist/december.js
CHANGED
|
@@ -65,7 +65,7 @@ var package_default;
|
|
|
65
65
|
var init_package = __esm(() => {
|
|
66
66
|
package_default = {
|
|
67
67
|
name: "@trydecember/cli",
|
|
68
|
-
version: "0.3.
|
|
68
|
+
version: "0.3.29",
|
|
69
69
|
description: "a coding agent for terminal and cloud.",
|
|
70
70
|
homepage: "https://trydecember.com",
|
|
71
71
|
repository: {
|
|
@@ -107052,6 +107052,28 @@ async function exchangeGitHubTokenForCopilot(githubOAuthToken) {
|
|
|
107052
107052
|
});
|
|
107053
107053
|
if (!res.ok) {
|
|
107054
107054
|
const text = await res.text().catch(() => "");
|
|
107055
|
+
let parsedJson = null;
|
|
107056
|
+
try {
|
|
107057
|
+
parsedJson = JSON.parse(text);
|
|
107058
|
+
} catch {}
|
|
107059
|
+
if (res.status === 403) {
|
|
107060
|
+
const errorDetails = parsedJson?.error_details;
|
|
107061
|
+
if (errorDetails?.notification_id === "no_copilot_access") {
|
|
107062
|
+
const detailMsg = errorDetails.message || "";
|
|
107063
|
+
const userMatch = detailMsg.match(/logged in as ([^.]+)/i);
|
|
107064
|
+
const userNotice = userMatch ? ` for account @${userMatch[1].trim()}` : "";
|
|
107065
|
+
throw new Error(`No active GitHub Copilot subscription found${userNotice}. ${detailMsg} Please sign up at https://github.com/github-copilot/signup or ensure your browser is logged into an authorized GitHub account.`);
|
|
107066
|
+
}
|
|
107067
|
+
if (errorDetails?.message) {
|
|
107068
|
+
throw new Error(`GitHub Copilot subscription verification failed (403): ${errorDetails.message}`);
|
|
107069
|
+
}
|
|
107070
|
+
if (parsedJson?.message) {
|
|
107071
|
+
throw new Error(`GitHub Copilot subscription verification failed (403): ${parsedJson.message}`);
|
|
107072
|
+
}
|
|
107073
|
+
}
|
|
107074
|
+
if (parsedJson?.message) {
|
|
107075
|
+
throw new Error(`Failed to exchange GitHub token for Copilot token (${res.status}): ${parsedJson.message}`);
|
|
107076
|
+
}
|
|
107055
107077
|
throw new Error(`Failed to exchange GitHub token for Copilot token (${res.status}): ${text}`);
|
|
107056
107078
|
}
|
|
107057
107079
|
const data = await res.json();
|
|
@@ -107207,7 +107229,11 @@ var init_copilot2 = __esm(() => {
|
|
|
107207
107229
|
try {
|
|
107208
107230
|
exchangeResult = await exchangeGitHubTokenForCopilot(ghOAuthToken);
|
|
107209
107231
|
} catch (err) {
|
|
107210
|
-
|
|
107232
|
+
const msg = err?.message || String(err);
|
|
107233
|
+
if (msg.includes("No active GitHub Copilot subscription") || msg.includes("GitHub Copilot subscription verification failed")) {
|
|
107234
|
+
throw err;
|
|
107235
|
+
}
|
|
107236
|
+
throw new Error(`GitHub Copilot subscription verification failed. Please make sure your GitHub account has an active Copilot subscription and that external integrations are allowed by your organization. (${msg})`, { cause: err });
|
|
107211
107237
|
}
|
|
107212
107238
|
const copilotToken = exchangeResult.token;
|
|
107213
107239
|
const endpoint = exchangeResult.endpoint;
|
|
@@ -109462,6 +109488,9 @@ Initiating subscription login for ${providerName}...`);
|
|
|
109462
109488
|
console.log(`
|
|
109463
109489
|
Please open ${uri} in your browser and enter code: ${code}
|
|
109464
109490
|
Waiting for authorization...`);
|
|
109491
|
+
if (targetProvider === "copilot" || targetProvider === "github") {
|
|
109492
|
+
console.log("*(Note: Ensure your browser is signed into the GitHub account that owns your active Copilot subscription)*");
|
|
109493
|
+
}
|
|
109465
109494
|
});
|
|
109466
109495
|
const configToSave = await loadConfig();
|
|
109467
109496
|
configToSave.subscriptions = configToSave.subscriptions || {};
|
|
@@ -114460,10 +114489,11 @@ function formatError(e) {
|
|
|
114460
114489
|
} catch {}
|
|
114461
114490
|
return String(e) || "Unknown error";
|
|
114462
114491
|
}
|
|
114463
|
-
async function* runAgentLoop(agent, userInput) {
|
|
114492
|
+
async function* runAgentLoop(agent, userInput, options) {
|
|
114464
114493
|
const eventQueue = new AsyncQueue2;
|
|
114465
114494
|
const abortController = new AbortController;
|
|
114466
114495
|
agent.activeAbortController = abortController;
|
|
114496
|
+
const isReadOnly = Boolean(options?.readOnly || typeof userInput === "object" && userInput !== null && userInput.readOnly);
|
|
114467
114497
|
if (userInput) {
|
|
114468
114498
|
if (typeof userInput === "string") {
|
|
114469
114499
|
agent.addMessage({ role: "user", content: userInput });
|
|
@@ -114486,7 +114516,9 @@ async function* runAgentLoop(agent, userInput) {
|
|
|
114486
114516
|
});
|
|
114487
114517
|
} catch {}
|
|
114488
114518
|
eventQueue.push({ type: "AgentStart" });
|
|
114489
|
-
await runOuterLoop(agent, eventQueue, abortController.signal
|
|
114519
|
+
await runOuterLoop(agent, eventQueue, abortController.signal, {
|
|
114520
|
+
readOnly: isReadOnly
|
|
114521
|
+
});
|
|
114490
114522
|
try {
|
|
114491
114523
|
if (abortController.signal.aborted) {
|
|
114492
114524
|
agent.tracer?.endSession("ABORTED");
|
|
@@ -114525,9 +114557,9 @@ async function* runAgentLoop(agent, userInput) {
|
|
|
114525
114557
|
})();
|
|
114526
114558
|
yield* eventQueue;
|
|
114527
114559
|
}
|
|
114528
|
-
async function runOuterLoop(agent, eventQueue, signal) {
|
|
114560
|
+
async function runOuterLoop(agent, eventQueue, signal, options) {
|
|
114529
114561
|
while (!signal.aborted) {
|
|
114530
|
-
await runInnerLoop(agent, eventQueue, signal);
|
|
114562
|
+
await runInnerLoop(agent, eventQueue, signal, options);
|
|
114531
114563
|
if (signal.aborted)
|
|
114532
114564
|
break;
|
|
114533
114565
|
if (agent.followUpQueue.length > 0) {
|
|
@@ -114540,7 +114572,7 @@ async function runOuterLoop(agent, eventQueue, signal) {
|
|
|
114540
114572
|
break;
|
|
114541
114573
|
}
|
|
114542
114574
|
}
|
|
114543
|
-
async function runInnerLoop(agent, eventQueue, signal) {
|
|
114575
|
+
async function runInnerLoop(agent, eventQueue, signal, options) {
|
|
114544
114576
|
let isDone = false;
|
|
114545
114577
|
let turnCount = 0;
|
|
114546
114578
|
while (!isDone && turnCount < 100 && !signal.aborted) {
|
|
@@ -114561,7 +114593,7 @@ async function runInnerLoop(agent, eventQueue, signal) {
|
|
|
114561
114593
|
}
|
|
114562
114594
|
}
|
|
114563
114595
|
eventQueue.push({ type: "TurnStart" });
|
|
114564
|
-
const { assistantMessage, toolCalls, error } = await streamAssistantResponse(agent, eventQueue, signal, turnCount);
|
|
114596
|
+
const { assistantMessage, toolCalls, error } = await streamAssistantResponse(agent, eventQueue, signal, turnCount, options);
|
|
114565
114597
|
if (error || signal.aborted) {
|
|
114566
114598
|
break;
|
|
114567
114599
|
}
|
|
@@ -114574,7 +114606,7 @@ async function runInnerLoop(agent, eventQueue, signal) {
|
|
|
114574
114606
|
content: assistantMessage,
|
|
114575
114607
|
toolCalls
|
|
114576
114608
|
});
|
|
114577
|
-
await executeToolCalls(agent, toolCalls, eventQueue, signal);
|
|
114609
|
+
await executeToolCalls(agent, toolCalls, eventQueue, signal, options);
|
|
114578
114610
|
}
|
|
114579
114611
|
await agent.saveContext();
|
|
114580
114612
|
eventQueue.push({ type: "TurnEnd" });
|
|
@@ -114595,7 +114627,7 @@ async function runInnerLoop(agent, eventQueue, signal) {
|
|
|
114595
114627
|
}
|
|
114596
114628
|
}
|
|
114597
114629
|
}
|
|
114598
|
-
async function streamAssistantResponse(agent, eventQueue, signal, turnCount = 1) {
|
|
114630
|
+
async function streamAssistantResponse(agent, eventQueue, signal, turnCount = 1, options) {
|
|
114599
114631
|
let assistantMessage = "";
|
|
114600
114632
|
let toolCalls = [];
|
|
114601
114633
|
let thinkingText = "";
|
|
@@ -114621,7 +114653,7 @@ async function streamAssistantResponse(agent, eventQueue, signal, turnCount = 1)
|
|
|
114621
114653
|
});
|
|
114622
114654
|
}
|
|
114623
114655
|
const isConversational = isSimpleConversationalTurn(agent.messages);
|
|
114624
|
-
const activeTools = isConversational ? Array.from(agent.tools.values()).filter((t) => ["read_file", "ls", "ask_question"].includes(t.name)) : Array.from(agent.tools.values());
|
|
114656
|
+
const activeTools = options?.readOnly ? Array.from(agent.tools.values()).filter((t) => READ_ONLY_TOOLS.has(t.name)) : isConversational ? Array.from(agent.tools.values()).filter((t) => ["read_file", "ls", "ask_question"].includes(t.name)) : Array.from(agent.tools.values());
|
|
114625
114657
|
const toolsArray = activeTools.map((t, idx) => ({
|
|
114626
114658
|
name: t.name,
|
|
114627
114659
|
description: t.description ? t.description.replace(/\s+/g, " ").trim() : "",
|
|
@@ -114858,7 +114890,7 @@ ${errorMsg}`;
|
|
|
114858
114890
|
return { assistantMessage, toolCalls, error: errorMsg };
|
|
114859
114891
|
}
|
|
114860
114892
|
}
|
|
114861
|
-
async function executeToolCalls(agent, toolCalls, eventQueue, signal) {
|
|
114893
|
+
async function executeToolCalls(agent, toolCalls, eventQueue, signal, options) {
|
|
114862
114894
|
const isSequentialTool = (tc) => {
|
|
114863
114895
|
const tool = agent.tools.get(tc.name);
|
|
114864
114896
|
return tool?.executionMode === "sequential" || ["bash", "write_file", "edit_file", "edit_diff"].includes(tc.name);
|
|
@@ -114873,18 +114905,34 @@ async function executeToolCalls(agent, toolCalls, eventQueue, signal) {
|
|
|
114873
114905
|
}
|
|
114874
114906
|
}
|
|
114875
114907
|
if (parallelReadCalls.length > 0) {
|
|
114876
|
-
await executeToolCallsParallel(agent, parallelReadCalls, eventQueue, signal);
|
|
114908
|
+
await executeToolCallsParallel(agent, parallelReadCalls, eventQueue, signal, options);
|
|
114877
114909
|
}
|
|
114878
114910
|
if (sequentialWriteCalls.length > 0 && !signal.aborted) {
|
|
114879
|
-
await executeToolCallsSequential(agent, sequentialWriteCalls, eventQueue, signal);
|
|
114911
|
+
await executeToolCallsSequential(agent, sequentialWriteCalls, eventQueue, signal, options);
|
|
114880
114912
|
}
|
|
114881
114913
|
}
|
|
114882
|
-
async function executeSingleTool(agent, toolCall, eventQueue, signal) {
|
|
114914
|
+
async function executeSingleTool(agent, toolCall, eventQueue, signal, options) {
|
|
114883
114915
|
const toolStartTime = Date.now();
|
|
114884
114916
|
eventQueue.push({ type: "ToolCallStart", toolCall });
|
|
114885
114917
|
const tool = agent.tools.get(toolCall.name);
|
|
114886
114918
|
let resultStr = "";
|
|
114887
114919
|
let errorStr = undefined;
|
|
114920
|
+
if (options?.readOnly && !READ_ONLY_TOOLS.has(toolCall.name)) {
|
|
114921
|
+
errorStr = `Tool execution blocked: '${toolCall.name}' is not permitted in read-only / ask mode.`;
|
|
114922
|
+
const res = { toolCallId: toolCall.id, result: "", error: errorStr };
|
|
114923
|
+
eventQueue.push({ type: "ToolCallResult", result: res });
|
|
114924
|
+
try {
|
|
114925
|
+
agent.tracer?.recordToolExecution({
|
|
114926
|
+
toolCallId: toolCall.id,
|
|
114927
|
+
toolName: toolCall.name,
|
|
114928
|
+
input: toolCall.input,
|
|
114929
|
+
output: "",
|
|
114930
|
+
error: errorStr,
|
|
114931
|
+
durationMs: Date.now() - toolStartTime
|
|
114932
|
+
});
|
|
114933
|
+
} catch {}
|
|
114934
|
+
return { toolCall, toolResult: res, resultStr: "", errorStr };
|
|
114935
|
+
}
|
|
114888
114936
|
if (agent.operations?.ui?.requestPermission) {
|
|
114889
114937
|
const hookRes = await agent.operations.ui.requestPermission(toolCall);
|
|
114890
114938
|
if (hookRes?.block) {
|
|
@@ -114949,11 +114997,11 @@ async function executeSingleTool(agent, toolCall, eventQueue, signal) {
|
|
|
114949
114997
|
eventQueue.push({ type: "ToolCallResult", result: toolResult });
|
|
114950
114998
|
return { toolCall, toolResult, resultStr: toolResult.result, errorStr: toolResult.error };
|
|
114951
114999
|
}
|
|
114952
|
-
async function executeToolCallsSequential(agent, toolCalls, eventQueue, signal) {
|
|
115000
|
+
async function executeToolCallsSequential(agent, toolCalls, eventQueue, signal, options) {
|
|
114953
115001
|
for (const toolCall of toolCalls) {
|
|
114954
115002
|
if (signal.aborted)
|
|
114955
115003
|
break;
|
|
114956
|
-
const r = await executeSingleTool(agent, toolCall, eventQueue, signal);
|
|
115004
|
+
const r = await executeSingleTool(agent, toolCall, eventQueue, signal, options);
|
|
114957
115005
|
let finalContent = r.resultStr || "";
|
|
114958
115006
|
if (r.errorStr) {
|
|
114959
115007
|
finalContent = `Tool execution failed: ${r.errorStr}
|
|
@@ -114966,8 +115014,8 @@ Please adjust your arguments and try again.`;
|
|
|
114966
115014
|
});
|
|
114967
115015
|
}
|
|
114968
115016
|
}
|
|
114969
|
-
async function executeToolCallsParallel(agent, toolCalls, eventQueue, signal) {
|
|
114970
|
-
const promises = toolCalls.map((tc) => executeSingleTool(agent, tc, eventQueue, signal));
|
|
115017
|
+
async function executeToolCallsParallel(agent, toolCalls, eventQueue, signal, options) {
|
|
115018
|
+
const promises = toolCalls.map((tc) => executeSingleTool(agent, tc, eventQueue, signal, options));
|
|
114971
115019
|
const results = await Promise.all(promises);
|
|
114972
115020
|
for (const r of results) {
|
|
114973
115021
|
let finalContent = r.resultStr || "";
|
|
@@ -114982,7 +115030,7 @@ Please adjust your arguments and try again.`;
|
|
|
114982
115030
|
});
|
|
114983
115031
|
}
|
|
114984
115032
|
}
|
|
114985
|
-
var AsyncQueue2;
|
|
115033
|
+
var AsyncQueue2, READ_ONLY_TOOLS;
|
|
114986
115034
|
var init_agent_loop = __esm(() => {
|
|
114987
115035
|
init_src();
|
|
114988
115036
|
init_p_retry();
|
|
@@ -115023,6 +115071,15 @@ var init_agent_loop = __esm(() => {
|
|
|
115023
115071
|
}
|
|
115024
115072
|
}
|
|
115025
115073
|
};
|
|
115074
|
+
READ_ONLY_TOOLS = new Set([
|
|
115075
|
+
"read_file",
|
|
115076
|
+
"ls",
|
|
115077
|
+
"find_files",
|
|
115078
|
+
"grep_search",
|
|
115079
|
+
"web_search",
|
|
115080
|
+
"browser",
|
|
115081
|
+
"ask_question"
|
|
115082
|
+
]);
|
|
115026
115083
|
});
|
|
115027
115084
|
// ../../packages/agent/src/harness/agent-harness.ts
|
|
115028
115085
|
import fs22 from "node:fs";
|
|
@@ -115032,18 +115089,21 @@ function isReasoningModel(model, thinkingLevel) {
|
|
|
115032
115089
|
return thinkingLevel !== undefined && thinkingLevel !== "off";
|
|
115033
115090
|
}
|
|
115034
115091
|
const m = model.toLowerCase();
|
|
115035
|
-
if (m.includes("o1") || m.includes("o3") || m.includes("deepseek-reasoner") || m.includes("deepseek-r1")) {
|
|
115092
|
+
if (m.includes("o1") || m.includes("o3") || m.includes("deepseek-reasoner") || m.includes("deepseek-r1") || m.includes("thinking")) {
|
|
115036
115093
|
return true;
|
|
115037
115094
|
}
|
|
115038
115095
|
if (m.includes("claude") && thinkingLevel && thinkingLevel !== "off") {
|
|
115039
115096
|
return true;
|
|
115040
115097
|
}
|
|
115098
|
+
if (m.includes("gemini") && (m.includes("gemini-2.5") || thinkingLevel !== undefined && thinkingLevel !== "off")) {
|
|
115099
|
+
return true;
|
|
115100
|
+
}
|
|
115041
115101
|
return false;
|
|
115042
115102
|
}
|
|
115043
115103
|
function getModelFamilyPrompt(options) {
|
|
115044
115104
|
const model = options.model?.toLowerCase() || "";
|
|
115045
115105
|
const reasoning = isReasoningModel(options.model, options.thinkingLevel);
|
|
115046
|
-
if (reasoning) {
|
|
115106
|
+
if (reasoning && !model.includes("gemini")) {
|
|
115047
115107
|
return {
|
|
115048
115108
|
roleGuidelines: `### Model Specialization (Autonomous Reasoning & Verification)
|
|
115049
115109
|
- Persistent Problem Solving: Keep going until the user's task or bug is completely resolved and empirically verified before ending your turn.
|
|
@@ -115068,24 +115128,26 @@ function getModelFamilyPrompt(options) {
|
|
|
115068
115128
|
};
|
|
115069
115129
|
}
|
|
115070
115130
|
if (model.includes("gemini")) {
|
|
115131
|
+
const isGeminiThinking = model.includes("thinking") || model.includes("gemini-2.5") || options.thinkingLevel !== undefined && options.thinkingLevel !== "off";
|
|
115071
115132
|
return {
|
|
115072
115133
|
roleGuidelines: `### Model Specialization (Gemini)
|
|
115073
115134
|
- Structured Execution: Follow clear operational phases: 1) Explore and gather context, 2) Formulate targeted edits, 3) Verify thoroughly.
|
|
115074
115135
|
- Absolute File Paths: STRICTLY specify absolute file paths when referencing, viewing, or editing files. NEVER output ambiguous relative paths.`,
|
|
115075
|
-
reasoningProtocol:
|
|
115136
|
+
reasoningProtocol: isGeminiThinking ? `### Communication Protocol
|
|
115137
|
+
- Conciseness & Chat Focus: Be direct and concise. In chat messages, provide ONLY high-level status updates, architectural decisions, and tool confirmations. Do not repeat file contents in chat.
|
|
115138
|
+
- Execution Summary: At the end of your work, provide a concise summary (max 4-5 lines, single cohesive paragraph) highlighting key actions, modified files, and test verification results.` : `### Reasoning & Communication Protocol
|
|
115076
115139
|
- Thought Enclosure: Before calling any tool, you MUST enclose your step-by-step reasoning inside <thought>...</thought> tags. Write thoughts directly as natural, concise reasoning steps without outline scaffolding, markdown headers, or bullet lists (do NOT write labels like "* **Goal Understanding:**" or structured outlines).
|
|
115077
115140
|
- Conciseness & Chat Focus: Be direct and concise. In chat messages, provide ONLY high-level status updates, architectural decisions, and tool confirmations. Do not repeat file contents in chat.
|
|
115078
115141
|
- Execution Summary: At the end of your work, provide a concise summary (max 4-5 lines, single cohesive paragraph) highlighting key actions, modified files, and test verification results.`,
|
|
115079
|
-
suppressThoughtTags:
|
|
115142
|
+
suppressThoughtTags: isGeminiThinking
|
|
115080
115143
|
};
|
|
115081
115144
|
}
|
|
115082
115145
|
return {
|
|
115083
115146
|
roleGuidelines: "",
|
|
115084
|
-
reasoningProtocol: `###
|
|
115085
|
-
- Thought Enclosure: Before calling any tool, you MUST enclose your step-by-step reasoning inside <thought>...</thought> tags. Write thoughts directly as natural, concise reasoning steps without outline scaffolding, markdown headers, or bullet lists (do NOT write labels like "* **Goal Understanding:**" or structured outlines).
|
|
115147
|
+
reasoningProtocol: `### Communication Protocol
|
|
115086
115148
|
- Conciseness & Chat Focus: Be direct and concise. In chat messages, provide ONLY high-level status updates, architectural decisions, and tool confirmations. Do not repeat file contents in chat.
|
|
115087
115149
|
- Execution Summary: At the end of your work, provide a concise summary (max 4-5 lines, single cohesive paragraph) highlighting key actions, modified files, and test verification results.`,
|
|
115088
|
-
suppressThoughtTags:
|
|
115150
|
+
suppressThoughtTags: true
|
|
115089
115151
|
};
|
|
115090
115152
|
}
|
|
115091
115153
|
function buildDynamicToolGuidelines(activeTools) {
|
|
@@ -115503,6 +115565,20 @@ Select an option or type your answer: `).then((answer) => {
|
|
|
115503
115565
|
});
|
|
115504
115566
|
};
|
|
115505
115567
|
agent.operations.ui.requestPermission = async (toolCall) => {
|
|
115568
|
+
if (options.readOnly && ![
|
|
115569
|
+
"read_file",
|
|
115570
|
+
"ls",
|
|
115571
|
+
"find_files",
|
|
115572
|
+
"grep_search",
|
|
115573
|
+
"web_search",
|
|
115574
|
+
"browser",
|
|
115575
|
+
"ask_question"
|
|
115576
|
+
].includes(toolCall.name)) {
|
|
115577
|
+
return {
|
|
115578
|
+
block: true,
|
|
115579
|
+
reason: `Tool '${toolCall.name}' is not allowed in read-only / ask mode.`
|
|
115580
|
+
};
|
|
115581
|
+
}
|
|
115506
115582
|
if (isNonInteractive) {
|
|
115507
115583
|
return { block: false };
|
|
115508
115584
|
}
|
|
@@ -115546,7 +115622,7 @@ Execute ${toolCall.name}? (y/n): `);
|
|
|
115546
115622
|
effectivePrompt = resolved.expandedPrompt;
|
|
115547
115623
|
} catch {}
|
|
115548
115624
|
}
|
|
115549
|
-
const stream = runAgentLoop(agent, effectivePrompt);
|
|
115625
|
+
const stream = runAgentLoop(agent, options.readOnly ? { content: effectivePrompt, readOnly: true } : effectivePrompt);
|
|
115550
115626
|
for await (const event of stream) {
|
|
115551
115627
|
switch (event.type) {
|
|
115552
115628
|
case "StreamChunk":
|
|
@@ -168564,6 +168640,92 @@ var init_provider_factory = __esm(() => {
|
|
|
168564
168640
|
init_subscription_manager();
|
|
168565
168641
|
});
|
|
168566
168642
|
|
|
168643
|
+
// src/constants/prompts.ts
|
|
168644
|
+
var exports_prompts = {};
|
|
168645
|
+
__export(exports_prompts, {
|
|
168646
|
+
getAskPrompt: () => getAskPrompt,
|
|
168647
|
+
getGrillPrompt: () => getGrillPrompt,
|
|
168648
|
+
getPlanExecutionPrompt: () => getPlanExecutionPrompt,
|
|
168649
|
+
getPlanPrompt: () => getPlanPrompt,
|
|
168650
|
+
getPlanRefinePrompt: () => getPlanRefinePrompt
|
|
168651
|
+
});
|
|
168652
|
+
var getGrillPrompt = (userPrompt, projectContext) => `You are a principal software architect interviewing a developer to align on a technical specification before implementation.
|
|
168653
|
+
|
|
168654
|
+
The user wants to implement: "${userPrompt}"
|
|
168655
|
+
|
|
168656
|
+
${projectContext ? `<project_context>
|
|
168657
|
+
${projectContext}
|
|
168658
|
+
</project_context>
|
|
168659
|
+
` : ""}
|
|
168660
|
+
Analyze the user's request and the project context. Generate between 1 and 4 targeted, high-impact multiple-choice questions to clarify critical requirements, architectural choices, tech stack decisions, and edge cases. If the task is simple and unambiguous, generate fewer questions (e.g. 1 or 2). Do not ask more than 4 questions.
|
|
168661
|
+
|
|
168662
|
+
Requirements for questions:
|
|
168663
|
+
1. Focus on technical depth: probe architectural tradeoffs, API design, state management, edge cases, and error handling.
|
|
168664
|
+
2. Each question MUST have 2 to 3 distinct, concrete options representing clear design choices.
|
|
168665
|
+
3. Leverage the provided project context (if available) to tailor choices specifically to the existing codebase patterns.
|
|
168666
|
+
|
|
168667
|
+
Return the output strictly as a JSON array of objects with the following schema:
|
|
168668
|
+
[
|
|
168669
|
+
{
|
|
168670
|
+
"question": "Question text?",
|
|
168671
|
+
"options": ["Option 1 (Design choice A)", "Option 2 (Design choice B)", "Option 3 (Design choice C)"]
|
|
168672
|
+
}
|
|
168673
|
+
]
|
|
168674
|
+
|
|
168675
|
+
Do not include any other text, markdown formatting, or code blocks. Return raw JSON only.`, getPlanPrompt = (originalPrompt, qaPairs) => `You are an autonomous software engineer.
|
|
168676
|
+
The user wants to implement: "${originalPrompt}"
|
|
168677
|
+
${qaPairs && qaPairs.length > 0 ? `Here is the alignment interview results:
|
|
168678
|
+
${qaPairs.map((qa) => `Q: ${qa.question}
|
|
168679
|
+
A: ${qa.answer}`).join(`
|
|
168680
|
+
|
|
168681
|
+
`)}
|
|
168682
|
+
` : ""}
|
|
168683
|
+
Please create a detailed, step-by-step implementation plan based on these requirements.
|
|
168684
|
+
Do NOT execute any tools. Only describe the plan.
|
|
168685
|
+
Start your response with '### Implementation Plan' and list the concrete steps.
|
|
168686
|
+
Explain which files need to be created, modified, or deleted, and what the changes will be.`, getPlanExecutionPrompt = (originalPrompt, planText, qaPairs) => `You are an autonomous software engineer.
|
|
168687
|
+
The user has approved the implementation plan for: "${originalPrompt}".
|
|
168688
|
+
|
|
168689
|
+
${qaPairs && qaPairs.length > 0 ? `Key alignment decisions from the interview:
|
|
168690
|
+
${qaPairs.map((qa) => `Q: ${qa.question}
|
|
168691
|
+
A: ${qa.answer}`).join(`
|
|
168692
|
+
|
|
168693
|
+
`)}
|
|
168694
|
+
|
|
168695
|
+
` : ""}Approved Implementation Plan:
|
|
168696
|
+
${planText}
|
|
168697
|
+
|
|
168698
|
+
You are now in execution mode. Proceed with implementation immediately.
|
|
168699
|
+
Execute the plan step-by-step using your available tools (file editing, file creation, bash commands).
|
|
168700
|
+
Do not wait for further confirmation before starting tool execution.
|
|
168701
|
+
Report your progress as you complete each step.
|
|
168702
|
+
If a tool execution fails or encounters unexpected errors, do not repeat the failing action in a loop. Assess the failure, adjust your approach or remaining steps, and if critical information is missing, ask for clarification.`, getPlanRefinePrompt = (originalPrompt, previousPlan, feedback, qaPairs) => `You are an autonomous software engineer.
|
|
168703
|
+
The user wants to implement: "${originalPrompt}"
|
|
168704
|
+
|
|
168705
|
+
${qaPairs && qaPairs.length > 0 ? `Previous alignment interview results:
|
|
168706
|
+
${qaPairs.map((qa) => `Q: ${qa.question}
|
|
168707
|
+
A: ${qa.answer}`).join(`
|
|
168708
|
+
|
|
168709
|
+
`)}
|
|
168710
|
+
|
|
168711
|
+
` : ""}Previous Implementation Plan:
|
|
168712
|
+
${previousPlan}
|
|
168713
|
+
|
|
168714
|
+
The user provided the following feedback to refine the plan:
|
|
168715
|
+
"${feedback}"
|
|
168716
|
+
|
|
168717
|
+
Please update and refine the detailed, step-by-step implementation plan based on this feedback.
|
|
168718
|
+
Do NOT execute any tools. Only describe the updated plan.
|
|
168719
|
+
Start your response with '### Implementation Plan' and list the concrete updated steps.
|
|
168720
|
+
Explain which files need to be created, modified, or deleted, and what the changes will be.`, getAskPrompt = (question) => `You are in Ask mode (read-only Q&A).
|
|
168721
|
+
The user is asking: "${question}"
|
|
168722
|
+
|
|
168723
|
+
Guidelines:
|
|
168724
|
+
1. Answer the user's question thoroughly, clearly, and accurately based on the codebase.
|
|
168725
|
+
2. You can use your available tools (search, read files, list directories, search web) to inspect and verify code facts.
|
|
168726
|
+
3. You CANNOT and MUST NOT modify any files, write new files, or run bash/terminal commands.
|
|
168727
|
+
4. Provide comprehensive explanations, referencing relevant file paths, types, functions, and code snippets directly in your answer.`;
|
|
168728
|
+
|
|
168567
168729
|
// ../../node_modules/.bun/react@19.2.7/node_modules/react/cjs/react.development.js
|
|
168568
168730
|
var require_react_development = __commonJS(function(exports, module) {
|
|
168569
168731
|
(function() {
|
|
@@ -207370,6 +207532,12 @@ var init_commands2 = __esm(() => {
|
|
|
207370
207532
|
init_clipboard();
|
|
207371
207533
|
init_handoff();
|
|
207372
207534
|
COMMANDS = [
|
|
207535
|
+
{
|
|
207536
|
+
name: "ask",
|
|
207537
|
+
description: "Ask a question about the codebase (read-only Q&A mode)",
|
|
207538
|
+
value: "/ask",
|
|
207539
|
+
action: (ctx) => {}
|
|
207540
|
+
},
|
|
207373
207541
|
{
|
|
207374
207542
|
name: "clear",
|
|
207375
207543
|
description: "Clear conversation history",
|
|
@@ -208573,6 +208741,7 @@ var init_input_bar = __esm(async () => {
|
|
|
208573
208741
|
setValue("");
|
|
208574
208742
|
handleContentChange("");
|
|
208575
208743
|
const forwardCommands = [
|
|
208744
|
+
"/ask",
|
|
208576
208745
|
"/grill",
|
|
208577
208746
|
"/grill-me",
|
|
208578
208747
|
"/login",
|
|
@@ -253981,19 +254150,114 @@ function formatThought(raw) {
|
|
|
253981
254150
|
return cleanedLines.join(`
|
|
253982
254151
|
`);
|
|
253983
254152
|
}
|
|
253984
|
-
function
|
|
254153
|
+
function CollapsibleThought({
|
|
254154
|
+
content,
|
|
254155
|
+
isStreaming,
|
|
254156
|
+
forceExpanded,
|
|
254157
|
+
durationMs
|
|
254158
|
+
}) {
|
|
254159
|
+
const [elapsedSeconds, setElapsedSeconds] = import_react47.useState(0);
|
|
254160
|
+
const startTimeRef = import_react47.useRef(null);
|
|
254161
|
+
const finalDurationRef = import_react47.useRef(null);
|
|
254162
|
+
import_react47.useEffect(() => {
|
|
254163
|
+
if (!isStreaming) {
|
|
254164
|
+
if (startTimeRef.current) {
|
|
254165
|
+
const totalElapsed = (Date.now() - startTimeRef.current) / 1000;
|
|
254166
|
+
const finalSec = Math.round(totalElapsed * 10) / 10;
|
|
254167
|
+
finalDurationRef.current = Math.max(0.1, finalSec);
|
|
254168
|
+
setElapsedSeconds(finalSec);
|
|
254169
|
+
startTimeRef.current = null;
|
|
254170
|
+
}
|
|
254171
|
+
return;
|
|
254172
|
+
}
|
|
254173
|
+
if (!startTimeRef.current) {
|
|
254174
|
+
startTimeRef.current = Date.now();
|
|
254175
|
+
}
|
|
254176
|
+
const timer = setInterval(() => {
|
|
254177
|
+
if (startTimeRef.current) {
|
|
254178
|
+
const diff = (Date.now() - startTimeRef.current) / 1000;
|
|
254179
|
+
setElapsedSeconds(Math.round(diff * 10) / 10);
|
|
254180
|
+
}
|
|
254181
|
+
}, 100);
|
|
254182
|
+
return () => clearInterval(timer);
|
|
254183
|
+
}, [isStreaming]);
|
|
253985
254184
|
const formatted = formatThought(content);
|
|
253986
|
-
if (!formatted)
|
|
254185
|
+
if (!formatted && !isStreaming)
|
|
253987
254186
|
return null;
|
|
253988
|
-
|
|
254187
|
+
const words = formatted.trim() ? formatted.trim().split(/\s+/).length : 0;
|
|
254188
|
+
const tokenCount = Math.max(1, Math.round(words * 1.33));
|
|
254189
|
+
const displayDuration = durationMs !== undefined ? (durationMs / 1000).toFixed(1) : finalDurationRef.current !== null && finalDurationRef.current > 0 ? finalDurationRef.current.toFixed(1) : elapsedSeconds > 0 ? elapsedSeconds.toFixed(1) : Math.max(0.5, Math.round(words / 25 * 10) / 10).toFixed(1);
|
|
254190
|
+
if (isStreaming) {
|
|
254191
|
+
return /* @__PURE__ */ jsx_runtime14.jsxs(Box_default, {
|
|
254192
|
+
flexDirection: "row",
|
|
254193
|
+
marginY: 0,
|
|
254194
|
+
gap: 1,
|
|
254195
|
+
alignItems: "center",
|
|
254196
|
+
children: [
|
|
254197
|
+
/* @__PURE__ */ jsx_runtime14.jsx(Text3, {
|
|
254198
|
+
color: THEME.colors.brand,
|
|
254199
|
+
bold: true,
|
|
254200
|
+
children: "✱"
|
|
254201
|
+
}),
|
|
254202
|
+
/* @__PURE__ */ jsx_runtime14.jsx(Text3, {
|
|
254203
|
+
color: THEME.colors.text,
|
|
254204
|
+
children: "Thinking"
|
|
254205
|
+
}),
|
|
254206
|
+
/* @__PURE__ */ jsx_runtime14.jsxs(Text3, {
|
|
254207
|
+
color: THEME.colors.muted,
|
|
254208
|
+
children: [
|
|
254209
|
+
"(",
|
|
254210
|
+
displayDuration,
|
|
254211
|
+
"s)..."
|
|
254212
|
+
]
|
|
254213
|
+
})
|
|
254214
|
+
]
|
|
254215
|
+
});
|
|
254216
|
+
}
|
|
254217
|
+
const isExpanded = forceExpanded ?? false;
|
|
254218
|
+
const formattedLines = formatted.split(/\r?\n/).filter((l) => l.trim() !== "");
|
|
254219
|
+
return /* @__PURE__ */ jsx_runtime14.jsxs(Box_default, {
|
|
253989
254220
|
flexDirection: "column",
|
|
253990
|
-
paddingLeft: 1,
|
|
253991
254221
|
marginY: 0,
|
|
253992
|
-
children:
|
|
253993
|
-
|
|
253994
|
-
|
|
253995
|
-
|
|
253996
|
-
|
|
254222
|
+
children: [
|
|
254223
|
+
/* @__PURE__ */ jsx_runtime14.jsxs(Box_default, {
|
|
254224
|
+
flexDirection: "row",
|
|
254225
|
+
gap: 1,
|
|
254226
|
+
alignItems: "center",
|
|
254227
|
+
children: [
|
|
254228
|
+
/* @__PURE__ */ jsx_runtime14.jsx(Text3, {
|
|
254229
|
+
color: THEME.colors.muted,
|
|
254230
|
+
children: "✱"
|
|
254231
|
+
}),
|
|
254232
|
+
/* @__PURE__ */ jsx_runtime14.jsxs(Text3, {
|
|
254233
|
+
color: THEME.colors.muted,
|
|
254234
|
+
children: [
|
|
254235
|
+
"Thought for ",
|
|
254236
|
+
displayDuration,
|
|
254237
|
+
"s (",
|
|
254238
|
+
tokenCount,
|
|
254239
|
+
" tokens)"
|
|
254240
|
+
]
|
|
254241
|
+
}),
|
|
254242
|
+
/* @__PURE__ */ jsx_runtime14.jsxs(Text3, {
|
|
254243
|
+
color: THEME.colors.muted,
|
|
254244
|
+
children: [
|
|
254245
|
+
"· ctrl+o to ",
|
|
254246
|
+
isExpanded ? "collapse" : "view"
|
|
254247
|
+
]
|
|
254248
|
+
})
|
|
254249
|
+
]
|
|
254250
|
+
}),
|
|
254251
|
+
isExpanded && formattedLines.length > 0 && /* @__PURE__ */ jsx_runtime14.jsx(Box_default, {
|
|
254252
|
+
flexDirection: "column",
|
|
254253
|
+
paddingLeft: 2,
|
|
254254
|
+
marginTop: 0,
|
|
254255
|
+
children: formattedLines.map((line, lidx) => /* @__PURE__ */ jsx_runtime14.jsx(Text3, {
|
|
254256
|
+
color: THEME.colors.muted,
|
|
254257
|
+
children: line
|
|
254258
|
+
}, lidx))
|
|
254259
|
+
})
|
|
254260
|
+
]
|
|
253997
254261
|
});
|
|
253998
254262
|
}
|
|
253999
254263
|
function StyledCommand({ command, truncate = true }) {
|
|
@@ -254192,9 +254456,13 @@ var init_bot_message = __esm(async () => {
|
|
|
254192
254456
|
}),
|
|
254193
254457
|
parts.map((part, pidx) => {
|
|
254194
254458
|
if (/^<(?:thought|think)(?:>| [^>]*>)/i.test(part)) {
|
|
254459
|
+
const isClosed = /<\/(?:thought|think)>$/i.test(part);
|
|
254460
|
+
const isStreaming = !isClosed && idx === blocks.length - 1 && pidx === parts.length - 1;
|
|
254195
254461
|
const thoughtContent = part.replace(/^<(?:thought|think)(?:>| [^>]*>)/i, "").replace(/<\/(?:thought|think)>$/i, "").trim();
|
|
254196
|
-
return /* @__PURE__ */ jsx_runtime14.jsx(
|
|
254197
|
-
content: thoughtContent
|
|
254462
|
+
return /* @__PURE__ */ jsx_runtime14.jsx(CollapsibleThought, {
|
|
254463
|
+
content: thoughtContent,
|
|
254464
|
+
isStreaming,
|
|
254465
|
+
forceExpanded: expandCommands
|
|
254198
254466
|
}, pidx);
|
|
254199
254467
|
}
|
|
254200
254468
|
if (part.trim() === "")
|
|
@@ -254248,8 +254516,11 @@ var init_bot_message = __esm(async () => {
|
|
|
254248
254516
|
}, idx);
|
|
254249
254517
|
}
|
|
254250
254518
|
case "thinking": {
|
|
254251
|
-
return /* @__PURE__ */ jsx_runtime14.jsx(
|
|
254252
|
-
content: block.content
|
|
254519
|
+
return /* @__PURE__ */ jsx_runtime14.jsx(CollapsibleThought, {
|
|
254520
|
+
content: block.content,
|
|
254521
|
+
isStreaming: block.isStreaming,
|
|
254522
|
+
durationMs: block.durationMs,
|
|
254523
|
+
forceExpanded: expandCommands
|
|
254253
254524
|
}, idx);
|
|
254254
254525
|
}
|
|
254255
254526
|
case "compaction": {
|
|
@@ -257402,6 +257673,17 @@ function SubscriptionSelectMenu(props) {
|
|
|
257402
257673
|
/* @__PURE__ */ jsx_runtime32.jsx(Text3, {
|
|
257403
257674
|
color: isSelected ? THEME.colors.brand : THEME.colors.text,
|
|
257404
257675
|
children: item.label
|
|
257676
|
+
}),
|
|
257677
|
+
item.hint && /* @__PURE__ */ jsx_runtime32.jsx(Box_default, {
|
|
257678
|
+
marginLeft: 1,
|
|
257679
|
+
children: /* @__PURE__ */ jsx_runtime32.jsxs(Text3, {
|
|
257680
|
+
color: THEME.colors.muted,
|
|
257681
|
+
children: [
|
|
257682
|
+
"(",
|
|
257683
|
+
item.hint,
|
|
257684
|
+
")"
|
|
257685
|
+
]
|
|
257686
|
+
})
|
|
257405
257687
|
})
|
|
257406
257688
|
]
|
|
257407
257689
|
}, item.value);
|
|
@@ -257432,19 +257714,23 @@ var init_subscription_select_menu = __esm(async () => {
|
|
|
257432
257714
|
SUBSCRIPTION_MENU_ITEMS = [
|
|
257433
257715
|
{
|
|
257434
257716
|
label: "Anthropic (Claude)",
|
|
257435
|
-
value: "claude"
|
|
257717
|
+
value: "claude",
|
|
257718
|
+
hint: "Requires Claude Pro or Max"
|
|
257436
257719
|
},
|
|
257437
257720
|
{
|
|
257438
257721
|
label: "GitHub (Copilot)",
|
|
257439
|
-
value: "copilot"
|
|
257722
|
+
value: "copilot",
|
|
257723
|
+
hint: "Requires active Copilot plan"
|
|
257440
257724
|
},
|
|
257441
257725
|
{
|
|
257442
257726
|
label: "Google (Gemini / Antigravity)",
|
|
257443
|
-
value: "gemini"
|
|
257727
|
+
value: "gemini",
|
|
257728
|
+
hint: "Requires Gemini Advanced / Antigravity"
|
|
257444
257729
|
},
|
|
257445
257730
|
{
|
|
257446
257731
|
label: "OpenAI (ChatGPT)",
|
|
257447
|
-
value: "codex"
|
|
257732
|
+
value: "codex",
|
|
257733
|
+
hint: "Requires ChatGPT Plus / Pro"
|
|
257448
257734
|
}
|
|
257449
257735
|
];
|
|
257450
257736
|
});
|
|
@@ -259038,77 +259324,6 @@ var init_messages5 = __esm(() => {
|
|
|
259038
259324
|
};
|
|
259039
259325
|
});
|
|
259040
259326
|
|
|
259041
|
-
// src/constants/prompts.ts
|
|
259042
|
-
var getGrillPrompt = (userPrompt, projectContext) => `You are a principal software architect interviewing a developer to align on a technical specification before implementation.
|
|
259043
|
-
|
|
259044
|
-
The user wants to implement: "${userPrompt}"
|
|
259045
|
-
|
|
259046
|
-
${projectContext ? `<project_context>
|
|
259047
|
-
${projectContext}
|
|
259048
|
-
</project_context>
|
|
259049
|
-
` : ""}
|
|
259050
|
-
Analyze the user's request and the project context. Generate between 1 and 4 targeted, high-impact multiple-choice questions to clarify critical requirements, architectural choices, tech stack decisions, and edge cases. If the task is simple and unambiguous, generate fewer questions (e.g. 1 or 2). Do not ask more than 4 questions.
|
|
259051
|
-
|
|
259052
|
-
Requirements for questions:
|
|
259053
|
-
1. Focus on technical depth: probe architectural tradeoffs, API design, state management, edge cases, and error handling.
|
|
259054
|
-
2. Each question MUST have 2 to 3 distinct, concrete options representing clear design choices.
|
|
259055
|
-
3. Leverage the provided project context (if available) to tailor choices specifically to the existing codebase patterns.
|
|
259056
|
-
|
|
259057
|
-
Return the output strictly as a JSON array of objects with the following schema:
|
|
259058
|
-
[
|
|
259059
|
-
{
|
|
259060
|
-
"question": "Question text?",
|
|
259061
|
-
"options": ["Option 1 (Design choice A)", "Option 2 (Design choice B)", "Option 3 (Design choice C)"]
|
|
259062
|
-
}
|
|
259063
|
-
]
|
|
259064
|
-
|
|
259065
|
-
Do not include any other text, markdown formatting, or code blocks. Return raw JSON only.`, getPlanPrompt = (originalPrompt, qaPairs) => `You are an autonomous software engineer.
|
|
259066
|
-
The user wants to implement: "${originalPrompt}"
|
|
259067
|
-
${qaPairs && qaPairs.length > 0 ? `Here is the alignment interview results:
|
|
259068
|
-
${qaPairs.map((qa) => `Q: ${qa.question}
|
|
259069
|
-
A: ${qa.answer}`).join(`
|
|
259070
|
-
|
|
259071
|
-
`)}
|
|
259072
|
-
` : ""}
|
|
259073
|
-
Please create a detailed, step-by-step implementation plan based on these requirements.
|
|
259074
|
-
Do NOT execute any tools. Only describe the plan.
|
|
259075
|
-
Start your response with '### Implementation Plan' and list the concrete steps.
|
|
259076
|
-
Explain which files need to be created, modified, or deleted, and what the changes will be.`, getPlanExecutionPrompt = (originalPrompt, planText, qaPairs) => `You are an autonomous software engineer.
|
|
259077
|
-
The user has approved the implementation plan for: "${originalPrompt}".
|
|
259078
|
-
|
|
259079
|
-
${qaPairs && qaPairs.length > 0 ? `Key alignment decisions from the interview:
|
|
259080
|
-
${qaPairs.map((qa) => `Q: ${qa.question}
|
|
259081
|
-
A: ${qa.answer}`).join(`
|
|
259082
|
-
|
|
259083
|
-
`)}
|
|
259084
|
-
|
|
259085
|
-
` : ""}Approved Implementation Plan:
|
|
259086
|
-
${planText}
|
|
259087
|
-
|
|
259088
|
-
You are now in execution mode. Proceed with implementation immediately.
|
|
259089
|
-
Execute the plan step-by-step using your available tools (file editing, file creation, bash commands).
|
|
259090
|
-
Do not wait for further confirmation before starting tool execution.
|
|
259091
|
-
Report your progress as you complete each step.
|
|
259092
|
-
If a tool execution fails or encounters unexpected errors, do not repeat the failing action in a loop. Assess the failure, adjust your approach or remaining steps, and if critical information is missing, ask for clarification.`, getPlanRefinePrompt = (originalPrompt, previousPlan, feedback, qaPairs) => `You are an autonomous software engineer.
|
|
259093
|
-
The user wants to implement: "${originalPrompt}"
|
|
259094
|
-
|
|
259095
|
-
${qaPairs && qaPairs.length > 0 ? `Previous alignment interview results:
|
|
259096
|
-
${qaPairs.map((qa) => `Q: ${qa.question}
|
|
259097
|
-
A: ${qa.answer}`).join(`
|
|
259098
|
-
|
|
259099
|
-
`)}
|
|
259100
|
-
|
|
259101
|
-
` : ""}Previous Implementation Plan:
|
|
259102
|
-
${previousPlan}
|
|
259103
|
-
|
|
259104
|
-
The user provided the following feedback to refine the plan:
|
|
259105
|
-
"${feedback}"
|
|
259106
|
-
|
|
259107
|
-
Please update and refine the detailed, step-by-step implementation plan based on this feedback.
|
|
259108
|
-
Do NOT execute any tools. Only describe the updated plan.
|
|
259109
|
-
Start your response with '### Implementation Plan' and list the concrete updated steps.
|
|
259110
|
-
Explain which files need to be created, modified, or deleted, and what the changes will be.`;
|
|
259111
|
-
|
|
259112
259327
|
// ../../node_modules/.bun/zustand@5.0.14+93dbe784b8baa420/node_modules/zustand/esm/vanilla.mjs
|
|
259113
259328
|
var createStoreImpl = (createState) => {
|
|
259114
259329
|
let state;
|
|
@@ -260126,6 +260341,8 @@ function parseErrorMessage(err, context) {
|
|
|
260126
260341
|
if (extracted)
|
|
260127
260342
|
return extracted;
|
|
260128
260343
|
}
|
|
260344
|
+
if (typeof parsed.error_details?.message === "string")
|
|
260345
|
+
return parsed.error_details.message;
|
|
260129
260346
|
if (typeof parsed.error?.message === "string")
|
|
260130
260347
|
return parsed.error.message;
|
|
260131
260348
|
if (typeof parsed.message === "string")
|
|
@@ -260140,6 +260357,8 @@ function parseErrorMessage(err, context) {
|
|
|
260140
260357
|
const jsonStr = str.slice(firstBrace, lastBrace + 1);
|
|
260141
260358
|
try {
|
|
260142
260359
|
const parsed = JSON.parse(jsonStr);
|
|
260360
|
+
if (parsed?.error_details?.message && typeof parsed.error_details.message === "string")
|
|
260361
|
+
return parsed.error_details.message;
|
|
260143
260362
|
if (parsed?.error?.message && typeof parsed.error.message === "string")
|
|
260144
260363
|
return parsed.error.message;
|
|
260145
260364
|
if (parsed?.message && typeof parsed.message === "string")
|
|
@@ -260253,6 +260472,26 @@ function parseError(err, context) {
|
|
|
260253
260472
|
hint: "Please switch models using `/model` (e.g. glm-5.2, gpt-5.5, claude-opus-4-6, glm-4-plus)."
|
|
260254
260473
|
};
|
|
260255
260474
|
}
|
|
260475
|
+
const isCopilotNoAccess = combined.includes("no_copilot_access") || combined.includes("no access to github copilot") || combined.includes("no active github copilot subscription");
|
|
260476
|
+
if (isCopilotNoAccess) {
|
|
260477
|
+
let cause = explicitCause;
|
|
260478
|
+
if (!cause) {
|
|
260479
|
+
const match = fullMessage.match(/No access to GitHub Copilot found[^\n]*/i);
|
|
260480
|
+
if (match) {
|
|
260481
|
+
cause = match[0].trim();
|
|
260482
|
+
} else {
|
|
260483
|
+
const parts = fullMessage.split(`
|
|
260484
|
+
`);
|
|
260485
|
+
cause = parts.length > 1 ? parts.slice(1).join(`
|
|
260486
|
+
`).trim() : fullMessage;
|
|
260487
|
+
}
|
|
260488
|
+
}
|
|
260489
|
+
return {
|
|
260490
|
+
message: "No active GitHub Copilot subscription found.",
|
|
260491
|
+
cause,
|
|
260492
|
+
hint: "Please subscribe at https://github.com/github-copilot/signup, ensure your browser is logged into the correct GitHub account, or use BYOK / Ollama instead."
|
|
260493
|
+
};
|
|
260494
|
+
}
|
|
260256
260495
|
const isAuthError = combined.includes("401") || combined.includes("unauthorized") || combined.includes("invalid token") || combined.includes("access token expired") || combined.includes("session expired") || combined.includes("session not found");
|
|
260257
260496
|
if (isAuthError) {
|
|
260258
260497
|
const parts = fullMessage.split(`
|
|
@@ -260863,6 +261102,21 @@ async function processAgentStream({
|
|
|
260863
261102
|
}) {
|
|
260864
261103
|
let pendingEvents = [];
|
|
260865
261104
|
let flushTimeout = null;
|
|
261105
|
+
let thinkingStartTime = null;
|
|
261106
|
+
const finalizeThinking = (bList) => {
|
|
261107
|
+
if (thinkingStartTime) {
|
|
261108
|
+
const elapsed = Date.now() - thinkingStartTime;
|
|
261109
|
+
for (let i = bList.length - 1;i >= 0; i--) {
|
|
261110
|
+
const b = bList[i];
|
|
261111
|
+
if (b && b.type === "thinking" && b.isStreaming) {
|
|
261112
|
+
b.isStreaming = false;
|
|
261113
|
+
b.durationMs = elapsed;
|
|
261114
|
+
break;
|
|
261115
|
+
}
|
|
261116
|
+
}
|
|
261117
|
+
thinkingStartTime = null;
|
|
261118
|
+
}
|
|
261119
|
+
};
|
|
260866
261120
|
const flush = () => {
|
|
260867
261121
|
if (pendingEvents.length === 0)
|
|
260868
261122
|
return;
|
|
@@ -260879,6 +261133,7 @@ async function processAgentStream({
|
|
|
260879
261133
|
blocks.push({ type: "text", content: "Thinking..." });
|
|
260880
261134
|
break;
|
|
260881
261135
|
case "AgentError": {
|
|
261136
|
+
finalizeThinking(blocks);
|
|
260882
261137
|
const lastBlock = blocks[blocks.length - 1];
|
|
260883
261138
|
if (lastBlock && (lastBlock.type === "thinking" || lastBlock.type === "text" && isStatusMessage(lastBlock.content))) {
|
|
260884
261139
|
blocks.pop();
|
|
@@ -260893,6 +261148,7 @@ async function processAgentStream({
|
|
|
260893
261148
|
break;
|
|
260894
261149
|
}
|
|
260895
261150
|
case "AgentInterrupt": {
|
|
261151
|
+
finalizeThinking(blocks);
|
|
260896
261152
|
const lastBlock = blocks[blocks.length - 1];
|
|
260897
261153
|
if (lastBlock && lastBlock.type === "text" && isStatusMessage(lastBlock.content)) {
|
|
260898
261154
|
lastBlock.content = "";
|
|
@@ -260918,6 +261174,7 @@ async function processAgentStream({
|
|
|
260918
261174
|
break;
|
|
260919
261175
|
}
|
|
260920
261176
|
case "StreamChunk": {
|
|
261177
|
+
finalizeThinking(blocks);
|
|
260921
261178
|
if (!event.content)
|
|
260922
261179
|
break;
|
|
260923
261180
|
const lastBlock = blocks[blocks.length - 1];
|
|
@@ -260936,18 +261193,23 @@ async function processAgentStream({
|
|
|
260936
261193
|
const chunk = event.content || "";
|
|
260937
261194
|
if (!chunk)
|
|
260938
261195
|
break;
|
|
261196
|
+
if (!thinkingStartTime) {
|
|
261197
|
+
thinkingStartTime = Date.now();
|
|
261198
|
+
}
|
|
260939
261199
|
const lastBlock = blocks[blocks.length - 1];
|
|
260940
261200
|
if (lastBlock && lastBlock.type === "thinking") {
|
|
260941
261201
|
lastBlock.content += chunk;
|
|
261202
|
+
lastBlock.isStreaming = true;
|
|
260942
261203
|
} else {
|
|
260943
261204
|
if (lastBlock && lastBlock.type === "text" && isStatusMessage(lastBlock.content)) {
|
|
260944
261205
|
blocks.pop();
|
|
260945
261206
|
}
|
|
260946
|
-
blocks.push({ type: "thinking", content: chunk });
|
|
261207
|
+
blocks.push({ type: "thinking", content: chunk, isStreaming: true });
|
|
260947
261208
|
}
|
|
260948
261209
|
break;
|
|
260949
261210
|
}
|
|
260950
261211
|
case "ToolCallStart": {
|
|
261212
|
+
finalizeThinking(blocks);
|
|
260951
261213
|
const lastBlock = blocks[blocks.length - 1];
|
|
260952
261214
|
if (lastBlock && lastBlock.type === "text" && isStatusMessage(lastBlock.content)) {
|
|
260953
261215
|
blocks.pop();
|
|
@@ -261017,7 +261279,17 @@ async function processAgentStream({
|
|
|
261017
261279
|
setActiveMessages((prev) => prev.map((msg) => {
|
|
261018
261280
|
if (msg.id !== assistantMsgId)
|
|
261019
261281
|
return msg;
|
|
261020
|
-
const
|
|
261282
|
+
const finalElapsed = thinkingStartTime ? Date.now() - thinkingStartTime : undefined;
|
|
261283
|
+
const blocks = (msg.blocks || []).map((b) => {
|
|
261284
|
+
if (b.type === "thinking" && b.isStreaming) {
|
|
261285
|
+
return {
|
|
261286
|
+
...b,
|
|
261287
|
+
isStreaming: false,
|
|
261288
|
+
durationMs: b.durationMs ?? finalElapsed
|
|
261289
|
+
};
|
|
261290
|
+
}
|
|
261291
|
+
return b;
|
|
261292
|
+
}).filter((b) => !(b.type === "text" && isStatusMessage(b.content)));
|
|
261021
261293
|
return { ...msg, blocks };
|
|
261022
261294
|
}));
|
|
261023
261295
|
}
|
|
@@ -261271,6 +261543,10 @@ Please open [${uri}](${uri}) in your browser to authorize.`;
|
|
|
261271
261543
|
if (code && !code.endsWith("-AUTH")) {
|
|
261272
261544
|
promptText = `
|
|
261273
261545
|
Please open [${uri}](${uri}) on your device and enter code: \`${code}\``;
|
|
261546
|
+
}
|
|
261547
|
+
if (item.value === "copilot") {
|
|
261548
|
+
promptText += `
|
|
261549
|
+
*(Note: Ensure your browser is logged into the GitHub account that owns your active Copilot subscription)*`;
|
|
261274
261550
|
}
|
|
261275
261551
|
setActiveMessages([
|
|
261276
261552
|
{
|
|
@@ -261332,7 +261608,7 @@ ${formatSubscriptionCard(bundle, targetModel)}`
|
|
|
261332
261608
|
addToast(formatSubscriptionToast(bundle, targetModel), "success");
|
|
261333
261609
|
} catch (err) {
|
|
261334
261610
|
const parsed = parseError(err);
|
|
261335
|
-
const errorText = `Subscription verification failed: ${parsed.message}`;
|
|
261611
|
+
const errorText = parsed.message.startsWith("Subscription verification failed") || parsed.message.startsWith("No active GitHub Copilot subscription") ? parsed.message : `Subscription verification failed: ${parsed.message}`;
|
|
261336
261612
|
setAuthError(errorText);
|
|
261337
261613
|
setStaticMessages((prev) => [...prev, ...useCliStore.getState().activeMessages]);
|
|
261338
261614
|
setActiveMessages([
|
|
@@ -261661,6 +261937,7 @@ ${formatSubscriptionCard(bundle, targetModel)}`
|
|
|
261661
261937
|
try {
|
|
261662
261938
|
await agent.loadContext(item.value);
|
|
261663
261939
|
const resumedMessages = convertAgentMessagesToTuiMessages(agent.messages);
|
|
261940
|
+
console.clear();
|
|
261664
261941
|
setStaticMessages([{ id: "header", role: "header" }, ...resumedMessages]);
|
|
261665
261942
|
setStaticKey((k) => k + 1);
|
|
261666
261943
|
setActiveMessages([]);
|
|
@@ -262089,8 +262366,13 @@ function useAgentSession({
|
|
|
262089
262366
|
} catch {}
|
|
262090
262367
|
const nonSystem = (agent.messages || []).filter((m) => m.role !== "system");
|
|
262091
262368
|
if (nonSystem.length > 0) {
|
|
262369
|
+
const currentStatic = useCliStore.getState().staticMessages;
|
|
262370
|
+
if (currentStatic.length > 1) {
|
|
262371
|
+
return;
|
|
262372
|
+
}
|
|
262092
262373
|
const resumed = convertAgentMessagesToTuiMessages(agent.messages);
|
|
262093
262374
|
if (resumed.length > 0) {
|
|
262375
|
+
console.clear();
|
|
262094
262376
|
setStaticMessages([{ id: "header", role: "header" }, ...resumed]);
|
|
262095
262377
|
setStaticKey((k) => k + 1);
|
|
262096
262378
|
}
|
|
@@ -263290,6 +263572,10 @@ ${decStatus}
|
|
|
263290
263572
|
}
|
|
263291
263573
|
return;
|
|
263292
263574
|
}
|
|
263575
|
+
if (text.trim() === "/ask") {
|
|
263576
|
+
addToast("Please enter your question after /ask (e.g. /ask how does auth work?)", "info");
|
|
263577
|
+
return;
|
|
263578
|
+
}
|
|
263293
263579
|
if (text.trim() === "/plan" || text.trim().startsWith("/plan ")) {
|
|
263294
263580
|
const goal = text.trim().slice("/plan".length).trim();
|
|
263295
263581
|
if (!goal) {
|
|
@@ -263567,7 +263853,16 @@ If it doesn't open automatically, please click here:
|
|
|
263567
263853
|
const promptToProcess = currentRawPrompt;
|
|
263568
263854
|
let displayText = promptToProcess;
|
|
263569
263855
|
let executionPrompt = promptToProcess;
|
|
263570
|
-
|
|
263856
|
+
let isAskPrompt = false;
|
|
263857
|
+
if (promptToProcess.trim() === "/ask" || promptToProcess.trim().startsWith("/ask ") || promptToProcess.trim().startsWith("/ask\t")) {
|
|
263858
|
+
const question = promptToProcess.trim().replace(/^\/ask\s*/, "").trim();
|
|
263859
|
+
if (question) {
|
|
263860
|
+
isAskPrompt = true;
|
|
263861
|
+
executionPrompt = getAskPrompt(question);
|
|
263862
|
+
displayText = `/ask ${question}`;
|
|
263863
|
+
}
|
|
263864
|
+
}
|
|
263865
|
+
if (!isAskPrompt && promptToProcess.startsWith("/")) {
|
|
263571
263866
|
const [firstToken, ...restArgs] = promptToProcess.split(/\s+/);
|
|
263572
263867
|
let potentialCmd = firstToken ? firstToken.slice(1).toLowerCase() : "";
|
|
263573
263868
|
const isExplicitSkillPrefix = potentialCmd.startsWith("skill:");
|
|
@@ -263575,6 +263870,7 @@ If it doesn't open automatically, please click here:
|
|
|
263575
263870
|
potentialCmd = potentialCmd.slice("skill:".length);
|
|
263576
263871
|
}
|
|
263577
263872
|
const coreBuiltins = new Set([
|
|
263873
|
+
"ask",
|
|
263578
263874
|
"clear",
|
|
263579
263875
|
"context",
|
|
263580
263876
|
"copy",
|
|
@@ -263638,7 +263934,8 @@ If it doesn't open automatically, please click here:
|
|
|
263638
263934
|
try {
|
|
263639
263935
|
const stream = runAgentLoop(agent, {
|
|
263640
263936
|
content: executionPrompt,
|
|
263641
|
-
displayText
|
|
263937
|
+
displayText,
|
|
263938
|
+
readOnly: isAskPrompt
|
|
263642
263939
|
});
|
|
263643
263940
|
await processAgentStream({
|
|
263644
263941
|
stream,
|
|
@@ -263706,6 +264003,7 @@ If it doesn't open automatically, please click here:
|
|
|
263706
264003
|
setSessionsData,
|
|
263707
264004
|
setSettingsFollowUpMode,
|
|
263708
264005
|
setSettingsNonWorkspace,
|
|
264006
|
+
setSettingsPathGuard,
|
|
263709
264007
|
setSettingsSteeringMode,
|
|
263710
264008
|
setSettingsThinkingLevel,
|
|
263711
264009
|
setSettingsToolPermission,
|
|
@@ -263713,7 +264011,6 @@ If it doesn't open automatically, please click here:
|
|
|
263713
264011
|
setStaticMessages,
|
|
263714
264012
|
setStaticKey,
|
|
263715
264013
|
setOllamaModels,
|
|
263716
|
-
setCurrentPlannedPrompt,
|
|
263717
264014
|
authMethod,
|
|
263718
264015
|
selectedProvider,
|
|
263719
264016
|
setActiveModel,
|
|
@@ -264083,7 +264380,8 @@ function parseCliArgs(args) {
|
|
|
264083
264380
|
"link",
|
|
264084
264381
|
"key",
|
|
264085
264382
|
"resume",
|
|
264086
|
-
"docs"
|
|
264383
|
+
"docs",
|
|
264384
|
+
"ask"
|
|
264087
264385
|
];
|
|
264088
264386
|
let command;
|
|
264089
264387
|
let prompt;
|
|
@@ -264136,6 +264434,7 @@ a coding agent that lives in your terminal.
|
|
|
264136
264434
|
Usage:
|
|
264137
264435
|
december Launch interactive TUI session
|
|
264138
264436
|
december "<prompt>" Execute headless agent task
|
|
264437
|
+
december ask "<question>" Ask a question about the codebase (read-only Q&A mode)
|
|
264139
264438
|
december resume [session-id] Resume the most recent session or specified session ID
|
|
264140
264439
|
december auth [status|import] Inspect active subscriptions and authentication status
|
|
264141
264440
|
december link <provider> Link AI subscription (copilot, claude, chatgpt, gemini)
|
|
@@ -264273,6 +264572,17 @@ ${formattedStdin}`;
|
|
|
264273
264572
|
await handleDocsCommand({ section });
|
|
264274
264573
|
process.exit(0);
|
|
264275
264574
|
}
|
|
264575
|
+
const isAskMode = parsedArgs.command === "ask";
|
|
264576
|
+
if (isAskMode) {
|
|
264577
|
+
const question = parsedArgs.positionals.slice(1).join(" ").trim() || parsedArgs.prompt;
|
|
264578
|
+
if (!question) {
|
|
264579
|
+
console.error("Error: Please provide a question to ask.");
|
|
264580
|
+
console.error(`Usage: december ask "<question>"
|
|
264581
|
+
`);
|
|
264582
|
+
process.exit(1);
|
|
264583
|
+
}
|
|
264584
|
+
parsedArgs.prompt = question;
|
|
264585
|
+
}
|
|
264276
264586
|
if (parsedArgs.prompt) {
|
|
264277
264587
|
const [
|
|
264278
264588
|
{ AgentHarness },
|
|
@@ -264283,7 +264593,8 @@ ${formattedStdin}`;
|
|
|
264283
264593
|
{ runHeadlessTask },
|
|
264284
264594
|
{ localOperations, setActiveScopeDir },
|
|
264285
264595
|
{ instantiateProvider },
|
|
264286
|
-
{ ensureValidModelForProvider }
|
|
264596
|
+
{ ensureValidModelForProvider },
|
|
264597
|
+
{ getAskPrompt }
|
|
264287
264598
|
] = await Promise.all([
|
|
264288
264599
|
Promise.resolve().then(() => (init_src4(), exports_src3)),
|
|
264289
264600
|
Promise.resolve().then(() => (init_src3(), exports_src2)),
|
|
@@ -264293,7 +264604,8 @@ ${formattedStdin}`;
|
|
|
264293
264604
|
Promise.resolve().then(() => (init_headless_runner(), exports_headless_runner)),
|
|
264294
264605
|
Promise.resolve().then(() => (init_local_operations(), exports_local_operations)),
|
|
264295
264606
|
Promise.resolve().then(() => (init_provider_factory(), exports_provider_factory)),
|
|
264296
|
-
Promise.resolve().then(() => (init_models5(), exports_models2))
|
|
264607
|
+
Promise.resolve().then(() => (init_models5(), exports_models2)),
|
|
264608
|
+
Promise.resolve().then(() => exports_prompts)
|
|
264297
264609
|
]);
|
|
264298
264610
|
if (parsedArgs.scope) {
|
|
264299
264611
|
setActiveScopeDir(parsedArgs.scope);
|
|
@@ -264323,22 +264635,31 @@ ${formattedStdin}`;
|
|
|
264323
264635
|
const config = await loadConfig();
|
|
264324
264636
|
const activeProvider = providerConfig?.provider || config.activeProvider || "gemini";
|
|
264325
264637
|
const initialModel = providerConfig?.authMethod === "december" ? "december-auto" : parsedArgs.model || providerConfig?.model || ensureValidModelForProvider(activeProvider, config.activeModel);
|
|
264638
|
+
const effectiveTools = isAskMode ? [
|
|
264639
|
+
ReadFileTool,
|
|
264640
|
+
LsTool,
|
|
264641
|
+
FindFilesTool,
|
|
264642
|
+
GrepSearchTool,
|
|
264643
|
+
AskQuestionTool,
|
|
264644
|
+
BrowserTool,
|
|
264645
|
+
WebSearchTool
|
|
264646
|
+
] : [
|
|
264647
|
+
BashTool,
|
|
264648
|
+
ReadFileTool,
|
|
264649
|
+
WriteFileTool,
|
|
264650
|
+
LsTool,
|
|
264651
|
+
EditFileTool,
|
|
264652
|
+
EditDiffTool,
|
|
264653
|
+
FindFilesTool,
|
|
264654
|
+
GrepSearchTool,
|
|
264655
|
+
AskQuestionTool,
|
|
264656
|
+
ManageTaskTool,
|
|
264657
|
+
BrowserTool,
|
|
264658
|
+
WebSearchTool
|
|
264659
|
+
];
|
|
264326
264660
|
const harness = new AgentHarness({
|
|
264327
264661
|
llm,
|
|
264328
|
-
tools:
|
|
264329
|
-
BashTool,
|
|
264330
|
-
ReadFileTool,
|
|
264331
|
-
WriteFileTool,
|
|
264332
|
-
LsTool,
|
|
264333
|
-
EditFileTool,
|
|
264334
|
-
EditDiffTool,
|
|
264335
|
-
FindFilesTool,
|
|
264336
|
-
GrepSearchTool,
|
|
264337
|
-
AskQuestionTool,
|
|
264338
|
-
ManageTaskTool,
|
|
264339
|
-
BrowserTool,
|
|
264340
|
-
WebSearchTool
|
|
264341
|
-
],
|
|
264662
|
+
tools: effectiveTools,
|
|
264342
264663
|
operations: localOperations,
|
|
264343
264664
|
modelOptions: {
|
|
264344
264665
|
model: initialModel,
|
|
@@ -264355,14 +264676,18 @@ ${formattedStdin}`;
|
|
|
264355
264676
|
const agent = harness.getAgent();
|
|
264356
264677
|
await agent.loadContext();
|
|
264357
264678
|
if (!parsedArgs.json) {
|
|
264358
|
-
console.log(`
|
|
264679
|
+
console.log(isAskMode ? `
|
|
264680
|
+
Executing Ask Q&A: "${parsedArgs.prompt}"
|
|
264681
|
+
` : `
|
|
264359
264682
|
Executing Headless Task: "${parsedArgs.prompt}"
|
|
264360
264683
|
`);
|
|
264361
264684
|
}
|
|
264362
|
-
const
|
|
264685
|
+
const effectivePrompt = isAskMode ? getAskPrompt(parsedArgs.prompt) : parsedArgs.prompt;
|
|
264686
|
+
const result = await runHeadlessTask(effectivePrompt, {
|
|
264363
264687
|
agent,
|
|
264364
264688
|
nonInteractive: parsedArgs.yes,
|
|
264365
|
-
json: parsedArgs.json
|
|
264689
|
+
json: parsedArgs.json,
|
|
264690
|
+
readOnly: isAskMode
|
|
264366
264691
|
});
|
|
264367
264692
|
process.exit(result.success ? 0 : 1);
|
|
264368
264693
|
}
|
|
@@ -264465,7 +264790,19 @@ Executing Headless Task: "${parsedArgs.prompt}"
|
|
|
264465
264790
|
followUpMode: config.followUpMode || "all"
|
|
264466
264791
|
});
|
|
264467
264792
|
const agent = harness.getAgent();
|
|
264468
|
-
|
|
264793
|
+
if (targetSessionId) {
|
|
264794
|
+
await agent.loadContext().catch(() => {});
|
|
264795
|
+
const nonSystem = (agent.messages || []).filter((m) => m.role !== "system");
|
|
264796
|
+
if (nonSystem.length > 0) {
|
|
264797
|
+
await Promise.resolve().then(() => init_use_agent_runner());
|
|
264798
|
+
const resumed = convertAgentMessagesToTuiMessages(agent.messages);
|
|
264799
|
+
if (resumed.length > 0) {
|
|
264800
|
+
useCliStore.getState().setStaticMessages([{ id: "header", role: "header" }, ...resumed]);
|
|
264801
|
+
}
|
|
264802
|
+
}
|
|
264803
|
+
} else {
|
|
264804
|
+
agent.loadContext().catch(() => {});
|
|
264805
|
+
}
|
|
264469
264806
|
function AppWrapper(props) {
|
|
264470
264807
|
const [latestVersion, setLatestVersion] = React.useState(undefined);
|
|
264471
264808
|
React.useEffect(() => {
|