open-research 1.0.1 → 1.1.1
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/cli.js
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
loadOpenResearchConfig,
|
|
27
27
|
saveOpenResearchConfig,
|
|
28
28
|
themeValues
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-TJA4CAZE.js";
|
|
30
30
|
import {
|
|
31
31
|
readJsonFile,
|
|
32
32
|
writeJsonFile
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
} from "./chunk-3RG5ZIWI.js";
|
|
50
50
|
|
|
51
51
|
// src/cli.ts
|
|
52
|
-
import
|
|
52
|
+
import React7 from "react";
|
|
53
53
|
import path19 from "path";
|
|
54
54
|
import { Command } from "commander";
|
|
55
55
|
import { render } from "ink";
|
|
@@ -470,7 +470,6 @@ async function loginWithBrowser(options) {
|
|
|
470
470
|
// src/lib/llm/config.ts
|
|
471
471
|
var OPENAI_AUTH_ONLY = process.env.OPENAI_AUTH_ONLY !== "false";
|
|
472
472
|
var CODEX_RESPONSES_URL = process.env.CODEX_RESPONSES_URL ?? "https://chatgpt.com/backend-api/codex/responses";
|
|
473
|
-
var OPENAI_VALIDATION_STALE_MS = 15 * 60 * 1e3;
|
|
474
473
|
|
|
475
474
|
// src/lib/llm/openai-connection.ts
|
|
476
475
|
var VALIDATION_INSTRUCTIONS = "You are validating whether this OpenAI Codex connection can execute a minimal request. Reply with the single word ok.";
|
|
@@ -829,25 +828,25 @@ function formatDateTime(value) {
|
|
|
829
828
|
}
|
|
830
829
|
|
|
831
830
|
// src/lib/cli/version.ts
|
|
832
|
-
var PACKAGE_VERSION = "1.
|
|
831
|
+
var PACKAGE_VERSION = "1.1.1";
|
|
833
832
|
function getPackageVersion() {
|
|
834
833
|
return PACKAGE_VERSION;
|
|
835
834
|
}
|
|
836
835
|
|
|
837
836
|
// src/tui/app.tsx
|
|
838
837
|
import path18 from "path";
|
|
839
|
-
import {
|
|
838
|
+
import React6, {
|
|
840
839
|
startTransition as startTransition2,
|
|
841
840
|
useDeferredValue,
|
|
842
841
|
useEffect as useEffect4,
|
|
843
|
-
useMemo as
|
|
842
|
+
useMemo as useMemo4,
|
|
844
843
|
useRef as useRef2,
|
|
845
|
-
useState as
|
|
844
|
+
useState as useState7
|
|
846
845
|
} from "react";
|
|
847
|
-
import { Box as Box5, Static, Text as Text5, useApp, useInput as
|
|
846
|
+
import { Box as Box5, Static, Text as Text5, useApp, useInput as useInput5 } from "ink";
|
|
848
847
|
|
|
849
848
|
// src/tui/text-input.tsx
|
|
850
|
-
import { useState, useEffect, useRef } from "react";
|
|
849
|
+
import { useState, useEffect, useLayoutEffect, useRef } from "react";
|
|
851
850
|
import { Box, Text, useInput, useStdout, measureElement } from "ink";
|
|
852
851
|
|
|
853
852
|
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
@@ -1995,30 +1994,37 @@ function TextInput({
|
|
|
1995
1994
|
pasteMapRef.current.clear();
|
|
1996
1995
|
}
|
|
1997
1996
|
}, [originalValue]);
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
if (
|
|
2002
|
-
|
|
2003
|
-
}
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
}
|
|
2011
|
-
});
|
|
1997
|
+
useLayoutEffect(() => {
|
|
1998
|
+
setInputWidth((current) => {
|
|
1999
|
+
const fallbackWidth = typeof stdout.columns === "number" && stdout.columns > 0 ? stdout.columns : current;
|
|
2000
|
+
if (!containerRef.current) {
|
|
2001
|
+
return fallbackWidth > 0 && fallbackWidth !== current ? fallbackWidth : current;
|
|
2002
|
+
}
|
|
2003
|
+
const measuredWidth = measureElement(containerRef.current).width;
|
|
2004
|
+
const nextWidth = measuredWidth > 0 ? measuredWidth : fallbackWidth;
|
|
2005
|
+
if (nextWidth > 0 && nextWidth !== current) {
|
|
2006
|
+
return nextWidth;
|
|
2007
|
+
}
|
|
2008
|
+
return current;
|
|
2009
|
+
});
|
|
2010
|
+
}, [stdout.columns]);
|
|
2012
2011
|
function pasteBadge(entry) {
|
|
2013
2012
|
return applyThemeColor(source_default.dim, accentColor, `[Pasted text #${entry.id} +${entry.lineCount} lines]`);
|
|
2014
2013
|
}
|
|
2015
|
-
function
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2014
|
+
function getSlashCommandRange() {
|
|
2015
|
+
let slashIdx = originalValue.lastIndexOf("/");
|
|
2016
|
+
while (slashIdx > 0 && originalValue[slashIdx - 1] !== " ") {
|
|
2017
|
+
slashIdx = originalValue.lastIndexOf("/", slashIdx - 1);
|
|
2018
|
+
}
|
|
2019
|
+
if (slashIdx === -1) return { start: 0, end: 0 };
|
|
2020
|
+
const afterSlash = originalValue.indexOf(" ", slashIdx);
|
|
2021
|
+
const end = afterSlash === -1 ? originalValue.length : afterSlash;
|
|
2022
|
+
return { start: slashIdx, end };
|
|
2019
2023
|
}
|
|
2020
2024
|
function buildRendered() {
|
|
2021
|
-
const
|
|
2025
|
+
const cmdRange = getSlashCommandRange();
|
|
2026
|
+
const hasCmd = cmdRange.end > cmdRange.start;
|
|
2027
|
+
const inCmd = (idx) => hasCmd && idx >= cmdRange.start && idx < cmdRange.end;
|
|
2022
2028
|
if (showCursor && focus) {
|
|
2023
2029
|
if (originalValue.length === 0) return source_default.inverse(" ");
|
|
2024
2030
|
const pasteIds2 = [...pasteMapRef.current.keys()].sort((a, b) => a - b);
|
|
@@ -2037,12 +2043,12 @@ function TextInput({
|
|
|
2037
2043
|
} else if (i2 === cursorOffset) {
|
|
2038
2044
|
if (char === "\n") {
|
|
2039
2045
|
result2 += source_default.inverse(" ") + "\n";
|
|
2040
|
-
} else if (
|
|
2046
|
+
} else if (inCmd(i2)) {
|
|
2041
2047
|
result2 += applyThemeColor(source_default.inverse, accentColor, char);
|
|
2042
2048
|
} else {
|
|
2043
2049
|
result2 += source_default.inverse(char);
|
|
2044
2050
|
}
|
|
2045
|
-
} else if (
|
|
2051
|
+
} else if (inCmd(i2)) {
|
|
2046
2052
|
result2 += applyThemeColor(source_default, accentColor, char);
|
|
2047
2053
|
} else {
|
|
2048
2054
|
result2 += char;
|
|
@@ -2063,7 +2069,7 @@ function TextInput({
|
|
|
2063
2069
|
const entry = pasteIdx < pasteIds.length ? pasteMapRef.current.get(pasteIds[pasteIdx]) : void 0;
|
|
2064
2070
|
pasteIdx++;
|
|
2065
2071
|
result += entry ? pasteBadge(entry) : "";
|
|
2066
|
-
} else if (
|
|
2072
|
+
} else if (inCmd(i)) {
|
|
2067
2073
|
result += applyThemeColor(source_default, accentColor, char);
|
|
2068
2074
|
} else {
|
|
2069
2075
|
result += char;
|
|
@@ -2374,12 +2380,7 @@ var OPENAI_MODEL_MAP = {
|
|
|
2374
2380
|
"gpt-5.4": "gpt-5.4",
|
|
2375
2381
|
"gpt-5.4-mini": "gpt-5.4-mini",
|
|
2376
2382
|
"openai/gpt-5.4": "gpt-5.4",
|
|
2377
|
-
"openai/gpt-5.4-mini": "gpt-5.4-mini"
|
|
2378
|
-
"google/gemini-3-flash-preview": "gpt-5.4",
|
|
2379
|
-
"google/gemini-3.1-pro": "gpt-5.4",
|
|
2380
|
-
"google/gemini-3.1-flash-lite-preview": "gpt-5.4-mini",
|
|
2381
|
-
"google/gemini-2.5-flash-lite": "gpt-5.4-mini",
|
|
2382
|
-
"google/gemini-2.5-flash": "gpt-5.4-mini"
|
|
2383
|
+
"openai/gpt-5.4-mini": "gpt-5.4-mini"
|
|
2383
2384
|
};
|
|
2384
2385
|
function resolveOpenAIModel(model) {
|
|
2385
2386
|
return OPENAI_MODEL_MAP[model ?? "gpt-5.4"] ?? "gpt-5.4";
|
|
@@ -3650,14 +3651,24 @@ var TOOL_SCHEMAS = [
|
|
|
3650
3651
|
type: "function",
|
|
3651
3652
|
function: {
|
|
3652
3653
|
name: "write_new_file",
|
|
3653
|
-
description:
|
|
3654
|
+
description: [
|
|
3655
|
+
"Create a new workspace file. The key determines where the file is placed:",
|
|
3656
|
+
"- `note:<descriptive-slug>` \u2192 notes/<slug>.md \u2014 analysis, summaries, briefs, memos",
|
|
3657
|
+
"- `paper:<descriptive-slug>` \u2192 papers/<slug>.tex \u2014 LaTeX drafts and manuscripts",
|
|
3658
|
+
"- `experiment:<descriptive-slug>` \u2192 experiments/<slug>.json \u2014 experiment configs and results",
|
|
3659
|
+
"- `source:<descriptive-slug>` \u2192 sources/<slug>.md \u2014 extracted source material",
|
|
3660
|
+
"- `path:<relative/path.ext>` \u2192 exact path \u2014 scripts, configs, data files, any custom location",
|
|
3661
|
+
"Use path: for code files (e.g. `path:scripts/analyze.py`, `path:data/results.csv`).",
|
|
3662
|
+
"Use descriptive slugs, not UUIDs: `note:transformer-scaling-laws` not `note:abc123`.",
|
|
3663
|
+
'Use the folder param to organize within managed directories (e.g. folder: "lit-review").'
|
|
3664
|
+
].join(" "),
|
|
3654
3665
|
parameters: {
|
|
3655
3666
|
type: "object",
|
|
3656
3667
|
properties: {
|
|
3657
|
-
key: { type: "string" },
|
|
3658
|
-
label: { type: "string" },
|
|
3668
|
+
key: { type: "string", description: "File key with prefix determining placement: note:<slug>, paper:<slug>, experiment:<slug>, source:<slug>, or path:<relative/path>" },
|
|
3669
|
+
label: { type: "string", description: "Human-readable display name for the file" },
|
|
3659
3670
|
content: { type: "string" },
|
|
3660
|
-
folder: { type: "string" }
|
|
3671
|
+
folder: { type: "string", description: "Optional subfolder within the managed directory for organization" }
|
|
3661
3672
|
},
|
|
3662
3673
|
required: ["key", "label", "content"],
|
|
3663
3674
|
additionalProperties: false
|
|
@@ -3808,32 +3819,56 @@ var TOOL_SCHEMAS = [
|
|
|
3808
3819
|
type: "function",
|
|
3809
3820
|
function: {
|
|
3810
3821
|
name: "ask_user",
|
|
3811
|
-
description: "Ask the user
|
|
3822
|
+
description: "Ask the user one or more questions and wait for their responses. Use when you need clarification, a decision, or confirmation before proceeding. You can batch up to 4 related questions in a single call \u2014 the user answers them all at once. Provide predefined options when possible. The user can arrow-key select or type a custom answer.",
|
|
3812
3823
|
parameters: {
|
|
3813
3824
|
type: "object",
|
|
3814
3825
|
properties: {
|
|
3826
|
+
questions: {
|
|
3827
|
+
type: "array",
|
|
3828
|
+
minItems: 1,
|
|
3829
|
+
maxItems: 4,
|
|
3830
|
+
items: {
|
|
3831
|
+
type: "object",
|
|
3832
|
+
properties: {
|
|
3833
|
+
question: {
|
|
3834
|
+
type: "string",
|
|
3835
|
+
description: "Clear, specific question. State what you need to know and why."
|
|
3836
|
+
},
|
|
3837
|
+
options: {
|
|
3838
|
+
type: "array",
|
|
3839
|
+
items: {
|
|
3840
|
+
type: "object",
|
|
3841
|
+
properties: {
|
|
3842
|
+
label: { type: "string", description: "Short option label (1-5 words)" },
|
|
3843
|
+
description: { type: "string", description: "One-sentence explanation of what this choice means" }
|
|
3844
|
+
},
|
|
3845
|
+
required: ["label", "description"]
|
|
3846
|
+
},
|
|
3847
|
+
description: "Predefined options. Include 2-5 choices. The user can also type a custom answer."
|
|
3848
|
+
}
|
|
3849
|
+
},
|
|
3850
|
+
required: ["question"]
|
|
3851
|
+
},
|
|
3852
|
+
description: "One or more questions to ask. Batch related questions together (max 4)."
|
|
3853
|
+
},
|
|
3854
|
+
// Legacy single-question support (backward compat)
|
|
3815
3855
|
question: {
|
|
3816
3856
|
type: "string",
|
|
3817
|
-
description: "
|
|
3857
|
+
description: "Single question (shorthand). Use 'questions' array for multiple."
|
|
3818
3858
|
},
|
|
3819
3859
|
options: {
|
|
3820
3860
|
type: "array",
|
|
3821
3861
|
items: {
|
|
3822
3862
|
type: "object",
|
|
3823
3863
|
properties: {
|
|
3824
|
-
label: { type: "string"
|
|
3825
|
-
description: { type: "string"
|
|
3864
|
+
label: { type: "string" },
|
|
3865
|
+
description: { type: "string" }
|
|
3826
3866
|
},
|
|
3827
3867
|
required: ["label", "description"]
|
|
3828
3868
|
},
|
|
3829
|
-
description: "
|
|
3830
|
-
},
|
|
3831
|
-
allow_custom: {
|
|
3832
|
-
type: "boolean",
|
|
3833
|
-
description: "Whether the user can type a custom answer. Default: true."
|
|
3869
|
+
description: "Options for single question (shorthand)."
|
|
3834
3870
|
}
|
|
3835
3871
|
},
|
|
3836
|
-
required: ["question"],
|
|
3837
3872
|
additionalProperties: false
|
|
3838
3873
|
}
|
|
3839
3874
|
}
|
|
@@ -4547,36 +4582,52 @@ function clearPendingQuestion() {
|
|
|
4547
4582
|
function resetPendingQuestions() {
|
|
4548
4583
|
pendingQuestions = [];
|
|
4549
4584
|
}
|
|
4585
|
+
function normalizeQuestions(args) {
|
|
4586
|
+
if (args.questions && args.questions.length > 0) {
|
|
4587
|
+
return args.questions.slice(0, 4);
|
|
4588
|
+
}
|
|
4589
|
+
if (args.question) {
|
|
4590
|
+
return [{ question: args.question, options: args.options }];
|
|
4591
|
+
}
|
|
4592
|
+
return [];
|
|
4593
|
+
}
|
|
4550
4594
|
async function executeAskUser(args, signal) {
|
|
4551
|
-
const
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4595
|
+
const items = normalizeQuestions(args);
|
|
4596
|
+
if (items.length === 0) {
|
|
4597
|
+
return "Error: no question provided.";
|
|
4598
|
+
}
|
|
4599
|
+
const answers = [];
|
|
4600
|
+
for (const item of items) {
|
|
4601
|
+
const questionId = crypto.randomUUID();
|
|
4602
|
+
const question = {
|
|
4603
|
+
id: questionId,
|
|
4604
|
+
question: item.question,
|
|
4605
|
+
options: (item.options ?? []).map((o) => ({
|
|
4606
|
+
label: o.label,
|
|
4607
|
+
description: o.description
|
|
4608
|
+
})),
|
|
4609
|
+
allowCustom: true
|
|
4610
|
+
};
|
|
4611
|
+
const answer = await new Promise((resolve, reject) => {
|
|
4612
|
+
pendingQuestions.push({ question, resolve });
|
|
4613
|
+
if (signal) {
|
|
4614
|
+
const onAbort = () => {
|
|
4615
|
+
pendingQuestions = pendingQuestions.filter((q) => q.question.id !== questionId);
|
|
4616
|
+
reject(new Error("Question cancelled \u2014 user interrupted."));
|
|
4617
|
+
};
|
|
4618
|
+
if (signal.aborted) {
|
|
4619
|
+
onAbort();
|
|
4620
|
+
return;
|
|
4621
|
+
}
|
|
4622
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
4571
4623
|
}
|
|
4572
|
-
|
|
4573
|
-
}
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
return `User answered: "${answer.answer}"`;
|
|
4624
|
+
});
|
|
4625
|
+
const prefix = items.length > 1 ? `Q${answers.length + 1}: "${item.question}" \u2192 ` : "";
|
|
4626
|
+
answers.push(
|
|
4627
|
+
answer.isCustom ? `${prefix}User answered: "${answer.answer}"` : `${prefix}User selected: "${answer.answer}"`
|
|
4628
|
+
);
|
|
4578
4629
|
}
|
|
4579
|
-
return
|
|
4630
|
+
return answers.join("\n");
|
|
4580
4631
|
}
|
|
4581
4632
|
|
|
4582
4633
|
// src/lib/agent/tools/search-workspace.ts
|
|
@@ -4673,8 +4724,15 @@ function normalizeDbBackedKey(key) {
|
|
|
4673
4724
|
}
|
|
4674
4725
|
return `${prefix}:${crypto.randomUUID()}`;
|
|
4675
4726
|
}
|
|
4727
|
+
var VALID_PREFIXES = ["note:", "paper:", "experiment:", "source:", "path:"];
|
|
4676
4728
|
function executeWriteNewFile(args, ctx) {
|
|
4677
4729
|
const normalizedKey = normalizeDbBackedKey(args.key);
|
|
4730
|
+
if (!VALID_PREFIXES.some((p) => normalizedKey.startsWith(p))) {
|
|
4731
|
+
return {
|
|
4732
|
+
result: `Error: Key "${normalizedKey}" is missing a required prefix. Use one of: note:<slug>, paper:<slug>, experiment:<slug>, source:<slug>, or path:<relative/path>. Example: note:${normalizedKey}`,
|
|
4733
|
+
update: null
|
|
4734
|
+
};
|
|
4735
|
+
}
|
|
4678
4736
|
if (normalizedKey in ctx.workspaceFiles) {
|
|
4679
4737
|
return {
|
|
4680
4738
|
result: `Error: File "${normalizedKey}" already exists. Use update_existing_file to modify it.`,
|
|
@@ -4705,6 +4763,7 @@ function executeUpdateExistingFile(args, ctx) {
|
|
|
4705
4763
|
};
|
|
4706
4764
|
}
|
|
4707
4765
|
const mode = args.mode ?? "rewrite";
|
|
4766
|
+
const oldContent = ctx.workspaceFiles[args.key];
|
|
4708
4767
|
if (mode === "rewrite") {
|
|
4709
4768
|
const content = args.content;
|
|
4710
4769
|
if (content == null) {
|
|
@@ -4718,6 +4777,7 @@ function executeUpdateExistingFile(args, ctx) {
|
|
|
4718
4777
|
type: "edit",
|
|
4719
4778
|
key: args.key,
|
|
4720
4779
|
content,
|
|
4780
|
+
oldContent,
|
|
4721
4781
|
summary: args.summary
|
|
4722
4782
|
};
|
|
4723
4783
|
return {
|
|
@@ -4781,6 +4841,7 @@ ${preview}`,
|
|
|
4781
4841
|
type: "edit",
|
|
4782
4842
|
key: args.key,
|
|
4783
4843
|
content: currentContent,
|
|
4844
|
+
oldContent,
|
|
4784
4845
|
summary: autoSummary
|
|
4785
4846
|
};
|
|
4786
4847
|
return {
|
|
@@ -6392,7 +6453,7 @@ async function executeTool(name, args, ctx, activeSkills, homeDir, signal, provi
|
|
|
6392
6453
|
return { result: out.result, searchResults: out.sources };
|
|
6393
6454
|
}
|
|
6394
6455
|
case "web_search": {
|
|
6395
|
-
const { executeWebSearch } = await import("./web-search-
|
|
6456
|
+
const { executeWebSearch } = await import("./web-search-IBZ6UAXL.js");
|
|
6396
6457
|
const out = await executeWebSearch(
|
|
6397
6458
|
args,
|
|
6398
6459
|
provider
|
|
@@ -7291,6 +7352,17 @@ ${skill.prompt}`).join("\n\n");
|
|
|
7291
7352
|
"- Redirect large outputs to files. Read selectively \u2014 don't dump entire datasets into responses.",
|
|
7292
7353
|
"- Always wrap file paths in backticks: `notes/brief.md`, `experiments/analysis.py:42`.",
|
|
7293
7354
|
"",
|
|
7355
|
+
"## Workspace Organization",
|
|
7356
|
+
"The workspace has managed directories. When creating files with `write_new_file`, use the correct key prefix:",
|
|
7357
|
+
"- `note:<slug>` \u2192 `notes/` \u2014 analysis write-ups, literature reviews, meeting notes, briefs",
|
|
7358
|
+
"- `paper:<slug>` \u2192 `papers/` \u2014 LaTeX manuscripts and drafts",
|
|
7359
|
+
"- `experiment:<slug>` \u2192 `experiments/` \u2014 experiment definitions, configs, results",
|
|
7360
|
+
"- `source:<slug>` \u2192 `sources/` \u2014 extracted text from papers, articles, datasets",
|
|
7361
|
+
"- `path:<relative/path>` \u2192 exact location \u2014 scripts, code, CSV data, configs, anything else",
|
|
7362
|
+
"Use descriptive slugs that read naturally: `note:scaling-law-comparison`, `experiment:ablation-dropout-rates`, `path:scripts/parse-arxiv.py`.",
|
|
7363
|
+
"Use the `folder` param to group related files: e.g. key `note:gpt4-findings` with folder `lit-review` creates `notes/lit-review/gpt4-findings.md`.",
|
|
7364
|
+
"Never use bare keys without a prefix \u2014 they end up in `artifacts/` which is not user-facing.",
|
|
7365
|
+
"",
|
|
7294
7366
|
`## Workspace
|
|
7295
7367
|
Root: ${process.cwd()}`,
|
|
7296
7368
|
skillText
|
|
@@ -7592,20 +7664,22 @@ function classifyUpdateRisk(update) {
|
|
|
7592
7664
|
import fs14 from "fs/promises";
|
|
7593
7665
|
import path14 from "path";
|
|
7594
7666
|
function resolveRelativePath(update) {
|
|
7667
|
+
const folder = update.folder;
|
|
7668
|
+
const sub = (dir, name, ext) => folder ? `${dir}/${folder}/${name}${ext}` : `${dir}/${name}${ext}`;
|
|
7595
7669
|
if (update.key.startsWith("path:")) {
|
|
7596
7670
|
return update.key.slice(5);
|
|
7597
7671
|
}
|
|
7598
7672
|
if (update.key.startsWith("note:")) {
|
|
7599
|
-
return
|
|
7673
|
+
return sub("notes", update.key.slice(5), ".md");
|
|
7600
7674
|
}
|
|
7601
7675
|
if (update.key.startsWith("paper:")) {
|
|
7602
|
-
return
|
|
7676
|
+
return sub("papers", update.key.slice(6), ".tex");
|
|
7603
7677
|
}
|
|
7604
7678
|
if (update.key.startsWith("experiment:")) {
|
|
7605
|
-
return
|
|
7679
|
+
return sub("experiments", update.key.slice(11), ".json");
|
|
7606
7680
|
}
|
|
7607
7681
|
if (update.key.startsWith("source:")) {
|
|
7608
|
-
return
|
|
7682
|
+
return sub("sources", update.key.slice(7), ".md");
|
|
7609
7683
|
}
|
|
7610
7684
|
return `artifacts/${update.key}.md`;
|
|
7611
7685
|
}
|
|
@@ -8014,6 +8088,14 @@ function getUnifiedSuggestions(partial, allSkills) {
|
|
|
8014
8088
|
}));
|
|
8015
8089
|
return [...cmdHits, ...skillHits];
|
|
8016
8090
|
}
|
|
8091
|
+
function extractSlashTrigger(text) {
|
|
8092
|
+
const lastSlash = text.lastIndexOf("/");
|
|
8093
|
+
if (lastSlash === -1) return null;
|
|
8094
|
+
if (lastSlash > 0 && text[lastSlash - 1] !== " ") return null;
|
|
8095
|
+
const after = text.slice(lastSlash + 1);
|
|
8096
|
+
if (after.includes(" ")) return null;
|
|
8097
|
+
return { partial: after.toLowerCase(), start: lastSlash };
|
|
8098
|
+
}
|
|
8017
8099
|
function extractAtMention(text) {
|
|
8018
8100
|
const lastAt = text.lastIndexOf("@");
|
|
8019
8101
|
if (lastAt === -1) return null;
|
|
@@ -8038,7 +8120,9 @@ function truncate3(value, max = 96) {
|
|
|
8038
8120
|
}
|
|
8039
8121
|
|
|
8040
8122
|
// src/tui/components.tsx
|
|
8041
|
-
import {
|
|
8123
|
+
import { memo, useMemo as useMemo3, useState as useState4 } from "react";
|
|
8124
|
+
import { Box as Box4, Text as Text4, useInput as useInput4 } from "ink";
|
|
8125
|
+
import { structuredPatch } from "diff";
|
|
8042
8126
|
|
|
8043
8127
|
// src/tui/layout.ts
|
|
8044
8128
|
var DEFAULT_TERMINAL_WIDTH = 80;
|
|
@@ -8046,11 +8130,19 @@ var MIN_TERMINAL_WIDTH = 20;
|
|
|
8046
8130
|
function getTerminalWidth(columns) {
|
|
8047
8131
|
return Math.max(MIN_TERMINAL_WIDTH, columns ?? process.stdout.columns ?? DEFAULT_TERMINAL_WIDTH);
|
|
8048
8132
|
}
|
|
8049
|
-
function
|
|
8133
|
+
function normalizeObservedTerminalWidth(fallbackWidth, ...columns) {
|
|
8050
8134
|
const observed = columns.filter((value) => typeof value === "number" && Number.isFinite(value) && value > 0);
|
|
8051
|
-
if (observed.length === 0)
|
|
8135
|
+
if (observed.length === 0) {
|
|
8136
|
+
return Math.max(MIN_TERMINAL_WIDTH, fallbackWidth);
|
|
8137
|
+
}
|
|
8052
8138
|
return Math.max(MIN_TERMINAL_WIDTH, Math.min(...observed));
|
|
8053
8139
|
}
|
|
8140
|
+
function getObservedTerminalWidth(...columns) {
|
|
8141
|
+
return normalizeObservedTerminalWidth(DEFAULT_TERMINAL_WIDTH, ...columns);
|
|
8142
|
+
}
|
|
8143
|
+
function getStableObservedTerminalWidth(currentWidth, ...columns) {
|
|
8144
|
+
return normalizeObservedTerminalWidth(currentWidth, ...columns);
|
|
8145
|
+
}
|
|
8054
8146
|
function insetWidth(width, inset) {
|
|
8055
8147
|
return Math.max(1, width - inset);
|
|
8056
8148
|
}
|
|
@@ -8166,7 +8258,7 @@ function renderInline(text, codeColor = source_default.cyan, linkColor = source_
|
|
|
8166
8258
|
}
|
|
8167
8259
|
|
|
8168
8260
|
// src/tui/components.tsx
|
|
8169
|
-
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
8261
|
+
import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
8170
8262
|
var GUTTER = {
|
|
8171
8263
|
user: "\u203A",
|
|
8172
8264
|
agent: "\u25AA",
|
|
@@ -8190,7 +8282,12 @@ function borderedContentWidth(width) {
|
|
|
8190
8282
|
function wrapText(value, width) {
|
|
8191
8283
|
return wrapAnsi(value, Math.max(1, width), { trim: false, hard: true });
|
|
8192
8284
|
}
|
|
8193
|
-
function
|
|
8285
|
+
function Divider({ width, color }) {
|
|
8286
|
+
const theme = useTheme();
|
|
8287
|
+
const w = insetWidth(resolveWidth(width), 4);
|
|
8288
|
+
return /* @__PURE__ */ jsx4(Text4, { color: color ?? theme.muted, dimColor: true, children: "\u2500".repeat(Math.max(1, w)) });
|
|
8289
|
+
}
|
|
8290
|
+
var UserMessage = memo(function UserMessage2({ text, turnNumber, width }) {
|
|
8194
8291
|
const theme = useTheme();
|
|
8195
8292
|
const contentWidth = resolveWidth(width);
|
|
8196
8293
|
const bodyWidth = indentedWidth(contentWidth);
|
|
@@ -8201,12 +8298,18 @@ function UserMessage({ text, width }) {
|
|
|
8201
8298
|
GUTTER.user,
|
|
8202
8299
|
" "
|
|
8203
8300
|
] }),
|
|
8204
|
-
/* @__PURE__ */ jsx4(Text4, { bold: true, color: theme.accent, children: "you" })
|
|
8301
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: theme.accent, children: "you" }),
|
|
8302
|
+
typeof turnNumber === "number" && /* @__PURE__ */ jsxs3(Text4, { color: theme.muted, dimColor: true, children: [
|
|
8303
|
+
" ",
|
|
8304
|
+
GUTTER.system,
|
|
8305
|
+
" #",
|
|
8306
|
+
turnNumber
|
|
8307
|
+
] })
|
|
8205
8308
|
] }),
|
|
8206
8309
|
/* @__PURE__ */ jsx4(Box4, { marginLeft: 2, width: bodyWidth, children: /* @__PURE__ */ jsx4(Text4, { color: theme.text, wrap: "wrap", children: wrappedText }) })
|
|
8207
8310
|
] });
|
|
8208
|
-
}
|
|
8209
|
-
|
|
8311
|
+
});
|
|
8312
|
+
var AgentMessage = memo(function AgentMessage2({ text, width }) {
|
|
8210
8313
|
const contentWidth = resolveWidth(width);
|
|
8211
8314
|
const bodyWidth = indentedWidth(contentWidth);
|
|
8212
8315
|
const theme = useTheme();
|
|
@@ -8222,6 +8325,20 @@ function AgentMessage({ text, width }) {
|
|
|
8222
8325
|
] }),
|
|
8223
8326
|
/* @__PURE__ */ jsx4(Box4, { marginLeft: 2, width: bodyWidth, children: /* @__PURE__ */ jsx4(Text4, { wrap: "wrap", children: wrappedText }) })
|
|
8224
8327
|
] });
|
|
8328
|
+
});
|
|
8329
|
+
function ThinkingIndicator({ frame, width }) {
|
|
8330
|
+
const theme = useTheme();
|
|
8331
|
+
const contentWidth = resolveWidth(width);
|
|
8332
|
+
return /* @__PURE__ */ jsxs3(Box4, { marginBottom: 1, width: contentWidth, children: [
|
|
8333
|
+
/* @__PURE__ */ jsxs3(Text4, { color: theme.secondary, bold: true, children: [
|
|
8334
|
+
GUTTER.agent,
|
|
8335
|
+
" "
|
|
8336
|
+
] }),
|
|
8337
|
+
/* @__PURE__ */ jsxs3(Text4, { color: theme.muted, dimColor: true, children: [
|
|
8338
|
+
frame,
|
|
8339
|
+
" thinking..."
|
|
8340
|
+
] })
|
|
8341
|
+
] });
|
|
8225
8342
|
}
|
|
8226
8343
|
function TaskPanel({
|
|
8227
8344
|
tasks: tasks2,
|
|
@@ -8254,7 +8371,7 @@ function TaskPanel({
|
|
|
8254
8371
|
] })
|
|
8255
8372
|
] });
|
|
8256
8373
|
}
|
|
8257
|
-
|
|
8374
|
+
var ToolActivitySummary = memo(function ToolActivitySummary2({
|
|
8258
8375
|
summary,
|
|
8259
8376
|
tools,
|
|
8260
8377
|
expanded = false,
|
|
@@ -8262,43 +8379,50 @@ function ToolActivitySummary({
|
|
|
8262
8379
|
}) {
|
|
8263
8380
|
const theme = useTheme();
|
|
8264
8381
|
const contentWidth = indentedWidth(resolveWidth(width));
|
|
8382
|
+
const innerWidth = indentedWidth(contentWidth, 4);
|
|
8265
8383
|
if (expanded) {
|
|
8266
|
-
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "
|
|
8267
|
-
/* @__PURE__ */
|
|
8268
|
-
|
|
8269
|
-
|
|
8270
|
-
|
|
8271
|
-
] }),
|
|
8272
|
-
tools.map((t, i) => {
|
|
8273
|
-
const dur = t.durationMs ? ` (${(t.durationMs / 1e3).toFixed(1)}s)` : "";
|
|
8274
|
-
const prefix = i === tools.length - 1 ? "\u2514" : "\u251C";
|
|
8275
|
-
return /* @__PURE__ */ jsxs3(Text4, { color: theme.muted, dimColor: true, wrap: "wrap", children: [
|
|
8276
|
-
" ",
|
|
8277
|
-
prefix,
|
|
8278
|
-
" ",
|
|
8279
|
-
GUTTER.success,
|
|
8384
|
+
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "row", marginLeft: 2, marginBottom: 0, width: contentWidth, children: [
|
|
8385
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.muted, dimColor: true, children: "\u2502 " }),
|
|
8386
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", width: innerWidth, children: [
|
|
8387
|
+
/* @__PURE__ */ jsxs3(Text4, { color: theme.muted, dimColor: true, wrap: "wrap", children: [
|
|
8388
|
+
GUTTER.tool,
|
|
8280
8389
|
" ",
|
|
8281
|
-
|
|
8282
|
-
|
|
8283
|
-
|
|
8284
|
-
|
|
8390
|
+
summary
|
|
8391
|
+
] }),
|
|
8392
|
+
tools.map((t, i) => {
|
|
8393
|
+
const dur = t.durationMs ? ` (${(t.durationMs / 1e3).toFixed(1)}s)` : "";
|
|
8394
|
+
const prefix = i === tools.length - 1 ? "\u2514" : "\u251C";
|
|
8395
|
+
return /* @__PURE__ */ jsxs3(Text4, { color: theme.muted, dimColor: true, wrap: "wrap", children: [
|
|
8396
|
+
" ",
|
|
8397
|
+
prefix,
|
|
8398
|
+
" ",
|
|
8399
|
+
GUTTER.success,
|
|
8400
|
+
" ",
|
|
8401
|
+
t.description,
|
|
8402
|
+
dur
|
|
8403
|
+
] }, i);
|
|
8404
|
+
})
|
|
8405
|
+
] })
|
|
8285
8406
|
] });
|
|
8286
8407
|
}
|
|
8287
8408
|
const lastTarget = tools.length > 0 ? tools[tools.length - 1].description : "";
|
|
8288
8409
|
const hint = tools.length > 1 ? " (ctrl+o to expand)" : "";
|
|
8289
|
-
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "
|
|
8290
|
-
/* @__PURE__ */
|
|
8291
|
-
|
|
8292
|
-
|
|
8293
|
-
|
|
8294
|
-
|
|
8295
|
-
|
|
8296
|
-
|
|
8297
|
-
|
|
8298
|
-
lastTarget
|
|
8410
|
+
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "row", marginLeft: 2, marginBottom: 0, width: contentWidth, children: [
|
|
8411
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.muted, dimColor: true, children: "\u2502 " }),
|
|
8412
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", width: innerWidth, children: [
|
|
8413
|
+
/* @__PURE__ */ jsxs3(Text4, { color: theme.muted, dimColor: true, wrap: "wrap", children: [
|
|
8414
|
+
GUTTER.tool,
|
|
8415
|
+
" ",
|
|
8416
|
+
summary,
|
|
8417
|
+
hint
|
|
8418
|
+
] }),
|
|
8419
|
+
lastTarget && tools.length > 1 && /* @__PURE__ */ jsxs3(Text4, { color: theme.muted, dimColor: true, wrap: "wrap", children: [
|
|
8420
|
+
" \u2514 ",
|
|
8421
|
+
lastTarget
|
|
8422
|
+
] })
|
|
8299
8423
|
] })
|
|
8300
8424
|
] });
|
|
8301
|
-
}
|
|
8425
|
+
});
|
|
8302
8426
|
function SubAgentIndicator({
|
|
8303
8427
|
agentType,
|
|
8304
8428
|
goal,
|
|
@@ -8347,23 +8471,30 @@ function SubAgentIndicator({
|
|
|
8347
8471
|
}
|
|
8348
8472
|
);
|
|
8349
8473
|
}
|
|
8350
|
-
|
|
8474
|
+
var SystemMessage = memo(function SystemMessage2({ text, width }) {
|
|
8351
8475
|
const theme = useTheme();
|
|
8352
8476
|
const contentWidth = resolveWidth(width);
|
|
8353
8477
|
const indentedContentWidth = indentedWidth(contentWidth);
|
|
8354
8478
|
const wrappedIndentedText = wrapText(text, indentedContentWidth);
|
|
8355
8479
|
const wrappedText = wrapText(text, contentWidth);
|
|
8356
|
-
|
|
8480
|
+
const trimmed = text.trimStart();
|
|
8481
|
+
if (trimmed.startsWith("\u2713") || trimmed.startsWith("\u2717")) {
|
|
8357
8482
|
return /* @__PURE__ */ jsx4(Box4, { marginLeft: 2, width: indentedContentWidth, children: /* @__PURE__ */ jsx4(Text4, { color: theme.muted, dimColor: true, wrap: "wrap", children: wrappedIndentedText }) });
|
|
8358
8483
|
}
|
|
8359
|
-
if (
|
|
8484
|
+
if (trimmed.startsWith("Error:") || trimmed.startsWith("Failed:")) {
|
|
8485
|
+
return /* @__PURE__ */ jsx4(Box4, { marginLeft: 2, width: indentedContentWidth, children: /* @__PURE__ */ jsx4(Text4, { color: theme.error, wrap: "wrap", children: wrapText(`${GUTTER.error} ${text.trim()}`, indentedContentWidth) }) });
|
|
8486
|
+
}
|
|
8487
|
+
if (trimmed.includes("\u25CA remembered:") || trimmed.includes("\u25CA ontology") || trimmed.includes("\u25CA learned:")) {
|
|
8488
|
+
return /* @__PURE__ */ jsx4(Box4, { marginLeft: 2, width: indentedContentWidth, children: /* @__PURE__ */ jsx4(Text4, { color: theme.accent, dimColor: true, wrap: "wrap", children: wrapText(text.trim(), indentedContentWidth) }) });
|
|
8489
|
+
}
|
|
8490
|
+
if (text.includes("compacted") || text.includes("Context compacted")) {
|
|
8360
8491
|
return /* @__PURE__ */ jsx4(Box4, { marginLeft: 2, width: indentedContentWidth, children: /* @__PURE__ */ jsx4(Text4, { color: theme.warning, dimColor: true, wrap: "wrap", children: wrapText(`${GUTTER.system} ${text.trim()}`, indentedContentWidth) }) });
|
|
8361
8492
|
}
|
|
8362
|
-
if (
|
|
8493
|
+
if (trimmed.startsWith(">")) {
|
|
8363
8494
|
return /* @__PURE__ */ jsx4(Box4, { width: contentWidth, children: /* @__PURE__ */ jsx4(Text4, { color: theme.muted, dimColor: true, wrap: "wrap", children: wrappedText }) });
|
|
8364
8495
|
}
|
|
8365
8496
|
return /* @__PURE__ */ jsx4(Box4, { width: contentWidth, children: /* @__PURE__ */ jsx4(Text4, { color: theme.muted, wrap: "wrap", children: wrapText(`${GUTTER.system} ${text.trim()}`, contentWidth) }) });
|
|
8366
|
-
}
|
|
8497
|
+
});
|
|
8367
8498
|
function PromptPrefix({
|
|
8368
8499
|
busy,
|
|
8369
8500
|
frame,
|
|
@@ -8382,25 +8513,131 @@ function PromptPrefix({
|
|
|
8382
8513
|
" "
|
|
8383
8514
|
] });
|
|
8384
8515
|
}
|
|
8516
|
+
var MAX_DIFF_LINES = 16;
|
|
8517
|
+
function computeDiffLines(oldContent, newContent, fileName) {
|
|
8518
|
+
if (oldContent == null) {
|
|
8519
|
+
const lines = newContent.split("\n");
|
|
8520
|
+
return lines.slice(0, MAX_DIFF_LINES + 4).map((l) => ({ type: "add", text: l }));
|
|
8521
|
+
}
|
|
8522
|
+
const patch = structuredPatch(fileName, fileName, oldContent, newContent, "", "", { context: 2 });
|
|
8523
|
+
const result = [];
|
|
8524
|
+
for (const hunk of patch.hunks) {
|
|
8525
|
+
if (result.length > 0) {
|
|
8526
|
+
result.push({ type: "ctx", text: "\xB7\xB7\xB7" });
|
|
8527
|
+
}
|
|
8528
|
+
for (const line of hunk.lines) {
|
|
8529
|
+
if (line.startsWith("+")) {
|
|
8530
|
+
result.push({ type: "add", text: line.slice(1) });
|
|
8531
|
+
} else if (line.startsWith("-")) {
|
|
8532
|
+
result.push({ type: "del", text: line.slice(1) });
|
|
8533
|
+
} else {
|
|
8534
|
+
result.push({ type: "ctx", text: line.slice(1) });
|
|
8535
|
+
}
|
|
8536
|
+
}
|
|
8537
|
+
}
|
|
8538
|
+
return result;
|
|
8539
|
+
}
|
|
8385
8540
|
function PendingUpdateCard({
|
|
8386
8541
|
count,
|
|
8387
8542
|
summary,
|
|
8543
|
+
fileName,
|
|
8544
|
+
updateType,
|
|
8545
|
+
oldContent,
|
|
8546
|
+
newContent,
|
|
8547
|
+
active,
|
|
8548
|
+
onAccept,
|
|
8549
|
+
onReject,
|
|
8550
|
+
onFeedback,
|
|
8388
8551
|
width
|
|
8389
8552
|
}) {
|
|
8390
8553
|
const theme = useTheme();
|
|
8391
8554
|
const contentWidth = resolveWidth(width);
|
|
8392
|
-
const
|
|
8555
|
+
const innerWidth = borderedContentWidth(contentWidth);
|
|
8556
|
+
const bodyWidth = indentedWidth(innerWidth);
|
|
8557
|
+
const diffLines = useMemo3(
|
|
8558
|
+
() => computeDiffLines(oldContent, newContent, fileName),
|
|
8559
|
+
[oldContent, newContent, fileName]
|
|
8560
|
+
);
|
|
8561
|
+
const truncated = diffLines.length > MAX_DIFF_LINES;
|
|
8562
|
+
const visibleLines = truncated ? diffLines.slice(0, MAX_DIFF_LINES) : diffLines;
|
|
8563
|
+
const additions = diffLines.filter((l) => l.type === "add").length;
|
|
8564
|
+
const deletions = diffLines.filter((l) => l.type === "del").length;
|
|
8565
|
+
const options = [
|
|
8566
|
+
{ label: "Accept", description: "Apply this update" },
|
|
8567
|
+
{ label: "Reject", description: "Discard this update" }
|
|
8568
|
+
];
|
|
8569
|
+
const totalItems = options.length + 1;
|
|
8570
|
+
const feedbackIndex = options.length;
|
|
8571
|
+
const [selectedIndex, setSelectedIndex] = useState4(0);
|
|
8572
|
+
const [mode, setMode] = useState4("selecting");
|
|
8573
|
+
const [feedbackText, setFeedbackText] = useState4("");
|
|
8574
|
+
useInput4((input2, key) => {
|
|
8575
|
+
if (!active || mode !== "selecting") return;
|
|
8576
|
+
if (key.upArrow) {
|
|
8577
|
+
setSelectedIndex((i) => Math.max(0, i - 1));
|
|
8578
|
+
return;
|
|
8579
|
+
}
|
|
8580
|
+
if (key.downArrow) {
|
|
8581
|
+
setSelectedIndex((i) => Math.min(totalItems - 1, i + 1));
|
|
8582
|
+
return;
|
|
8583
|
+
}
|
|
8584
|
+
if (key.return) {
|
|
8585
|
+
if (selectedIndex === 0) {
|
|
8586
|
+
onAccept();
|
|
8587
|
+
return;
|
|
8588
|
+
}
|
|
8589
|
+
if (selectedIndex === 1) {
|
|
8590
|
+
onReject();
|
|
8591
|
+
return;
|
|
8592
|
+
}
|
|
8593
|
+
if (selectedIndex === feedbackIndex) {
|
|
8594
|
+
setMode("typing");
|
|
8595
|
+
setFeedbackText("");
|
|
8596
|
+
}
|
|
8597
|
+
return;
|
|
8598
|
+
}
|
|
8599
|
+
}, { isActive: active && mode === "selecting" });
|
|
8600
|
+
useInput4((input2, key) => {
|
|
8601
|
+
if (!active || mode !== "typing") return;
|
|
8602
|
+
if (key.escape) {
|
|
8603
|
+
setMode("selecting");
|
|
8604
|
+
setFeedbackText("");
|
|
8605
|
+
return;
|
|
8606
|
+
}
|
|
8607
|
+
if (key.return) {
|
|
8608
|
+
if (feedbackText.trim()) {
|
|
8609
|
+
onFeedback(feedbackText.trim());
|
|
8610
|
+
setFeedbackText("");
|
|
8611
|
+
setMode("selecting");
|
|
8612
|
+
}
|
|
8613
|
+
return;
|
|
8614
|
+
}
|
|
8615
|
+
if (key.backspace || key.delete) {
|
|
8616
|
+
setFeedbackText((t) => t.slice(0, -1));
|
|
8617
|
+
return;
|
|
8618
|
+
}
|
|
8619
|
+
if (key.ctrl && input2 === "u") {
|
|
8620
|
+
setFeedbackText("");
|
|
8621
|
+
return;
|
|
8622
|
+
}
|
|
8623
|
+
if (!key.ctrl && !key.meta && !key.tab && input2.length === 1 && input2 >= " ") {
|
|
8624
|
+
setFeedbackText((t) => t + input2);
|
|
8625
|
+
}
|
|
8626
|
+
}, { isActive: active && mode === "typing" });
|
|
8627
|
+
const isFeedbackSelected = selectedIndex === feedbackIndex;
|
|
8628
|
+
const lineNumWidth = Math.max(3, String(diffLines.length).length + 1);
|
|
8629
|
+
const diffContentWidth = Math.max(1, bodyWidth - lineNumWidth - 3);
|
|
8393
8630
|
return /* @__PURE__ */ jsxs3(
|
|
8394
8631
|
Box4,
|
|
8395
8632
|
{
|
|
8396
8633
|
borderStyle: "single",
|
|
8397
|
-
borderColor: theme.
|
|
8634
|
+
borderColor: theme.warning,
|
|
8398
8635
|
paddingX: 1,
|
|
8399
|
-
marginBottom:
|
|
8636
|
+
marginBottom: 0,
|
|
8400
8637
|
flexDirection: "column",
|
|
8401
8638
|
width: contentWidth,
|
|
8402
8639
|
children: [
|
|
8403
|
-
/* @__PURE__ */ jsxs3(Box4, { width:
|
|
8640
|
+
/* @__PURE__ */ jsxs3(Box4, { width: innerWidth, children: [
|
|
8404
8641
|
/* @__PURE__ */ jsxs3(Text4, { color: theme.pending, bold: true, children: [
|
|
8405
8642
|
GUTTER.pending,
|
|
8406
8643
|
" "
|
|
@@ -8412,13 +8649,70 @@ function PendingUpdateCard({
|
|
|
8412
8649
|
" awaiting review"
|
|
8413
8650
|
] })
|
|
8414
8651
|
] }),
|
|
8415
|
-
/* @__PURE__ */
|
|
8416
|
-
|
|
8417
|
-
/* @__PURE__ */ jsx4(Text4, {
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
|
|
8421
|
-
|
|
8652
|
+
/* @__PURE__ */ jsxs3(Box4, { marginLeft: 2, marginTop: 0, width: bodyWidth, children: [
|
|
8653
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.muted, wrap: "wrap", children: summary }),
|
|
8654
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.muted, dimColor: true, children: " " }),
|
|
8655
|
+
additions > 0 && /* @__PURE__ */ jsxs3(Text4, { color: theme.secondary, children: [
|
|
8656
|
+
"+",
|
|
8657
|
+
additions
|
|
8658
|
+
] }),
|
|
8659
|
+
additions > 0 && deletions > 0 && /* @__PURE__ */ jsx4(Text4, { color: theme.muted, dimColor: true, children: " " }),
|
|
8660
|
+
deletions > 0 && /* @__PURE__ */ jsxs3(Text4, { color: theme.error, children: [
|
|
8661
|
+
"-",
|
|
8662
|
+
deletions
|
|
8663
|
+
] })
|
|
8664
|
+
] }),
|
|
8665
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", marginLeft: 2, marginTop: 1, width: bodyWidth, children: [
|
|
8666
|
+
visibleLines.map((line, i) => {
|
|
8667
|
+
const prefix = line.type === "add" ? "+" : line.type === "del" ? "-" : " ";
|
|
8668
|
+
const color = line.type === "add" ? theme.secondary : line.type === "del" ? theme.error : theme.muted;
|
|
8669
|
+
const dimmed = line.type === "ctx";
|
|
8670
|
+
const displayText = truncateToWidth(line.text, diffContentWidth);
|
|
8671
|
+
return /* @__PURE__ */ jsxs3(Text4, { color, dimColor: dimmed, wrap: "truncate-end", children: [
|
|
8672
|
+
prefix,
|
|
8673
|
+
" ",
|
|
8674
|
+
displayText
|
|
8675
|
+
] }, i);
|
|
8676
|
+
}),
|
|
8677
|
+
truncated && /* @__PURE__ */ jsxs3(Text4, { color: theme.muted, dimColor: true, children: [
|
|
8678
|
+
" \xB7\xB7\xB7 ",
|
|
8679
|
+
diffLines.length - MAX_DIFF_LINES,
|
|
8680
|
+
" more lines"
|
|
8681
|
+
] })
|
|
8682
|
+
] }),
|
|
8683
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", marginLeft: 2, marginTop: 1, width: bodyWidth, children: [
|
|
8684
|
+
options.map((opt, idx) => {
|
|
8685
|
+
const isSelected = active && mode === "selecting" && idx === selectedIndex;
|
|
8686
|
+
const optColor = idx === 0 ? theme.secondary : theme.error;
|
|
8687
|
+
return /* @__PURE__ */ jsx4(Box4, { width: bodyWidth, children: isSelected ? /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
8688
|
+
/* @__PURE__ */ jsx4(Text4, { inverse: true, bold: true, color: theme.accent, children: " \u203A " }),
|
|
8689
|
+
/* @__PURE__ */ jsx4(Text4, { inverse: true, bold: true, children: " " + opt.label + " " }),
|
|
8690
|
+
/* @__PURE__ */ jsxs3(Text4, { color: theme.muted, dimColor: true, children: [
|
|
8691
|
+
" \u2014 ",
|
|
8692
|
+
opt.description
|
|
8693
|
+
] })
|
|
8694
|
+
] }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
8695
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.muted, children: " " }),
|
|
8696
|
+
/* @__PURE__ */ jsx4(Text4, { color: optColor, children: opt.label }),
|
|
8697
|
+
/* @__PURE__ */ jsxs3(Text4, { color: theme.muted, dimColor: true, children: [
|
|
8698
|
+
" \u2014 ",
|
|
8699
|
+
opt.description
|
|
8700
|
+
] })
|
|
8701
|
+
] }) }, opt.label);
|
|
8702
|
+
}),
|
|
8703
|
+
mode === "typing" ? /* @__PURE__ */ jsxs3(Box4, { width: bodyWidth, children: [
|
|
8704
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.accent, bold: true, children: " \u203A " }),
|
|
8705
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.text, children: feedbackText }),
|
|
8706
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.accent, children: "\u2588" })
|
|
8707
|
+
] }) : /* @__PURE__ */ jsx4(Box4, { width: bodyWidth, children: active && isFeedbackSelected ? /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
8708
|
+
/* @__PURE__ */ jsx4(Text4, { inverse: true, bold: true, color: theme.accent, children: " \u203A " }),
|
|
8709
|
+
/* @__PURE__ */ jsx4(Text4, { inverse: true, bold: true, color: theme.muted, children: " Give feedback... " })
|
|
8710
|
+
] }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
8711
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.muted, children: " " }),
|
|
8712
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.muted, dimColor: true, children: "Give feedback..." })
|
|
8713
|
+
] }) })
|
|
8714
|
+
] }),
|
|
8715
|
+
/* @__PURE__ */ jsx4(Box4, { marginLeft: 2, marginTop: 0, width: bodyWidth, children: /* @__PURE__ */ jsx4(Text4, { color: theme.muted, dimColor: true, wrap: "wrap", children: mode === "typing" ? "Type your feedback \xB7 Enter submit \xB7 Esc back" : active ? "\u2191/\u2193 select \xB7 Enter confirm" : "Waiting..." }) })
|
|
8422
8716
|
]
|
|
8423
8717
|
}
|
|
8424
8718
|
);
|
|
@@ -8426,12 +8720,67 @@ function PendingUpdateCard({
|
|
|
8426
8720
|
function QuestionCard({
|
|
8427
8721
|
question,
|
|
8428
8722
|
options,
|
|
8723
|
+
active,
|
|
8724
|
+
onSelect,
|
|
8429
8725
|
width
|
|
8430
8726
|
}) {
|
|
8431
8727
|
const theme = useTheme();
|
|
8432
8728
|
const contentWidth = resolveWidth(width);
|
|
8433
8729
|
const innerWidth = borderedContentWidth(contentWidth);
|
|
8434
8730
|
const bodyWidth = indentedWidth(innerWidth);
|
|
8731
|
+
const hasOptions = options.length > 0;
|
|
8732
|
+
const totalItems = hasOptions ? options.length + 1 : 0;
|
|
8733
|
+
const customIndex = options.length;
|
|
8734
|
+
const [selectedIndex, setSelectedIndex] = useState4(0);
|
|
8735
|
+
const [mode, setMode] = useState4(hasOptions ? "selecting" : "typing");
|
|
8736
|
+
const [customText, setCustomText] = useState4("");
|
|
8737
|
+
useInput4((input2, key) => {
|
|
8738
|
+
if (!active || mode !== "selecting" || !hasOptions) return;
|
|
8739
|
+
if (key.upArrow) {
|
|
8740
|
+
setSelectedIndex((i) => Math.max(0, i - 1));
|
|
8741
|
+
return;
|
|
8742
|
+
}
|
|
8743
|
+
if (key.downArrow) {
|
|
8744
|
+
setSelectedIndex((i) => Math.min(totalItems - 1, i + 1));
|
|
8745
|
+
return;
|
|
8746
|
+
}
|
|
8747
|
+
if (key.return) {
|
|
8748
|
+
if (selectedIndex < options.length) {
|
|
8749
|
+
const picked = options[selectedIndex];
|
|
8750
|
+
if (picked) onSelect(picked.label, false);
|
|
8751
|
+
} else {
|
|
8752
|
+
setMode("typing");
|
|
8753
|
+
setCustomText("");
|
|
8754
|
+
}
|
|
8755
|
+
return;
|
|
8756
|
+
}
|
|
8757
|
+
}, { isActive: active && mode === "selecting" });
|
|
8758
|
+
useInput4((input2, key) => {
|
|
8759
|
+
if (!active || mode !== "typing") return;
|
|
8760
|
+
if (key.escape && hasOptions) {
|
|
8761
|
+
setMode("selecting");
|
|
8762
|
+
setCustomText("");
|
|
8763
|
+
return;
|
|
8764
|
+
}
|
|
8765
|
+
if (key.return) {
|
|
8766
|
+
if (customText.trim()) {
|
|
8767
|
+
onSelect(customText.trim(), true);
|
|
8768
|
+
}
|
|
8769
|
+
return;
|
|
8770
|
+
}
|
|
8771
|
+
if (key.backspace || key.delete) {
|
|
8772
|
+
setCustomText((t) => t.slice(0, -1));
|
|
8773
|
+
return;
|
|
8774
|
+
}
|
|
8775
|
+
if (key.ctrl && input2 === "u") {
|
|
8776
|
+
setCustomText("");
|
|
8777
|
+
return;
|
|
8778
|
+
}
|
|
8779
|
+
if (!key.ctrl && !key.meta && !key.tab && input2.length === 1 && input2 >= " ") {
|
|
8780
|
+
setCustomText((t) => t + input2);
|
|
8781
|
+
}
|
|
8782
|
+
}, { isActive: active && mode === "typing" });
|
|
8783
|
+
const isCustomSelected = selectedIndex === customIndex;
|
|
8435
8784
|
return /* @__PURE__ */ jsxs3(
|
|
8436
8785
|
Box4,
|
|
8437
8786
|
{
|
|
@@ -8450,18 +8799,38 @@ function QuestionCard({
|
|
|
8450
8799
|
/* @__PURE__ */ jsx4(Text4, { bold: true, color: theme.warning, children: "Agent needs your input" })
|
|
8451
8800
|
] }),
|
|
8452
8801
|
/* @__PURE__ */ jsx4(Box4, { marginLeft: 2, marginTop: 0, width: bodyWidth, children: /* @__PURE__ */ jsx4(Text4, { color: theme.text, wrap: "wrap", children: question }) }),
|
|
8453
|
-
|
|
8454
|
-
|
|
8455
|
-
|
|
8456
|
-
|
|
8457
|
-
|
|
8458
|
-
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
|
|
8462
|
-
|
|
8463
|
-
|
|
8464
|
-
|
|
8802
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", marginLeft: 2, marginTop: 1, width: bodyWidth, children: [
|
|
8803
|
+
options.map((opt, idx) => {
|
|
8804
|
+
const isSelected = active && mode === "selecting" && idx === selectedIndex;
|
|
8805
|
+
return /* @__PURE__ */ jsx4(Box4, { width: bodyWidth, children: isSelected ? /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
8806
|
+
/* @__PURE__ */ jsx4(Text4, { inverse: true, bold: true, color: theme.accent, children: " \u203A " }),
|
|
8807
|
+
/* @__PURE__ */ jsx4(Text4, { inverse: true, bold: true, children: " " + opt.label + " " }),
|
|
8808
|
+
/* @__PURE__ */ jsxs3(Text4, { color: theme.muted, dimColor: true, children: [
|
|
8809
|
+
" \u2014 ",
|
|
8810
|
+
opt.description
|
|
8811
|
+
] })
|
|
8812
|
+
] }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
8813
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.muted, children: " " }),
|
|
8814
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.text, children: opt.label }),
|
|
8815
|
+
/* @__PURE__ */ jsxs3(Text4, { color: theme.muted, dimColor: true, children: [
|
|
8816
|
+
" \u2014 ",
|
|
8817
|
+
opt.description
|
|
8818
|
+
] })
|
|
8819
|
+
] }) }, opt.label);
|
|
8820
|
+
}),
|
|
8821
|
+
mode === "typing" ? /* @__PURE__ */ jsxs3(Box4, { width: bodyWidth, children: [
|
|
8822
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.accent, bold: true, children: " \u203A " }),
|
|
8823
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.text, children: customText }),
|
|
8824
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.accent, children: "\u2588" })
|
|
8825
|
+
] }) : /* @__PURE__ */ jsx4(Box4, { width: bodyWidth, children: active && isCustomSelected ? /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
8826
|
+
/* @__PURE__ */ jsx4(Text4, { inverse: true, bold: true, color: theme.accent, children: " \u203A " }),
|
|
8827
|
+
/* @__PURE__ */ jsx4(Text4, { inverse: true, bold: true, color: theme.muted, children: " Custom answer... " })
|
|
8828
|
+
] }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
8829
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.muted, children: " " }),
|
|
8830
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.muted, dimColor: true, children: "Custom answer..." })
|
|
8831
|
+
] }) })
|
|
8832
|
+
] }),
|
|
8833
|
+
/* @__PURE__ */ jsx4(Box4, { marginLeft: 2, marginTop: 0, width: bodyWidth, children: /* @__PURE__ */ jsx4(Text4, { color: theme.muted, dimColor: true, wrap: "wrap", children: mode === "typing" ? "Type your answer \xB7 Enter submit \xB7 Esc back" : active ? "\u2191/\u2193 select \xB7 Enter confirm" : "Waiting..." }) })
|
|
8465
8834
|
]
|
|
8466
8835
|
}
|
|
8467
8836
|
);
|
|
@@ -8656,22 +9025,22 @@ function FooterBar({
|
|
|
8656
9025
|
var STREAM_FLUSH_PATTERN = /[.!?]\s|\n|^#{1,3}\s|^[-*]\s/m;
|
|
8657
9026
|
var STREAM_FLUSH_INTERVAL_MS = 80;
|
|
8658
9027
|
function splitMessagesForRender(messages, busy) {
|
|
8659
|
-
if (
|
|
9028
|
+
if (messages.length === 0) {
|
|
8660
9029
|
return {
|
|
8661
9030
|
staticMessages: messages,
|
|
8662
9031
|
dynamicMessages: []
|
|
8663
9032
|
};
|
|
8664
9033
|
}
|
|
8665
9034
|
const last = messages[messages.length - 1];
|
|
8666
|
-
if (
|
|
9035
|
+
if (last && (last.role === "assistant" ? busy : !busy && last.role === "system")) {
|
|
8667
9036
|
return {
|
|
8668
|
-
staticMessages: messages,
|
|
8669
|
-
dynamicMessages: []
|
|
9037
|
+
staticMessages: messages.slice(0, -1),
|
|
9038
|
+
dynamicMessages: [last]
|
|
8670
9039
|
};
|
|
8671
9040
|
}
|
|
8672
9041
|
return {
|
|
8673
|
-
staticMessages: messages
|
|
8674
|
-
dynamicMessages: [
|
|
9042
|
+
staticMessages: messages,
|
|
9043
|
+
dynamicMessages: []
|
|
8675
9044
|
};
|
|
8676
9045
|
}
|
|
8677
9046
|
function createSentenceStreamBuffer({
|
|
@@ -8720,10 +9089,10 @@ function createSentenceStreamBuffer({
|
|
|
8720
9089
|
}
|
|
8721
9090
|
|
|
8722
9091
|
// src/tui/hooks/use-animated-frame.ts
|
|
8723
|
-
import { useState as
|
|
9092
|
+
import { useState as useState5, useEffect as useEffect2 } from "react";
|
|
8724
9093
|
var SPINNER_FRAMES = ["\u25D0", "\u25D3", "\u25D1", "\u25D2"];
|
|
8725
9094
|
function useAnimatedFrame(active) {
|
|
8726
|
-
const [index, setIndex] =
|
|
9095
|
+
const [index, setIndex] = useState5(0);
|
|
8727
9096
|
useEffect2(() => {
|
|
8728
9097
|
if (!active) {
|
|
8729
9098
|
setIndex(0);
|
|
@@ -8736,28 +9105,49 @@ function useAnimatedFrame(active) {
|
|
|
8736
9105
|
}
|
|
8737
9106
|
|
|
8738
9107
|
// src/tui/hooks/use-terminal-width.ts
|
|
8739
|
-
import { useState as
|
|
9108
|
+
import { useState as useState6, useEffect as useEffect3 } from "react";
|
|
8740
9109
|
import { useStdout as useStdout2 } from "ink";
|
|
9110
|
+
var RESIZE_DEBOUNCE_MS = 50;
|
|
8741
9111
|
function useTerminalWidth() {
|
|
8742
9112
|
const { stdout } = useStdout2();
|
|
8743
|
-
const [terminalWidth, setTerminalWidth] =
|
|
9113
|
+
const [terminalWidth, setTerminalWidth] = useState6(
|
|
8744
9114
|
() => getObservedTerminalWidth(stdout.columns, process.stdout.columns)
|
|
8745
9115
|
);
|
|
8746
9116
|
useEffect3(() => {
|
|
8747
9117
|
const stream = stdout;
|
|
8748
|
-
|
|
8749
|
-
|
|
8750
|
-
setTerminalWidth((current) =>
|
|
9118
|
+
let resizeTimer = null;
|
|
9119
|
+
const commitWidth = () => {
|
|
9120
|
+
setTerminalWidth((current) => {
|
|
9121
|
+
const nextWidth = getStableObservedTerminalWidth(current, stream.columns, process.stdout.columns);
|
|
9122
|
+
return current === nextWidth ? current : nextWidth;
|
|
9123
|
+
});
|
|
9124
|
+
};
|
|
9125
|
+
const scheduleWidthUpdate = () => {
|
|
9126
|
+
if (resizeTimer) {
|
|
9127
|
+
clearTimeout(resizeTimer);
|
|
9128
|
+
}
|
|
9129
|
+
resizeTimer = setTimeout(() => {
|
|
9130
|
+
resizeTimer = null;
|
|
9131
|
+
commitWidth();
|
|
9132
|
+
}, RESIZE_DEBOUNCE_MS);
|
|
8751
9133
|
};
|
|
8752
|
-
|
|
9134
|
+
commitWidth();
|
|
8753
9135
|
if (typeof stream.on === "function") {
|
|
8754
|
-
stream.on("resize",
|
|
9136
|
+
stream.on("resize", scheduleWidthUpdate);
|
|
8755
9137
|
return () => {
|
|
9138
|
+
if (resizeTimer) {
|
|
9139
|
+
clearTimeout(resizeTimer);
|
|
9140
|
+
}
|
|
8756
9141
|
if (typeof stream.off === "function") {
|
|
8757
|
-
stream.off("resize",
|
|
9142
|
+
stream.off("resize", scheduleWidthUpdate);
|
|
8758
9143
|
}
|
|
8759
9144
|
};
|
|
8760
9145
|
}
|
|
9146
|
+
return () => {
|
|
9147
|
+
if (resizeTimer) {
|
|
9148
|
+
clearTimeout(resizeTimer);
|
|
9149
|
+
}
|
|
9150
|
+
};
|
|
8761
9151
|
}, [stdout]);
|
|
8762
9152
|
return terminalWidth;
|
|
8763
9153
|
}
|
|
@@ -9936,22 +10326,36 @@ function parseCharterYaml(raw) {
|
|
|
9936
10326
|
|
|
9937
10327
|
// src/tui/helpers/render-message.tsx
|
|
9938
10328
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
9939
|
-
function
|
|
9940
|
-
|
|
9941
|
-
|
|
9942
|
-
|
|
9943
|
-
|
|
9944
|
-
|
|
9945
|
-
|
|
9946
|
-
|
|
10329
|
+
function renderConversationMessages(messages, expanded, width) {
|
|
10330
|
+
const elements = [];
|
|
10331
|
+
let turnCount = 0;
|
|
10332
|
+
for (let i = 0; i < messages.length; i++) {
|
|
10333
|
+
const message = messages[i];
|
|
10334
|
+
const key = `msg-${i}`;
|
|
10335
|
+
if (message.role === "user" && i > 0) {
|
|
10336
|
+
const prev = messages[i - 1];
|
|
10337
|
+
if (prev && prev.role !== "user") {
|
|
10338
|
+
elements.push(/* @__PURE__ */ jsx5(Divider, { width }, `div-${i}`));
|
|
10339
|
+
}
|
|
10340
|
+
}
|
|
10341
|
+
if (message.role === "user") {
|
|
10342
|
+
turnCount++;
|
|
10343
|
+
elements.push(/* @__PURE__ */ jsx5(UserMessage, { text: message.text, turnNumber: turnCount, width }, key));
|
|
10344
|
+
} else if (message.role === "system") {
|
|
10345
|
+
if (message.text.startsWith("__tool_summary__")) {
|
|
10346
|
+
try {
|
|
10347
|
+
const data = JSON.parse(message.text.slice("__tool_summary__".length));
|
|
10348
|
+
elements.push(/* @__PURE__ */ jsx5(ToolActivitySummary, { summary: data.summary, tools: data.tools, expanded, width }, key));
|
|
10349
|
+
} catch {
|
|
10350
|
+
}
|
|
10351
|
+
} else {
|
|
10352
|
+
elements.push(/* @__PURE__ */ jsx5(SystemMessage, { text: message.text, width }, key));
|
|
9947
10353
|
}
|
|
10354
|
+
} else {
|
|
10355
|
+
elements.push(/* @__PURE__ */ jsx5(AgentMessage, { text: message.text, width }, key));
|
|
9948
10356
|
}
|
|
9949
|
-
return /* @__PURE__ */ jsx5(SystemMessage, { text: message.text, width }, key);
|
|
9950
10357
|
}
|
|
9951
|
-
|
|
9952
|
-
return /* @__PURE__ */ jsx5(UserMessage, { text: message.text, width }, key);
|
|
9953
|
-
}
|
|
9954
|
-
return /* @__PURE__ */ jsx5(AgentMessage, { text: message.text, width }, key);
|
|
10358
|
+
return elements;
|
|
9955
10359
|
}
|
|
9956
10360
|
|
|
9957
10361
|
// src/tui/app.tsx
|
|
@@ -9962,55 +10366,98 @@ function App({
|
|
|
9962
10366
|
}) {
|
|
9963
10367
|
const app = useApp();
|
|
9964
10368
|
const abortRef = useRef2(null);
|
|
9965
|
-
const [input2, setInput] =
|
|
9966
|
-
const [composerFocused, setComposerFocused] =
|
|
9967
|
-
const [busy, setBusy] =
|
|
9968
|
-
const [authStatus, setAuthStatus] =
|
|
9969
|
-
const [workspacePath, setWorkspacePath] =
|
|
9970
|
-
const [workspaceFiles, setWorkspaceFiles] =
|
|
9971
|
-
const [skills2, setSkills] =
|
|
9972
|
-
const [messages, setMessages] =
|
|
9973
|
-
const [
|
|
9974
|
-
const [
|
|
9975
|
-
const [
|
|
9976
|
-
const [
|
|
9977
|
-
const [
|
|
9978
|
-
const [
|
|
9979
|
-
const [
|
|
9980
|
-
const [
|
|
9981
|
-
const [
|
|
9982
|
-
const [
|
|
9983
|
-
const [
|
|
10369
|
+
const [input2, setInput] = useState7("");
|
|
10370
|
+
const [composerFocused, setComposerFocused] = useState7(true);
|
|
10371
|
+
const [busy, setBusy] = useState7(false);
|
|
10372
|
+
const [authStatus, setAuthStatus] = useState7(initialState.authStatus);
|
|
10373
|
+
const [workspacePath, setWorkspacePath] = useState7(initialState.workspacePath);
|
|
10374
|
+
const [workspaceFiles, setWorkspaceFiles] = useState7([]);
|
|
10375
|
+
const [skills2, setSkills] = useState7([]);
|
|
10376
|
+
const [messages, setMessages] = useState7([]);
|
|
10377
|
+
const [history, setHistory] = useState7([]);
|
|
10378
|
+
const [activeSkills, setActiveSkills] = useState7([]);
|
|
10379
|
+
const [pendingUpdates, setPendingUpdates] = useState7(initialState.pendingUpdates);
|
|
10380
|
+
const [statusLine, setStatusLine] = useState7("");
|
|
10381
|
+
const [activeToolActivities, setActiveToolActivities] = useState7({});
|
|
10382
|
+
const [turnToolCount, setTurnToolCount] = useState7(0);
|
|
10383
|
+
const [latchedToolActivity, setLatchedToolActivity] = useState7("");
|
|
10384
|
+
const [latchedToolCount, setLatchedToolCount] = useState7(0);
|
|
10385
|
+
const [subAgentProgress, setSubAgentProgress] = useState7({});
|
|
10386
|
+
const [toolActivityExpanded, setToolActivityExpanded] = useState7(false);
|
|
10387
|
+
const [taskPanelVisible, setTaskPanelVisible] = useState7(true);
|
|
10388
|
+
const [taskVersion, setTaskVersion] = useState7(0);
|
|
9984
10389
|
const turnToolLogRef = useRef2([]);
|
|
9985
|
-
const [sessionTokens, setSessionTokens] =
|
|
9986
|
-
const [tokenDisplay, setTokenDisplay] =
|
|
9987
|
-
const [showSuggestions, setShowSuggestions] =
|
|
9988
|
-
const [agentMode, setAgentMode] =
|
|
9989
|
-
const [planningState, setPlanningState] =
|
|
10390
|
+
const [sessionTokens, setSessionTokens] = useState7(() => createSessionUsage());
|
|
10391
|
+
const [tokenDisplay, setTokenDisplay] = useState7("");
|
|
10392
|
+
const [showSuggestions, setShowSuggestions] = useState7(false);
|
|
10393
|
+
const [agentMode, setAgentMode] = useState7("manual-review");
|
|
10394
|
+
const [planningState, setPlanningState] = useState7({
|
|
9990
10395
|
status: "idle",
|
|
9991
10396
|
planningHistory: []
|
|
9992
10397
|
});
|
|
9993
|
-
const [theme, setTheme] =
|
|
9994
|
-
const [config, setConfig] =
|
|
9995
|
-
const [cursorToEnd, setCursorToEnd] =
|
|
9996
|
-
const [
|
|
9997
|
-
const [
|
|
9998
|
-
const [
|
|
9999
|
-
const
|
|
10000
|
-
const
|
|
10398
|
+
const [theme, setTheme] = useState7("dark");
|
|
10399
|
+
const [config, setConfig] = useState7(null);
|
|
10400
|
+
const [cursorToEnd, setCursorToEnd] = useState7(0);
|
|
10401
|
+
const [messageRenderVersion, setMessageRenderVersion] = useState7(0);
|
|
10402
|
+
const [screen, setScreen] = useState7("main");
|
|
10403
|
+
const [resumeSessions, setResumeSessions] = useState7([]);
|
|
10404
|
+
const [ctrlCPending, setCtrlCPending] = useState7(false);
|
|
10405
|
+
const sessionId2 = useMemo4(() => crypto.randomUUID(), []);
|
|
10001
10406
|
const deferredPendingUpdates = useDeferredValue(pendingUpdates);
|
|
10407
|
+
const visiblePendingUpdates = deferredPendingUpdates.length > 0 ? deferredPendingUpdates : pendingUpdates;
|
|
10002
10408
|
const activityFrame = useAnimatedFrame(busy);
|
|
10003
10409
|
const terminalWidth = useTerminalWidth();
|
|
10004
10410
|
const contentWidth = insetWidth(terminalWidth, 2);
|
|
10005
10411
|
const panelInnerWidth = insetWidth(contentWidth, 4);
|
|
10006
10412
|
const panelBodyWidth = insetWidth(panelInnerWidth, 2);
|
|
10007
|
-
const [agentQuestion, setAgentQuestion] =
|
|
10413
|
+
const [agentQuestion, setAgentQuestion] = useState7(null);
|
|
10008
10414
|
const previewRef = useRef2(null);
|
|
10009
10415
|
const ctrlCTimerRef = useRef2(null);
|
|
10010
|
-
const isHome =
|
|
10011
|
-
const { staticMessages, dynamicMessages } =
|
|
10012
|
-
() => splitMessagesForRender(
|
|
10013
|
-
[busy,
|
|
10416
|
+
const isHome = messages.length === 0 && !busy;
|
|
10417
|
+
const { staticMessages, dynamicMessages } = useMemo4(
|
|
10418
|
+
() => splitMessagesForRender(messages, busy),
|
|
10419
|
+
[busy, messages]
|
|
10420
|
+
);
|
|
10421
|
+
const staticRenderItems = useMemo4(
|
|
10422
|
+
() => renderConversationMessages(staticMessages, toolActivityExpanded, contentWidth),
|
|
10423
|
+
[contentWidth, staticMessages, toolActivityExpanded]
|
|
10424
|
+
);
|
|
10425
|
+
const dynamicRenderItems = useMemo4(
|
|
10426
|
+
() => renderConversationMessages(dynamicMessages, toolActivityExpanded, contentWidth),
|
|
10427
|
+
[contentWidth, dynamicMessages, toolActivityExpanded]
|
|
10428
|
+
);
|
|
10429
|
+
const showThinking = busy && (messages.length === 0 || messages[messages.length - 1]?.role !== "assistant");
|
|
10430
|
+
const activeToolDescriptions = useMemo4(
|
|
10431
|
+
() => Object.values(activeToolActivities),
|
|
10432
|
+
[activeToolActivities]
|
|
10433
|
+
);
|
|
10434
|
+
const currentToolActivity = useMemo4(() => {
|
|
10435
|
+
if (activeToolDescriptions.length === 0) {
|
|
10436
|
+
return "";
|
|
10437
|
+
}
|
|
10438
|
+
if (activeToolDescriptions.length === 1 && turnToolCount === 0) {
|
|
10439
|
+
return activeToolDescriptions[0] ?? "";
|
|
10440
|
+
}
|
|
10441
|
+
if (activeToolDescriptions.length === 1) {
|
|
10442
|
+
return "Running 1 tool";
|
|
10443
|
+
}
|
|
10444
|
+
return `Running ${activeToolDescriptions.length} tools in parallel`;
|
|
10445
|
+
}, [activeToolDescriptions, turnToolCount]);
|
|
10446
|
+
useEffect4(() => {
|
|
10447
|
+
if (!busy) {
|
|
10448
|
+
setLatchedToolActivity("");
|
|
10449
|
+
setLatchedToolCount(0);
|
|
10450
|
+
return;
|
|
10451
|
+
}
|
|
10452
|
+
if (!currentToolActivity) {
|
|
10453
|
+
return;
|
|
10454
|
+
}
|
|
10455
|
+
setLatchedToolActivity(currentToolActivity);
|
|
10456
|
+
setLatchedToolCount(turnToolCount);
|
|
10457
|
+
}, [busy, currentToolActivity, turnToolCount]);
|
|
10458
|
+
const visibleSubAgents = useMemo4(
|
|
10459
|
+
() => Object.values(subAgentProgress),
|
|
10460
|
+
[subAgentProgress]
|
|
10014
10461
|
);
|
|
10015
10462
|
const hasWorkspace = workspacePath !== null;
|
|
10016
10463
|
const hasAuth = authStatus === "connected";
|
|
@@ -10023,7 +10470,7 @@ function App({
|
|
|
10023
10470
|
const pending = getPendingQuestion();
|
|
10024
10471
|
if (pending && (!agentQuestion || pending.question.id !== agentQuestion.question.id)) {
|
|
10025
10472
|
setAgentQuestion(pending);
|
|
10026
|
-
setComposerFocused(
|
|
10473
|
+
setComposerFocused(false);
|
|
10027
10474
|
}
|
|
10028
10475
|
}, 200);
|
|
10029
10476
|
return () => clearInterval(interval);
|
|
@@ -10078,15 +10525,16 @@ function App({
|
|
|
10078
10525
|
}
|
|
10079
10526
|
};
|
|
10080
10527
|
}, []);
|
|
10081
|
-
const [selectedSuggestion, setSelectedSuggestion] =
|
|
10082
|
-
const atMention =
|
|
10083
|
-
const
|
|
10528
|
+
const [selectedSuggestion, setSelectedSuggestion] = useState7(-1);
|
|
10529
|
+
const atMention = useMemo4(() => extractAtMention(input2), [input2]);
|
|
10530
|
+
const slashTrigger = useMemo4(() => extractSlashTrigger(input2), [input2]);
|
|
10531
|
+
const suggestions = useMemo4(() => {
|
|
10084
10532
|
if (atMention) {
|
|
10085
10533
|
return getFileSuggestions(atMention.partial, workspaceFiles);
|
|
10086
10534
|
}
|
|
10087
|
-
if (!
|
|
10088
|
-
return getUnifiedSuggestions(
|
|
10089
|
-
}, [input2, skills2, atMention, workspaceFiles]);
|
|
10535
|
+
if (!slashTrigger) return [];
|
|
10536
|
+
return getUnifiedSuggestions(`/${slashTrigger.partial}`, skills2);
|
|
10537
|
+
}, [input2, skills2, atMention, slashTrigger, workspaceFiles]);
|
|
10090
10538
|
useEffect4(() => {
|
|
10091
10539
|
setSelectedSuggestion(-1);
|
|
10092
10540
|
}, [suggestions.length, input2]);
|
|
@@ -10095,8 +10543,9 @@ function App({
|
|
|
10095
10543
|
if (s.kind === "file" && atMention) {
|
|
10096
10544
|
const before = input2.slice(0, atMention.start);
|
|
10097
10545
|
setInput(`${before}@${s.path} `);
|
|
10098
|
-
} else if (s.kind === "command" || s.kind === "skill") {
|
|
10099
|
-
|
|
10546
|
+
} else if ((s.kind === "command" || s.kind === "skill") && slashTrigger) {
|
|
10547
|
+
const before = input2.slice(0, slashTrigger.start);
|
|
10548
|
+
setInput(`${before}/${s.name}`);
|
|
10100
10549
|
}
|
|
10101
10550
|
setSelectedSuggestion(-1);
|
|
10102
10551
|
setCursorToEnd((c) => c + 1);
|
|
@@ -10153,10 +10602,8 @@ function App({
|
|
|
10153
10602
|
});
|
|
10154
10603
|
}
|
|
10155
10604
|
function replaceMessages(nextMessages) {
|
|
10156
|
-
|
|
10157
|
-
|
|
10158
|
-
setMessages(nextMessages);
|
|
10159
|
-
});
|
|
10605
|
+
setMessages(nextMessages);
|
|
10606
|
+
setMessageRenderVersion((current) => current + 1);
|
|
10160
10607
|
}
|
|
10161
10608
|
const slashCtx = {
|
|
10162
10609
|
homeDir,
|
|
@@ -10220,6 +10667,19 @@ function App({
|
|
|
10220
10667
|
addSystemMessage(`Rejected: ${next.summary}`);
|
|
10221
10668
|
});
|
|
10222
10669
|
}
|
|
10670
|
+
function feedbackOnPendingUpdate(feedback) {
|
|
10671
|
+
if (pendingUpdates.length === 0 || !workspacePath) return;
|
|
10672
|
+
const [next, ...rest] = pendingUpdates;
|
|
10673
|
+
void appendSessionEvent(workspacePath, sessionId2, {
|
|
10674
|
+
type: "update.rejected",
|
|
10675
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10676
|
+
payload: { key: next.key, summary: next.summary, feedback }
|
|
10677
|
+
});
|
|
10678
|
+
startTransition2(() => {
|
|
10679
|
+
setPendingUpdates(rest);
|
|
10680
|
+
addSystemMessage(`Feedback on "${next.summary}": ${feedback}`);
|
|
10681
|
+
});
|
|
10682
|
+
}
|
|
10223
10683
|
function clearCtrlCPending() {
|
|
10224
10684
|
if (ctrlCTimerRef.current) {
|
|
10225
10685
|
clearTimeout(ctrlCTimerRef.current);
|
|
@@ -10295,13 +10755,12 @@ function App({
|
|
|
10295
10755
|
setPlanningState({ status: "idle", planningHistory: [] });
|
|
10296
10756
|
addSystemMessage("Charter cancelled. Planning reset.");
|
|
10297
10757
|
}
|
|
10298
|
-
|
|
10758
|
+
useInput5((key, inputKey) => {
|
|
10299
10759
|
if (inputKey.ctrl && key === "c") {
|
|
10300
10760
|
if (busy) {
|
|
10301
10761
|
clearCtrlCPending();
|
|
10302
10762
|
if (abortRef.current) {
|
|
10303
10763
|
abortRef.current.abort();
|
|
10304
|
-
addSystemMessage("Interrupting agent...");
|
|
10305
10764
|
}
|
|
10306
10765
|
return;
|
|
10307
10766
|
}
|
|
@@ -10347,7 +10806,6 @@ function App({
|
|
|
10347
10806
|
if (inputKey.escape) {
|
|
10348
10807
|
if (busy && abortRef.current) {
|
|
10349
10808
|
abortRef.current.abort();
|
|
10350
|
-
addSystemMessage("Interrupting agent...");
|
|
10351
10809
|
} else if (planningState.status === "charter-review") {
|
|
10352
10810
|
rejectCharter();
|
|
10353
10811
|
} else {
|
|
@@ -10368,14 +10826,7 @@ function App({
|
|
|
10368
10826
|
return;
|
|
10369
10827
|
}
|
|
10370
10828
|
}
|
|
10371
|
-
if (
|
|
10372
|
-
void acceptNextPendingUpdate();
|
|
10373
|
-
return;
|
|
10374
|
-
}
|
|
10375
|
-
if (key === "r" && pendingUpdates.length > 0) {
|
|
10376
|
-
rejectNextPendingUpdate();
|
|
10377
|
-
return;
|
|
10378
|
-
}
|
|
10829
|
+
if (pendingUpdates.length > 0 && !agentQuestion || agentQuestion) return;
|
|
10379
10830
|
if (key === "i" || key.length === 1 && !inputKey.ctrl && !inputKey.meta && !inputKey.tab) {
|
|
10380
10831
|
setComposerFocused(true);
|
|
10381
10832
|
if (key !== "i") setInput((c) => c + key);
|
|
@@ -10387,24 +10838,9 @@ function App({
|
|
|
10387
10838
|
if (handleDropdownSelect()) return;
|
|
10388
10839
|
const trimmed = value.trim();
|
|
10389
10840
|
if (!trimmed) return;
|
|
10390
|
-
if (agentQuestion)
|
|
10391
|
-
const options = agentQuestion.question.options;
|
|
10392
|
-
const numChoice = parseInt(trimmed, 10);
|
|
10393
|
-
if (!isNaN(numChoice) && numChoice >= 1 && numChoice <= options.length) {
|
|
10394
|
-
const picked = options[numChoice - 1];
|
|
10395
|
-
addSystemMessage(`> ${picked.label}`);
|
|
10396
|
-
agentQuestion.resolve({ questionId: agentQuestion.question.id, answer: picked.label, isCustom: false });
|
|
10397
|
-
} else {
|
|
10398
|
-
addSystemMessage(`> ${trimmed}`);
|
|
10399
|
-
agentQuestion.resolve({ questionId: agentQuestion.question.id, answer: trimmed, isCustom: true });
|
|
10400
|
-
}
|
|
10401
|
-
clearPendingQuestion();
|
|
10402
|
-
setAgentQuestion(null);
|
|
10403
|
-
setInput("");
|
|
10404
|
-
return;
|
|
10405
|
-
}
|
|
10841
|
+
if (agentQuestion) return;
|
|
10406
10842
|
if (busy) return;
|
|
10407
|
-
if (
|
|
10843
|
+
if (dropdownVisible && applyAutocomplete()) {
|
|
10408
10844
|
return;
|
|
10409
10845
|
}
|
|
10410
10846
|
setInput("");
|
|
@@ -10447,9 +10883,14 @@ function App({
|
|
|
10447
10883
|
if (!workspacePath) return;
|
|
10448
10884
|
turnToolLogRef.current = [];
|
|
10449
10885
|
setTurnToolCount(0);
|
|
10450
|
-
|
|
10886
|
+
setLatchedToolActivity("");
|
|
10887
|
+
setLatchedToolCount(0);
|
|
10888
|
+
setActiveToolActivities({});
|
|
10889
|
+
setSubAgentProgress({});
|
|
10451
10890
|
const controller = new AbortController();
|
|
10452
10891
|
let streamBuffer = null;
|
|
10892
|
+
let focusPendingReviewOnComplete = false;
|
|
10893
|
+
const postTurnNotices = [];
|
|
10453
10894
|
abortRef.current = controller;
|
|
10454
10895
|
setBusy(true);
|
|
10455
10896
|
startTransition2(() => {
|
|
@@ -10485,13 +10926,22 @@ function App({
|
|
|
10485
10926
|
onTextDelta: (chunk) => {
|
|
10486
10927
|
assistantText += chunk;
|
|
10487
10928
|
streamBuffer?.push(chunk);
|
|
10929
|
+
setLatchedToolActivity("");
|
|
10930
|
+
setLatchedToolCount(0);
|
|
10488
10931
|
},
|
|
10489
10932
|
onToolActivity: (activity) => {
|
|
10490
10933
|
streamBuffer?.flush();
|
|
10491
10934
|
if (activity.type === "tool_start") {
|
|
10492
|
-
|
|
10935
|
+
setActiveToolActivities((current) => ({
|
|
10936
|
+
...current,
|
|
10937
|
+
[activity.toolCallId]: activity.description ?? activity.name
|
|
10938
|
+
}));
|
|
10493
10939
|
} else {
|
|
10494
|
-
|
|
10940
|
+
setActiveToolActivities((current) => {
|
|
10941
|
+
const next = { ...current };
|
|
10942
|
+
delete next[activity.toolCallId];
|
|
10943
|
+
return next;
|
|
10944
|
+
});
|
|
10495
10945
|
turnToolLogRef.current.push({
|
|
10496
10946
|
name: activity.name,
|
|
10497
10947
|
description: activity.description ?? activity.name,
|
|
@@ -10505,9 +10955,16 @@ function App({
|
|
|
10505
10955
|
},
|
|
10506
10956
|
onSubAgentProgress: (progress) => {
|
|
10507
10957
|
if (progress.status === "done") {
|
|
10508
|
-
setSubAgentProgress(
|
|
10958
|
+
setSubAgentProgress((current) => {
|
|
10959
|
+
const next = { ...current };
|
|
10960
|
+
delete next[progress.agentId];
|
|
10961
|
+
return next;
|
|
10962
|
+
});
|
|
10509
10963
|
} else {
|
|
10510
|
-
setSubAgentProgress(
|
|
10964
|
+
setSubAgentProgress((current) => ({
|
|
10965
|
+
...current,
|
|
10966
|
+
[progress.agentId]: { ...progress }
|
|
10967
|
+
}));
|
|
10511
10968
|
}
|
|
10512
10969
|
},
|
|
10513
10970
|
onMemoryExtracted: (mems) => {
|
|
@@ -10529,7 +10986,9 @@ function App({
|
|
|
10529
10986
|
streamBuffer.flush();
|
|
10530
10987
|
if (turnToolLogRef.current.length > 0) {
|
|
10531
10988
|
const summary = buildToolSummary(turnToolLogRef.current);
|
|
10532
|
-
|
|
10989
|
+
postTurnNotices.push(
|
|
10990
|
+
`__tool_summary__${JSON.stringify({ summary, tools: turnToolLogRef.current })}`
|
|
10991
|
+
);
|
|
10533
10992
|
turnToolLogRef.current = [];
|
|
10534
10993
|
}
|
|
10535
10994
|
startTransition2(() => {
|
|
@@ -10554,7 +11013,8 @@ function App({
|
|
|
10554
11013
|
}
|
|
10555
11014
|
}
|
|
10556
11015
|
if (reviewRequired.length > 0) {
|
|
10557
|
-
|
|
11016
|
+
focusPendingReviewOnComplete = true;
|
|
11017
|
+
setPendingUpdates((current) => [...current, ...reviewRequired]);
|
|
10558
11018
|
}
|
|
10559
11019
|
await appendSessionEvent(workspacePath, sessionId2, {
|
|
10560
11020
|
type: "chat.turn",
|
|
@@ -10586,10 +11046,18 @@ ${error.stack}` : String(error)}` }
|
|
|
10586
11046
|
} finally {
|
|
10587
11047
|
streamBuffer?.dispose();
|
|
10588
11048
|
abortRef.current = null;
|
|
11049
|
+
setActiveToolActivities({});
|
|
11050
|
+
setSubAgentProgress({});
|
|
10589
11051
|
setBusy(false);
|
|
10590
|
-
setComposerFocused(
|
|
11052
|
+
setComposerFocused(!focusPendingReviewOnComplete);
|
|
11053
|
+
if (controller.signal.aborted) {
|
|
11054
|
+
postTurnNotices.push("Interrupting agent...\nAgent interrupted.");
|
|
11055
|
+
}
|
|
11056
|
+
for (const notice of postTurnNotices) {
|
|
11057
|
+
addSystemMessage(notice);
|
|
11058
|
+
}
|
|
10591
11059
|
if (controller.signal.aborted) {
|
|
10592
|
-
|
|
11060
|
+
return;
|
|
10593
11061
|
}
|
|
10594
11062
|
}
|
|
10595
11063
|
}
|
|
@@ -10694,10 +11162,10 @@ ${error.stack}` : String(error)}` }
|
|
|
10694
11162
|
else statusParts.push("no workspace");
|
|
10695
11163
|
if (skills2.length > 0) statusParts.push(`${skills2.length} skills`);
|
|
10696
11164
|
statusParts.push(agentMode);
|
|
10697
|
-
if (
|
|
11165
|
+
if (pendingUpdates.length > 0) statusParts.push(`${pendingUpdates.length} pending`);
|
|
10698
11166
|
const themeColors = getThemeColors(theme);
|
|
10699
|
-
const statusColor = busy ? themeColors.warning : ctrlCPending ? themeColors.warning : !hasAuth ? themeColors.error :
|
|
10700
|
-
const configItems =
|
|
11167
|
+
const statusColor = busy ? themeColors.warning : ctrlCPending ? themeColors.warning : !hasAuth ? themeColors.error : pendingUpdates.length > 0 ? themeColors.pending : themeColors.secondary;
|
|
11168
|
+
const configItems = useMemo4(() => [
|
|
10701
11169
|
{ key: "defaults.model", label: "Model", values: [...getAvailableModels()], current: config?.defaults.model ?? "gpt-5.4" },
|
|
10702
11170
|
{ key: "theme", label: "Theme", values: [...themeValues], current: theme },
|
|
10703
11171
|
{ key: "defaults.reasoningEffort", label: "Reasoning effort", values: ["low", "medium", "high", "xhigh"], current: config?.defaults.reasoningEffort ?? "medium" },
|
|
@@ -10731,11 +11199,8 @@ ${error.stack}` : String(error)}` }
|
|
|
10731
11199
|
onSelect: async (session) => {
|
|
10732
11200
|
try {
|
|
10733
11201
|
const restored = await loadSessionHistory(workspacePath, session.id);
|
|
10734
|
-
|
|
10735
|
-
|
|
10736
|
-
setMessages(restored.messages);
|
|
10737
|
-
setHistory(restored.llmHistory);
|
|
10738
|
-
});
|
|
11202
|
+
replaceMessages(restored.messages);
|
|
11203
|
+
startTransition2(() => setHistory(restored.llmHistory));
|
|
10739
11204
|
addSystemMessage(`Resumed session (${session.turnCount} turns). Continue where you left off.`);
|
|
10740
11205
|
} catch (err) {
|
|
10741
11206
|
addSystemMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -10768,23 +11233,28 @@ ${error.stack}` : String(error)}` }
|
|
|
10768
11233
|
width: contentWidth
|
|
10769
11234
|
}
|
|
10770
11235
|
),
|
|
10771
|
-
|
|
10772
|
-
|
|
10773
|
-
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
|
|
10777
|
-
|
|
11236
|
+
staticRenderItems.length > 0 && /* @__PURE__ */ jsx6(
|
|
11237
|
+
Static,
|
|
11238
|
+
{
|
|
11239
|
+
items: staticRenderItems,
|
|
11240
|
+
children: (item, index) => /* @__PURE__ */ jsx6(React6.Fragment, { children: item }, `conversation-static-item-${messageRenderVersion}-${index}`)
|
|
11241
|
+
},
|
|
11242
|
+
`conversation-static-${messageRenderVersion}`
|
|
11243
|
+
),
|
|
11244
|
+
dynamicRenderItems.length > 0 && /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", marginBottom: 1, width: contentWidth, children: dynamicRenderItems }),
|
|
11245
|
+
showThinking && /* @__PURE__ */ jsx6(ThinkingIndicator, { frame: activityFrame, width: contentWidth }),
|
|
11246
|
+
visibleSubAgents.map((progress) => /* @__PURE__ */ jsx6(
|
|
10778
11247
|
SubAgentIndicator,
|
|
10779
11248
|
{
|
|
10780
|
-
agentType:
|
|
10781
|
-
goal:
|
|
10782
|
-
currentTool:
|
|
10783
|
-
toolCount:
|
|
11249
|
+
agentType: progress.agentType,
|
|
11250
|
+
goal: progress.goal,
|
|
11251
|
+
currentTool: progress.currentTool,
|
|
11252
|
+
toolCount: progress.toolCount,
|
|
10784
11253
|
frame: activityFrame,
|
|
10785
11254
|
width: contentWidth
|
|
10786
|
-
}
|
|
10787
|
-
|
|
11255
|
+
},
|
|
11256
|
+
progress.agentId
|
|
11257
|
+
)),
|
|
10788
11258
|
taskPanelVisible && getVisibleTasks().length > 0 && /* @__PURE__ */ jsx6(
|
|
10789
11259
|
TaskPanel,
|
|
10790
11260
|
{
|
|
@@ -10793,11 +11263,28 @@ ${error.stack}` : String(error)}` }
|
|
|
10793
11263
|
width: contentWidth
|
|
10794
11264
|
}
|
|
10795
11265
|
),
|
|
10796
|
-
|
|
11266
|
+
visiblePendingUpdates.length > 0 && /* @__PURE__ */ jsx6(
|
|
10797
11267
|
PendingUpdateCard,
|
|
10798
11268
|
{
|
|
10799
|
-
count:
|
|
10800
|
-
summary: truncate3(
|
|
11269
|
+
count: pendingUpdates.length,
|
|
11270
|
+
summary: truncate3(visiblePendingUpdates[0].summary, Math.max(24, insetWidth(contentWidth, 8))),
|
|
11271
|
+
fileName: visiblePendingUpdates[0].key,
|
|
11272
|
+
updateType: visiblePendingUpdates[0].type,
|
|
11273
|
+
oldContent: visiblePendingUpdates[0].oldContent,
|
|
11274
|
+
newContent: visiblePendingUpdates[0].content,
|
|
11275
|
+
active: !composerFocused && !agentQuestion,
|
|
11276
|
+
onAccept: () => {
|
|
11277
|
+
void acceptNextPendingUpdate();
|
|
11278
|
+
if (pendingUpdates.length <= 1) setComposerFocused(true);
|
|
11279
|
+
},
|
|
11280
|
+
onReject: () => {
|
|
11281
|
+
rejectNextPendingUpdate();
|
|
11282
|
+
if (pendingUpdates.length <= 1) setComposerFocused(true);
|
|
11283
|
+
},
|
|
11284
|
+
onFeedback: (fb) => {
|
|
11285
|
+
feedbackOnPendingUpdate(fb);
|
|
11286
|
+
if (pendingUpdates.length <= 1) setComposerFocused(true);
|
|
11287
|
+
},
|
|
10801
11288
|
width: contentWidth
|
|
10802
11289
|
}
|
|
10803
11290
|
),
|
|
@@ -10841,7 +11328,23 @@ ${error.stack}` : String(error)}` }
|
|
|
10841
11328
|
] }) })
|
|
10842
11329
|
] }),
|
|
10843
11330
|
dropdownVisible && /* @__PURE__ */ jsx6(SuggestionDropdown, { width: contentWidth, items: suggestions, selectedIndex: selectedSuggestion }),
|
|
10844
|
-
agentQuestion && /* @__PURE__ */ jsx6(
|
|
11331
|
+
agentQuestion && /* @__PURE__ */ jsx6(
|
|
11332
|
+
QuestionCard,
|
|
11333
|
+
{
|
|
11334
|
+
width: contentWidth,
|
|
11335
|
+
question: agentQuestion.question.question,
|
|
11336
|
+
options: agentQuestion.question.options,
|
|
11337
|
+
active: !composerFocused,
|
|
11338
|
+
onSelect: (answer, isCustom) => {
|
|
11339
|
+
addSystemMessage(`> ${answer}`);
|
|
11340
|
+
agentQuestion.resolve({ questionId: agentQuestion.question.id, answer, isCustom });
|
|
11341
|
+
clearPendingQuestion();
|
|
11342
|
+
const nextQuestion = getPendingQuestion();
|
|
11343
|
+
setAgentQuestion(nextQuestion);
|
|
11344
|
+
setComposerFocused(nextQuestion === null);
|
|
11345
|
+
}
|
|
11346
|
+
}
|
|
11347
|
+
),
|
|
10845
11348
|
/* @__PURE__ */ jsx6(Box5, { borderStyle: "round", borderColor: agentQuestion ? themeColors.warning : composerFocused ? themeColors.borderFocused : themeColors.borderDefault, paddingX: 1, flexDirection: "column", width: contentWidth, children: /* @__PURE__ */ jsxs4(Box5, { children: [
|
|
10846
11349
|
/* @__PURE__ */ jsx6(PromptPrefix, { busy, frame: activityFrame, hasQuestion: !!agentQuestion, mode: agentMode }),
|
|
10847
11350
|
/* @__PURE__ */ jsx6(
|
|
@@ -10857,7 +11360,7 @@ ${error.stack}` : String(error)}` }
|
|
|
10857
11360
|
cursorToEnd,
|
|
10858
11361
|
accentColor: themeColors.accent,
|
|
10859
11362
|
mutedColor: themeColors.muted,
|
|
10860
|
-
placeholder: agentQuestion ? "
|
|
11363
|
+
placeholder: agentQuestion ? "Answer in the card above" : !hasAuth ? "Type /auth or /config apikey" : !hasWorkspace ? "Type /init to create workspace" : pendingUpdates.length > 0 && composerFocused ? "Esc to review updates, or keep drafting" : busy ? "Draft your next message while the agent works" : "Ask a question or type / for commands"
|
|
10861
11364
|
}
|
|
10862
11365
|
)
|
|
10863
11366
|
] }) }),
|
|
@@ -10873,8 +11376,8 @@ ${error.stack}` : String(error)}` }
|
|
|
10873
11376
|
width: contentWidth,
|
|
10874
11377
|
busy,
|
|
10875
11378
|
frame: activityFrame,
|
|
10876
|
-
toolActivity: currentToolActivity,
|
|
10877
|
-
toolCount: turnToolCount,
|
|
11379
|
+
toolActivity: currentToolActivity || latchedToolActivity,
|
|
11380
|
+
toolCount: currentToolActivity ? turnToolCount : latchedToolCount,
|
|
10878
11381
|
statusParts,
|
|
10879
11382
|
statusColor,
|
|
10880
11383
|
tokenDisplay,
|
|
@@ -10886,6 +11389,35 @@ ${error.stack}` : String(error)}` }
|
|
|
10886
11389
|
] }) });
|
|
10887
11390
|
}
|
|
10888
11391
|
|
|
11392
|
+
// src/tui/ink-stdout.ts
|
|
11393
|
+
function getStableDimension(current, fallback) {
|
|
11394
|
+
return typeof current === "number" && current > 0 ? current : fallback;
|
|
11395
|
+
}
|
|
11396
|
+
function createStableInkStdout(stdout, options) {
|
|
11397
|
+
const forceFullRedraw = options?.forceFullRedraw ?? process.env.OPEN_RESEARCH_FORCE_FULL_REDRAW === "1";
|
|
11398
|
+
let lastRows = getStableDimension(stdout.rows, 24);
|
|
11399
|
+
let lastColumns = getStableDimension(stdout.columns, 80);
|
|
11400
|
+
return new Proxy(stdout, {
|
|
11401
|
+
get(target, prop, receiver) {
|
|
11402
|
+
if (prop === "rows") {
|
|
11403
|
+
if (forceFullRedraw) {
|
|
11404
|
+
return 0;
|
|
11405
|
+
}
|
|
11406
|
+
const rows = Reflect.get(target, prop, receiver);
|
|
11407
|
+
lastRows = getStableDimension(rows, lastRows);
|
|
11408
|
+
return lastRows;
|
|
11409
|
+
}
|
|
11410
|
+
if (prop === "columns") {
|
|
11411
|
+
const columns = Reflect.get(target, prop, receiver);
|
|
11412
|
+
lastColumns = getStableDimension(columns, lastColumns);
|
|
11413
|
+
return lastColumns;
|
|
11414
|
+
}
|
|
11415
|
+
const value = Reflect.get(target, prop, receiver);
|
|
11416
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
11417
|
+
}
|
|
11418
|
+
});
|
|
11419
|
+
}
|
|
11420
|
+
|
|
10889
11421
|
// src/cli.ts
|
|
10890
11422
|
var program = new Command();
|
|
10891
11423
|
program.name("open-research").version(getPackageVersion()).description("Local-first research CLI powered by OpenAI account auth or API keys.").argument("[workspacePath]", "Optional workspace path to open").action(async (workspacePath) => {
|
|
@@ -10894,7 +11426,7 @@ program.name("open-research").version(getPackageVersion()).description("Local-fi
|
|
|
10894
11426
|
const project = await loadWorkspaceProject(target);
|
|
10895
11427
|
const hasProvider = await hasConfiguredProvider();
|
|
10896
11428
|
render(
|
|
10897
|
-
|
|
11429
|
+
React7.createElement(App, {
|
|
10898
11430
|
initialState: {
|
|
10899
11431
|
authStatus: hasProvider ? "connected" : "missing",
|
|
10900
11432
|
workspacePath: project ? target : null,
|
|
@@ -10902,7 +11434,10 @@ program.name("open-research").version(getPackageVersion()).description("Local-fi
|
|
|
10902
11434
|
pendingUpdates: []
|
|
10903
11435
|
}
|
|
10904
11436
|
}),
|
|
10905
|
-
{
|
|
11437
|
+
{
|
|
11438
|
+
exitOnCtrlC: false,
|
|
11439
|
+
stdout: createStableInkStdout(process.stdout)
|
|
11440
|
+
}
|
|
10906
11441
|
);
|
|
10907
11442
|
});
|
|
10908
11443
|
program.command("init").argument("[workspacePath]").description("Initialize an Open Research workspace.").action(async (workspacePath) => {
|