code-ollama 0.24.0 → 0.25.0
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/assets/{tui-DEmaVgHT.js → tui-c76QePyQ.js} +88 -39
- package/dist/cli.js +44 -13
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as LABEL, A as loadConfig, B as CHAT, C as checkHealth, D as pullModel, E as listModels, F as withSystemMessage, G as ASSISTANT, H as SEARCH_SETTINGS, I as HEADER_PREFIX, J as PLAN_GENERATION_INSTRUCTION, K as SYSTEM, L as WARNING, M as removeClipboardImage, N as saveClipboardImage, O as sanitizeAssistantContent, P as resetSystemMessage, Q as AUTO, R as LIST$1, S as TOOL_INTENT_CORRECTION, T as hasUncalledToolIntent, U as SESSION_MANAGER, V as MODEL_MANAGER, W as THEME_SETTINGS, X as BACK, Y as PLAN_INSTRUCTION, Z as CATALOG, _ as loadSession, a as normalizeToolCall, at as VERSION, b as reset, c as WRITE_TOOLS, d as write, et as PLAN, f as appendMessage, g as listSessions, h as deleteSessionIfEmpty, i as formatToolResultContent, it as NAME, j as saveConfig, k as streamChat, l as tick, m as deleteSession, n as executeTool, nt as APPROVE, o as READ_TOOLS, ot as LIST, p as createSession, q as USER, r as executeToolCall, rt as REJECT, s as TOOLS, t as checkForUpdate, tt as SAFE, u as color, v as updateSessionModel, w as deleteModel, x as setClearHandler, y as clear, z as getTheme } from "../cli.js";
|
|
2
2
|
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { basename, extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
@@ -1411,7 +1411,7 @@ function ChatInput({ history: sessionHistory, isDisabled = false, onInterrupt, o
|
|
|
1411
1411
|
}
|
|
1412
1412
|
//#endregion
|
|
1413
1413
|
//#region src/components/Chat/constants.ts
|
|
1414
|
-
var ACTION_NOT_PERFORMED = "The requested action
|
|
1414
|
+
var ACTION_NOT_PERFORMED = "The requested action did not complete successfully";
|
|
1415
1415
|
var PLAN_CHECKLIST_REMINDER = "Then display the plan using either the Plan Needs Input or Proposed Plan Markdown template";
|
|
1416
1416
|
var PLAN_EXECUTION_REMINDER = `Do not claim success and do not call ${Array.from(WRITE_TOOLS).join(", ")} until the user approves execution`;
|
|
1417
1417
|
var ChatActionType = /* @__PURE__ */ function(ChatActionType) {
|
|
@@ -1445,6 +1445,18 @@ function hasExecutablePlan(content) {
|
|
|
1445
1445
|
const nextSectionIndex = lines.findIndex((line, index) => index > executionStepsIndex && /^#{1,6}\s+\S/.test(line.trim()));
|
|
1446
1446
|
return lines.slice(executionStepsIndex + 1, nextSectionIndex === -1 ? void 0 : nextSectionIndex).some((line) => /^(?:[-*]|\d+[.)])\s+\S/.test(line.trim()));
|
|
1447
1447
|
}
|
|
1448
|
+
function isPlanModeFinal(content) {
|
|
1449
|
+
const firstHeading = content.split("\n").find((line) => line.trim())?.trim().toLowerCase();
|
|
1450
|
+
return isPlanNeedsInput(content) || firstHeading === "## proposed plan";
|
|
1451
|
+
}
|
|
1452
|
+
function isPlanNeedsInput(content) {
|
|
1453
|
+
return content.split("\n").find((line) => line.trim())?.trim().toLowerCase() === "## plan needs input";
|
|
1454
|
+
}
|
|
1455
|
+
function isDirectPlanAnswer(content) {
|
|
1456
|
+
const normalized = content.trim();
|
|
1457
|
+
if (!normalized || isPlanModeFinal(normalized)) return false;
|
|
1458
|
+
return !/^(?:research(?: is)? complete|done)\.?$/i.test(normalized);
|
|
1459
|
+
}
|
|
1448
1460
|
//#endregion
|
|
1449
1461
|
//#region src/components/Chat/reducer.ts
|
|
1450
1462
|
function createInitialChatState(messages = []) {
|
|
@@ -1667,7 +1679,9 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1667
1679
|
toolResultMessages.push(buildToolResultMessage(toolCall.function.name, {
|
|
1668
1680
|
content: "",
|
|
1669
1681
|
// v8 ignore next
|
|
1670
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1682
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1683
|
+
// v8 ignore next
|
|
1684
|
+
...error instanceof Error && error.stack ? { stack: error.stack } : {}
|
|
1671
1685
|
}));
|
|
1672
1686
|
}
|
|
1673
1687
|
nextMessages = [...updatedMessages, ...toolResultMessages];
|
|
@@ -1746,7 +1760,7 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1746
1760
|
mode,
|
|
1747
1761
|
theme
|
|
1748
1762
|
]);
|
|
1749
|
-
const processStreamReadOnly = useCallback(async (currentMessages) => {
|
|
1763
|
+
const processStreamReadOnly = useCallback(async (currentMessages, toolIntentCorrections = 0) => {
|
|
1750
1764
|
const modelName = model;
|
|
1751
1765
|
// v8 ignore next
|
|
1752
1766
|
if (!modelName) throw new Error("Model is required");
|
|
@@ -1843,7 +1857,9 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1843
1857
|
/* v8 ignore start */
|
|
1844
1858
|
const toolResultMessage = buildToolResultMessage(toolCall.function.name, {
|
|
1845
1859
|
content: "",
|
|
1846
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1860
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1861
|
+
// v8 ignore next
|
|
1862
|
+
...error instanceof Error && error.stack ? { stack: error.stack } : {}
|
|
1847
1863
|
});
|
|
1848
1864
|
const newMessages = [...updatedMessages, toolResultMessage];
|
|
1849
1865
|
dispatch({
|
|
@@ -1866,6 +1882,13 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1866
1882
|
}
|
|
1867
1883
|
await prewarmCodeBlocks(assistantMessage.content, theme);
|
|
1868
1884
|
const researchMessages = commitAssistantMessage();
|
|
1885
|
+
if (isPlanNeedsInput(assistantMessage.content)) {
|
|
1886
|
+
dispatch({
|
|
1887
|
+
type: ChatActionType.SetLoading,
|
|
1888
|
+
isLoading: false
|
|
1889
|
+
});
|
|
1890
|
+
return;
|
|
1891
|
+
}
|
|
1869
1892
|
if (hasExecutablePlan(assistantMessage.content)) {
|
|
1870
1893
|
dispatch({
|
|
1871
1894
|
type: ChatActionType.RequestPlanReview,
|
|
@@ -1876,6 +1899,32 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1876
1899
|
});
|
|
1877
1900
|
return;
|
|
1878
1901
|
}
|
|
1902
|
+
if (hasUncalledToolIntent(assistantMessage.content) && toolIntentCorrections < MAX_TOOL_INTENT_CORRECTIONS) {
|
|
1903
|
+
const correctedMessages = [...researchMessages, {
|
|
1904
|
+
role: SYSTEM,
|
|
1905
|
+
content: TOOL_INTENT_CORRECTION
|
|
1906
|
+
}];
|
|
1907
|
+
dispatch({
|
|
1908
|
+
type: ChatActionType.CommitMessages,
|
|
1909
|
+
messages: correctedMessages
|
|
1910
|
+
});
|
|
1911
|
+
await processStreamReadOnly(correctedMessages, toolIntentCorrections + 1);
|
|
1912
|
+
return;
|
|
1913
|
+
}
|
|
1914
|
+
if (isPlanModeFinal(assistantMessage.content)) {
|
|
1915
|
+
dispatch({
|
|
1916
|
+
type: ChatActionType.SetLoading,
|
|
1917
|
+
isLoading: false
|
|
1918
|
+
});
|
|
1919
|
+
return;
|
|
1920
|
+
}
|
|
1921
|
+
if (currentMessages.some((message) => !!message.toolResult) && isDirectPlanAnswer(assistantMessage.content)) {
|
|
1922
|
+
dispatch({
|
|
1923
|
+
type: ChatActionType.SetLoading,
|
|
1924
|
+
isLoading: false
|
|
1925
|
+
});
|
|
1926
|
+
return;
|
|
1927
|
+
}
|
|
1879
1928
|
const planInstruction = {
|
|
1880
1929
|
role: SYSTEM,
|
|
1881
1930
|
content: PLAN_GENERATION_INSTRUCTION
|
|
@@ -2003,6 +2052,13 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
2003
2052
|
});
|
|
2004
2053
|
switch (decision) {
|
|
2005
2054
|
case APPROVE: {
|
|
2055
|
+
dispatch({
|
|
2056
|
+
type: ChatActionType.SetStreamingMessage,
|
|
2057
|
+
message: {
|
|
2058
|
+
role: ASSISTANT,
|
|
2059
|
+
content: ""
|
|
2060
|
+
}
|
|
2061
|
+
});
|
|
2006
2062
|
const result = await executeToolCall(toolCall);
|
|
2007
2063
|
const toolResultMessage = buildToolResultMessage(toolCall.function.name, result, toolCall.function.arguments);
|
|
2008
2064
|
const newMessages = [...approvedMessages, toolResultMessage];
|
|
@@ -3199,46 +3255,36 @@ function UpdateBanner({ onLoad, theme }) {
|
|
|
3199
3255
|
});
|
|
3200
3256
|
}
|
|
3201
3257
|
//#endregion
|
|
3202
|
-
//#region src/components/App/constants.ts
|
|
3203
|
-
var Screen = /* @__PURE__ */ function(Screen) {
|
|
3204
|
-
Screen["Chat"] = "chat";
|
|
3205
|
-
Screen["ModelManager"] = "model-manager";
|
|
3206
|
-
Screen["SearchSettings"] = "search-settings";
|
|
3207
|
-
Screen["SessionManager"] = "session-manager";
|
|
3208
|
-
Screen["ThemeSettings"] = "theme-settings";
|
|
3209
|
-
return Screen;
|
|
3210
|
-
}({});
|
|
3211
|
-
//#endregion
|
|
3212
3258
|
//#region src/components/App/hooks/useScreenRouter.ts
|
|
3213
|
-
function useScreenRouter() {
|
|
3259
|
+
function useScreenRouter({ initialScreen } = {}) {
|
|
3214
3260
|
const { exit } = useApp();
|
|
3215
|
-
const [currentScreen, setScreen] = useState(
|
|
3261
|
+
const [currentScreen, setScreen] = useState(initialScreen ?? "chat");
|
|
3216
3262
|
return {
|
|
3217
3263
|
currentScreen,
|
|
3218
3264
|
setScreen,
|
|
3219
3265
|
handleClose: useCallback(() => {
|
|
3220
|
-
setScreen(
|
|
3266
|
+
setScreen(CHAT);
|
|
3221
3267
|
}, []),
|
|
3222
3268
|
handleCommand: useCallback((command, callbacks) => {
|
|
3223
3269
|
const { onCreateSession, onSetPreviewThemeId, model, theme } = callbacks;
|
|
3224
3270
|
switch (command) {
|
|
3225
3271
|
case "/session":
|
|
3226
|
-
setScreen(
|
|
3272
|
+
setScreen(SESSION_MANAGER);
|
|
3227
3273
|
break;
|
|
3228
3274
|
case "/model":
|
|
3229
|
-
setScreen(
|
|
3275
|
+
setScreen(MODEL_MANAGER);
|
|
3230
3276
|
break;
|
|
3231
3277
|
case "/search":
|
|
3232
|
-
setScreen(
|
|
3278
|
+
setScreen(SEARCH_SETTINGS);
|
|
3233
3279
|
break;
|
|
3234
3280
|
case "/theme":
|
|
3235
3281
|
onSetPreviewThemeId(theme);
|
|
3236
|
-
setScreen(
|
|
3282
|
+
setScreen(THEME_SETTINGS);
|
|
3237
3283
|
break;
|
|
3238
3284
|
case "/clear": {
|
|
3239
3285
|
resetSystemMessage();
|
|
3240
3286
|
const nextSession = onCreateSession(model);
|
|
3241
|
-
setScreen(
|
|
3287
|
+
setScreen(CHAT);
|
|
3242
3288
|
clear(nextSession.metadata.id);
|
|
3243
3289
|
break;
|
|
3244
3290
|
}
|
|
@@ -3325,7 +3371,7 @@ function useThemeSettings({ currentTheme, onUpdateConfig, setScreen }) {
|
|
|
3325
3371
|
activeTheme,
|
|
3326
3372
|
handleThemeClose: useCallback(() => {
|
|
3327
3373
|
setPreviewThemeId(null);
|
|
3328
|
-
setScreen(
|
|
3374
|
+
setScreen(CHAT);
|
|
3329
3375
|
}, [setScreen]),
|
|
3330
3376
|
handleThemePreview,
|
|
3331
3377
|
handleThemeSave: useCallback((themeId) => {
|
|
@@ -3417,13 +3463,13 @@ function ReadinessCheck({ errorMessage, onCommand, setupState, theme = getTheme(
|
|
|
3417
3463
|
}
|
|
3418
3464
|
//#endregion
|
|
3419
3465
|
//#region src/components/App/App.tsx
|
|
3420
|
-
function App({ sessionId }) {
|
|
3466
|
+
function App({ sessionId, initialScreen }) {
|
|
3421
3467
|
const [appConfig, setConfig] = useState(() => loadConfig());
|
|
3422
3468
|
const [mode, setMode] = useState(SAFE);
|
|
3423
3469
|
const [isLoaded, setIsLoaded] = useState(false);
|
|
3424
3470
|
const [setupState, setSetupState] = useState(() => appConfig.model ? ReadinessState.Ready : ReadinessState.MissingModelConfig);
|
|
3425
3471
|
const [setupErrorMessage, setSetupErrorMessage] = useState(null);
|
|
3426
|
-
const { currentScreen, setScreen, handleClose, handleCommand } = useScreenRouter();
|
|
3472
|
+
const { currentScreen, setScreen, handleClose, handleCommand } = useScreenRouter({ initialScreen });
|
|
3427
3473
|
const { activeSession, setSession, handleCreateSession, handleOpenSession, handleDeleteSession, handleMessagesChange } = useSessionManager({
|
|
3428
3474
|
sessionId,
|
|
3429
3475
|
model: appConfig.model ?? "",
|
|
@@ -3440,7 +3486,7 @@ function App({ sessionId }) {
|
|
|
3440
3486
|
}
|
|
3441
3487
|
return;
|
|
3442
3488
|
}
|
|
3443
|
-
if (currentScreen !==
|
|
3489
|
+
if (currentScreen !== "chat") return;
|
|
3444
3490
|
// v8 ignore next
|
|
3445
3491
|
if (isMounted) {
|
|
3446
3492
|
setSetupErrorMessage(null);
|
|
@@ -3477,7 +3523,7 @@ function App({ sessionId }) {
|
|
|
3477
3523
|
...current,
|
|
3478
3524
|
metadata: updateSessionModel(current.metadata.id, newModel)
|
|
3479
3525
|
}));
|
|
3480
|
-
setScreen(
|
|
3526
|
+
setScreen(CHAT);
|
|
3481
3527
|
}, [setScreen, setSession]);
|
|
3482
3528
|
const { activeTheme, handleThemeClose, handleThemePreview, handleThemeSave, setPreviewThemeId } = useThemeSettings({
|
|
3483
3529
|
currentTheme: appConfig.theme,
|
|
@@ -3500,7 +3546,7 @@ function App({ sessionId }) {
|
|
|
3500
3546
|
]);
|
|
3501
3547
|
let screenContent;
|
|
3502
3548
|
switch (currentScreen) {
|
|
3503
|
-
case
|
|
3549
|
+
case MODEL_MANAGER:
|
|
3504
3550
|
screenContent = /* @__PURE__ */ jsx(ModelManager, {
|
|
3505
3551
|
currentModel: appConfig.model ?? "",
|
|
3506
3552
|
onSelect: handleUpdateConfig,
|
|
@@ -3508,7 +3554,7 @@ function App({ sessionId }) {
|
|
|
3508
3554
|
theme: activeTheme
|
|
3509
3555
|
});
|
|
3510
3556
|
break;
|
|
3511
|
-
case
|
|
3557
|
+
case SEARCH_SETTINGS:
|
|
3512
3558
|
screenContent = /* @__PURE__ */ jsx(SearchSettings, {
|
|
3513
3559
|
currentUrl: appConfig.searxngBaseUrl,
|
|
3514
3560
|
onSave: handleUpdateConfig,
|
|
@@ -3516,26 +3562,26 @@ function App({ sessionId }) {
|
|
|
3516
3562
|
theme: activeTheme
|
|
3517
3563
|
});
|
|
3518
3564
|
break;
|
|
3519
|
-
case
|
|
3565
|
+
case SESSION_MANAGER:
|
|
3520
3566
|
screenContent = /* @__PURE__ */ jsx(SessionManager, {
|
|
3521
3567
|
currentSessionId: activeSession.metadata.id,
|
|
3522
3568
|
onClose: handleClose,
|
|
3523
3569
|
onDelete: (sessionId) => {
|
|
3524
3570
|
handleDeleteSession(sessionId);
|
|
3525
|
-
setScreen(
|
|
3571
|
+
setScreen(SESSION_MANAGER);
|
|
3526
3572
|
},
|
|
3527
3573
|
onNew: () => {
|
|
3528
3574
|
handleCreateSession();
|
|
3529
|
-
setScreen(
|
|
3575
|
+
setScreen(CHAT);
|
|
3530
3576
|
},
|
|
3531
3577
|
onOpen: (sessionId) => {
|
|
3532
3578
|
handleOpenSession(sessionId);
|
|
3533
|
-
setScreen(
|
|
3579
|
+
setScreen(CHAT);
|
|
3534
3580
|
},
|
|
3535
3581
|
theme: activeTheme
|
|
3536
3582
|
});
|
|
3537
3583
|
break;
|
|
3538
|
-
case
|
|
3584
|
+
case THEME_SETTINGS:
|
|
3539
3585
|
screenContent = /* @__PURE__ */ jsx(ThemeSettings, {
|
|
3540
3586
|
currentTheme: appConfig.theme,
|
|
3541
3587
|
onClose: handleThemeClose,
|
|
@@ -3543,7 +3589,7 @@ function App({ sessionId }) {
|
|
|
3543
3589
|
onSave: handleThemeSave
|
|
3544
3590
|
});
|
|
3545
3591
|
break;
|
|
3546
|
-
case
|
|
3592
|
+
case CHAT:
|
|
3547
3593
|
screenContent = setupState === ReadinessState.Ready ? /* @__PURE__ */ jsx(Chat, {
|
|
3548
3594
|
initialMessages: activeSession.messages,
|
|
3549
3595
|
model: appConfig.model,
|
|
@@ -3631,15 +3677,18 @@ function ExitHint({ action = "go back" }) {
|
|
|
3631
3677
|
}
|
|
3632
3678
|
//#endregion
|
|
3633
3679
|
//#region src/tui.tsx
|
|
3634
|
-
function renderApp(
|
|
3680
|
+
function renderApp(options = {}) {
|
|
3635
3681
|
let resetKey = 0;
|
|
3636
|
-
const app = render(/* @__PURE__ */ jsx(App, {
|
|
3682
|
+
const app = render(/* @__PURE__ */ jsx(App, {
|
|
3683
|
+
sessionId: options.sessionId,
|
|
3684
|
+
initialScreen: options.initialScreen
|
|
3685
|
+
}, resetKey), {
|
|
3637
3686
|
exitOnCtrlC: false,
|
|
3638
3687
|
maxFps: 60
|
|
3639
3688
|
});
|
|
3640
3689
|
setClearHandler((nextSessionId) => {
|
|
3641
3690
|
reset();
|
|
3642
|
-
app.rerender(/* @__PURE__ */ jsx(App, { sessionId: nextSessionId ?? sessionId }, ++resetKey));
|
|
3691
|
+
app.rerender(/* @__PURE__ */ jsx(App, { sessionId: nextSessionId ?? options.sessionId }, ++resetKey));
|
|
3643
3692
|
});
|
|
3644
3693
|
}
|
|
3645
3694
|
//#endregion
|
package/dist/cli.js
CHANGED
|
@@ -50,7 +50,7 @@ var LIST$1 = [
|
|
|
50
50
|
//#endregion
|
|
51
51
|
//#region package.json
|
|
52
52
|
var name = "code-ollama";
|
|
53
|
-
var version = "0.
|
|
53
|
+
var version = "0.25.0";
|
|
54
54
|
//#endregion
|
|
55
55
|
//#region src/constants/package.ts
|
|
56
56
|
var NAME = name;
|
|
@@ -230,10 +230,18 @@ Use the exact headings shown below
|
|
|
230
230
|
${PLAN_RESPONSE_TEMPLATE}`;
|
|
231
231
|
var PLAN_INSTRUCTION = `Plan mode is active
|
|
232
232
|
|
|
233
|
+
Explore first:
|
|
234
|
+
- If the user provides an exact file path, inspect it with read_file before planning changes
|
|
235
|
+
- If the user asks "where", names an identifier/symbol, or asks where behavior is implemented, search the codebase with grep_search before answering
|
|
236
|
+
- If the user asks about project structure without a target identifier or path, use list_dir or find_files to locate likely files
|
|
237
|
+
- Prefer targeted grep_search for exact names over broad directory listing when the user provides an identifier
|
|
238
|
+
- After each read-only tool result, decide whether another read-only tool would materially improve the answer
|
|
239
|
+
- Do not produce Plan Needs Input while also saying you will use another read-only tool; call that tool instead
|
|
240
|
+
|
|
233
241
|
Only use read-only tools: ${PLAN_READ_TOOLS}
|
|
234
242
|
Do not call ${PLAN_WRITE_TOOLS} during Plan mode
|
|
235
243
|
Use read-only tools to resolve discoverable facts before asking questions
|
|
236
|
-
If the user asks to search, inspect, find, read, or
|
|
244
|
+
If the user asks to search, inspect, find, read, locate, change, adjust, update, edit, configure, or identify something, use read-only tools immediately
|
|
237
245
|
Only ask questions for user preferences or product decisions that cannot be discovered from available tools
|
|
238
246
|
When enough context is available, stop calling tools and produce either Plan Needs Input or Proposed Plan using the required template
|
|
239
247
|
|
|
@@ -244,6 +252,13 @@ var USER = "user";
|
|
|
244
252
|
var ASSISTANT = "assistant";
|
|
245
253
|
var SYSTEM = "system";
|
|
246
254
|
//#endregion
|
|
255
|
+
//#region src/constants/screen.ts
|
|
256
|
+
var CHAT = "chat";
|
|
257
|
+
var MODEL_MANAGER = "model-manager";
|
|
258
|
+
var SEARCH_SETTINGS = "search-settings";
|
|
259
|
+
var SESSION_MANAGER = "session-manager";
|
|
260
|
+
var THEME_SETTINGS = "theme-settings";
|
|
261
|
+
//#endregion
|
|
247
262
|
//#region src/constants/theme.ts
|
|
248
263
|
var DEFAULT_THEME_ID = "github-dark";
|
|
249
264
|
var LIST = [
|
|
@@ -956,6 +971,11 @@ var SHELL_EXEC_OPTIONS = {
|
|
|
956
971
|
timeout: 3e4,
|
|
957
972
|
maxBuffer: 1024 * 1024
|
|
958
973
|
};
|
|
974
|
+
function getErrorOutput(error) {
|
|
975
|
+
if (typeof error !== "object" || error === null) return "";
|
|
976
|
+
const output = error;
|
|
977
|
+
return [output.stdout, output.stderr].filter((value) => typeof value === "string" && !!value).join("\n");
|
|
978
|
+
}
|
|
959
979
|
/**
|
|
960
980
|
* Execute shell command with shared options (throws on error)
|
|
961
981
|
*/
|
|
@@ -970,9 +990,12 @@ async function runShell(command) {
|
|
|
970
990
|
const { stdout, stderr } = await execShell(command);
|
|
971
991
|
return { content: stdout || stderr };
|
|
972
992
|
} catch (error) {
|
|
993
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
973
994
|
return {
|
|
974
|
-
content:
|
|
975
|
-
error: `Command failed: ${
|
|
995
|
+
content: getErrorOutput(error),
|
|
996
|
+
error: `Command failed: ${message}`,
|
|
997
|
+
// v8 ignore next
|
|
998
|
+
...error instanceof Error && error.stack ? { stack: error.stack } : {}
|
|
976
999
|
};
|
|
977
1000
|
}
|
|
978
1001
|
}
|
|
@@ -1617,14 +1640,16 @@ function normalizeToolCall(toolCall) {
|
|
|
1617
1640
|
}
|
|
1618
1641
|
function formatToolResultContent(toolName, result, args) {
|
|
1619
1642
|
const formattedArgs = args ? `(${formatToolArguments(args)})` : "";
|
|
1620
|
-
const status = result.error ? "The requested action
|
|
1643
|
+
const status = result.error ? "The requested action did not complete successfully" : "";
|
|
1621
1644
|
const content = result.content ? `\n${result.content}` : "";
|
|
1622
1645
|
const error = result.error ? `\nError: ${result.error}` : "";
|
|
1646
|
+
const stack = result.error && result.stack ? `\nStack trace:\n${result.stack}` : "";
|
|
1623
1647
|
return [
|
|
1624
1648
|
`Tool ${toolName}${formattedArgs} result:`,
|
|
1625
1649
|
status,
|
|
1626
1650
|
content.trim(),
|
|
1627
|
-
error.trim()
|
|
1651
|
+
error.trim(),
|
|
1652
|
+
stack.trim()
|
|
1628
1653
|
].filter(Boolean).join("\n");
|
|
1629
1654
|
}
|
|
1630
1655
|
function formatToolArguments(args) {
|
|
@@ -1642,7 +1667,9 @@ async function executeToolCall(toolCall, options) {
|
|
|
1642
1667
|
return {
|
|
1643
1668
|
content: "",
|
|
1644
1669
|
// v8 ignore next
|
|
1645
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1670
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1671
|
+
// v8 ignore next
|
|
1672
|
+
...error instanceof Error && error.stack ? { stack: error.stack } : {}
|
|
1646
1673
|
};
|
|
1647
1674
|
}
|
|
1648
1675
|
}
|
|
@@ -1736,15 +1763,19 @@ cli.command("run <model> <prompt>", "Run a one-off prompt").action(async (model,
|
|
|
1736
1763
|
process.exitCode = 1;
|
|
1737
1764
|
}
|
|
1738
1765
|
});
|
|
1739
|
-
cli.command("resume
|
|
1766
|
+
cli.command("resume [sessionId]", "Resume a saved session").action(async (sessionId) => {
|
|
1740
1767
|
try {
|
|
1768
|
+
if (!sessionId) {
|
|
1769
|
+
await launchTui({ initialScreen: SESSION_MANAGER });
|
|
1770
|
+
return;
|
|
1771
|
+
}
|
|
1741
1772
|
const loaded = loadSession(sessionId);
|
|
1742
1773
|
if (loaded.metadata.directory && loaded.metadata.directory !== process.cwd()) {
|
|
1743
1774
|
writeError(color(`${WARNING} Cannot resume: session belongs to ${loaded.metadata.directory}\n`, "yellow"));
|
|
1744
1775
|
process.exitCode = 1;
|
|
1745
1776
|
return;
|
|
1746
1777
|
}
|
|
1747
|
-
await launchTui(sessionId);
|
|
1778
|
+
await launchTui({ sessionId });
|
|
1748
1779
|
} catch (error) {
|
|
1749
1780
|
writeError(`Error: ${error instanceof Error ? error.message : "Unknown error"}\n`);
|
|
1750
1781
|
process.exitCode = 1;
|
|
@@ -1819,10 +1850,10 @@ async function main(args = process.argv.slice(2)) {
|
|
|
1819
1850
|
]);
|
|
1820
1851
|
else await launchTui();
|
|
1821
1852
|
}
|
|
1822
|
-
async function launchTui(
|
|
1823
|
-
const { renderApp } = await import("./assets/tui-
|
|
1853
|
+
async function launchTui(options = {}) {
|
|
1854
|
+
const { renderApp } = await import("./assets/tui-c76QePyQ.js");
|
|
1824
1855
|
reset();
|
|
1825
|
-
renderApp(
|
|
1856
|
+
renderApp(options);
|
|
1826
1857
|
}
|
|
1827
1858
|
// v8 ignore start
|
|
1828
1859
|
function isEntrypoint(argv1 = process.argv[1]) {
|
|
@@ -1836,4 +1867,4 @@ function isEntrypoint(argv1 = process.argv[1]) {
|
|
|
1836
1867
|
if (isEntrypoint()) main();
|
|
1837
1868
|
// v8 ignore stop
|
|
1838
1869
|
//#endregion
|
|
1839
|
-
export {
|
|
1870
|
+
export { LABEL as $, loadConfig as A, CHAT as B, checkHealth as C, pullModel as D, listModels as E, withSystemMessage as F, ASSISTANT as G, SEARCH_SETTINGS as H, HEADER_PREFIX as I, PLAN_GENERATION_INSTRUCTION as J, SYSTEM as K, WARNING as L, removeClipboardImage as M, saveClipboardImage as N, sanitizeAssistantContent as O, resetSystemMessage as P, AUTO as Q, LIST as R, TOOL_INTENT_CORRECTION as S, hasUncalledToolIntent as T, SESSION_MANAGER as U, MODEL_MANAGER as V, THEME_SETTINGS as W, BACK as X, PLAN_INSTRUCTION as Y, CATALOG as Z, loadSession as _, normalizeToolCall as a, VERSION as at, reset as b, WRITE_TOOLS as c, write as d, PLAN as et, appendMessage as f, listSessions as g, deleteSessionIfEmpty as h, formatToolResultContent as i, NAME as it, saveConfig as j, streamChat as k, tick as l, deleteSession as m, main, executeTool as n, APPROVE as nt, READ_TOOLS as o, LIST$1 as ot, createSession as p, USER as q, executeToolCall as r, REJECT as rt, TOOLS as s, checkForUpdate as t, SAFE as tt, color as u, updateSessionModel as v, deleteModel as w, setClearHandler as x, clear as y, getTheme as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "code-ollama",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Ollama coding agent that runs in your terminal",
|
|
5
5
|
"author": "Mark <mark@remarkablemark.org> (https://remarkablemark.org)",
|
|
6
6
|
"type": "module",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"prepublishOnly": "npm run build && npm run lint && npm run lint:tsc && npm run test:ci",
|
|
21
21
|
"test": "vitest run",
|
|
22
22
|
"test:ci": "CI=true npm test -- --color --coverage",
|
|
23
|
-
"test:watch": "vitest
|
|
23
|
+
"test:watch": "vitest"
|
|
24
24
|
},
|
|
25
25
|
"repository": {
|
|
26
26
|
"type": "git",
|