open-research 1.0.1 → 1.1.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/cli.js +797 -287
- package/package.json +3 -1
package/dist/cli.js
CHANGED
|
@@ -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.0
|
|
831
|
+
var PACKAGE_VERSION = "1.1.0";
|
|
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 {
|
|
@@ -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,
|
|
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,
|
|
8278
8389
|
" ",
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
|
|
8282
|
-
dur
|
|
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
|
+
});
|
|
8751
9124
|
};
|
|
8752
|
-
|
|
9125
|
+
const scheduleWidthUpdate = () => {
|
|
9126
|
+
if (resizeTimer) {
|
|
9127
|
+
clearTimeout(resizeTimer);
|
|
9128
|
+
}
|
|
9129
|
+
resizeTimer = setTimeout(() => {
|
|
9130
|
+
resizeTimer = null;
|
|
9131
|
+
commitWidth();
|
|
9132
|
+
}, RESIZE_DEBOUNCE_MS);
|
|
9133
|
+
};
|
|
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
|
-
}
|
|
9951
|
-
if (message.role === "user") {
|
|
9952
|
-
return /* @__PURE__ */ jsx5(UserMessage, { text: message.text, width }, key);
|
|
9953
10357
|
}
|
|
9954
|
-
return
|
|
10358
|
+
return elements;
|
|
9955
10359
|
}
|
|
9956
10360
|
|
|
9957
10361
|
// src/tui/app.tsx
|
|
@@ -9962,55 +10366,84 @@ 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 [taskVersion, setTaskVersion] = useState6(0);
|
|
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 [subAgentProgress, setSubAgentProgress] = useState7({});
|
|
10384
|
+
const [toolActivityExpanded, setToolActivityExpanded] = useState7(false);
|
|
10385
|
+
const [taskPanelVisible, setTaskPanelVisible] = useState7(true);
|
|
10386
|
+
const [taskVersion, setTaskVersion] = useState7(0);
|
|
9984
10387
|
const turnToolLogRef = useRef2([]);
|
|
9985
|
-
const [sessionTokens, setSessionTokens] =
|
|
9986
|
-
const [tokenDisplay, setTokenDisplay] =
|
|
9987
|
-
const [showSuggestions, setShowSuggestions] =
|
|
9988
|
-
const [agentMode, setAgentMode] =
|
|
9989
|
-
const [planningState, setPlanningState] =
|
|
10388
|
+
const [sessionTokens, setSessionTokens] = useState7(() => createSessionUsage());
|
|
10389
|
+
const [tokenDisplay, setTokenDisplay] = useState7("");
|
|
10390
|
+
const [showSuggestions, setShowSuggestions] = useState7(false);
|
|
10391
|
+
const [agentMode, setAgentMode] = useState7("manual-review");
|
|
10392
|
+
const [planningState, setPlanningState] = useState7({
|
|
9990
10393
|
status: "idle",
|
|
9991
10394
|
planningHistory: []
|
|
9992
10395
|
});
|
|
9993
|
-
const [theme, setTheme] =
|
|
9994
|
-
const [config, setConfig] =
|
|
9995
|
-
const [cursorToEnd, setCursorToEnd] =
|
|
9996
|
-
const [
|
|
9997
|
-
const [
|
|
9998
|
-
const [
|
|
9999
|
-
const
|
|
10000
|
-
const
|
|
10396
|
+
const [theme, setTheme] = useState7("dark");
|
|
10397
|
+
const [config, setConfig] = useState7(null);
|
|
10398
|
+
const [cursorToEnd, setCursorToEnd] = useState7(0);
|
|
10399
|
+
const [messageRenderVersion, setMessageRenderVersion] = useState7(0);
|
|
10400
|
+
const [screen, setScreen] = useState7("main");
|
|
10401
|
+
const [resumeSessions, setResumeSessions] = useState7([]);
|
|
10402
|
+
const [ctrlCPending, setCtrlCPending] = useState7(false);
|
|
10403
|
+
const sessionId2 = useMemo4(() => crypto.randomUUID(), []);
|
|
10001
10404
|
const deferredPendingUpdates = useDeferredValue(pendingUpdates);
|
|
10405
|
+
const visiblePendingUpdates = deferredPendingUpdates.length > 0 ? deferredPendingUpdates : pendingUpdates;
|
|
10002
10406
|
const activityFrame = useAnimatedFrame(busy);
|
|
10003
10407
|
const terminalWidth = useTerminalWidth();
|
|
10004
10408
|
const contentWidth = insetWidth(terminalWidth, 2);
|
|
10005
10409
|
const panelInnerWidth = insetWidth(contentWidth, 4);
|
|
10006
10410
|
const panelBodyWidth = insetWidth(panelInnerWidth, 2);
|
|
10007
|
-
const [agentQuestion, setAgentQuestion] =
|
|
10411
|
+
const [agentQuestion, setAgentQuestion] = useState7(null);
|
|
10008
10412
|
const previewRef = useRef2(null);
|
|
10009
10413
|
const ctrlCTimerRef = useRef2(null);
|
|
10010
|
-
const isHome =
|
|
10011
|
-
const { staticMessages, dynamicMessages } =
|
|
10012
|
-
() => splitMessagesForRender(
|
|
10013
|
-
[busy,
|
|
10414
|
+
const isHome = messages.length === 0 && !busy;
|
|
10415
|
+
const { staticMessages, dynamicMessages } = useMemo4(
|
|
10416
|
+
() => splitMessagesForRender(messages, busy),
|
|
10417
|
+
[busy, messages]
|
|
10418
|
+
);
|
|
10419
|
+
const staticRenderItems = useMemo4(
|
|
10420
|
+
() => renderConversationMessages(staticMessages, toolActivityExpanded, contentWidth),
|
|
10421
|
+
[contentWidth, staticMessages, toolActivityExpanded]
|
|
10422
|
+
);
|
|
10423
|
+
const dynamicRenderItems = useMemo4(
|
|
10424
|
+
() => renderConversationMessages(dynamicMessages, toolActivityExpanded, contentWidth),
|
|
10425
|
+
[contentWidth, dynamicMessages, toolActivityExpanded]
|
|
10426
|
+
);
|
|
10427
|
+
const showThinking = busy && (messages.length === 0 || messages[messages.length - 1]?.role !== "assistant");
|
|
10428
|
+
const activeToolDescriptions = useMemo4(
|
|
10429
|
+
() => Object.values(activeToolActivities),
|
|
10430
|
+
[activeToolActivities]
|
|
10431
|
+
);
|
|
10432
|
+
const currentToolActivity = useMemo4(() => {
|
|
10433
|
+
if (activeToolDescriptions.length === 0) {
|
|
10434
|
+
return "";
|
|
10435
|
+
}
|
|
10436
|
+
if (activeToolDescriptions.length === 1 && turnToolCount === 0) {
|
|
10437
|
+
return activeToolDescriptions[0] ?? "";
|
|
10438
|
+
}
|
|
10439
|
+
if (activeToolDescriptions.length === 1) {
|
|
10440
|
+
return "Running 1 tool";
|
|
10441
|
+
}
|
|
10442
|
+
return `Running ${activeToolDescriptions.length} tools in parallel`;
|
|
10443
|
+
}, [activeToolDescriptions, turnToolCount]);
|
|
10444
|
+
const visibleSubAgents = useMemo4(
|
|
10445
|
+
() => Object.values(subAgentProgress),
|
|
10446
|
+
[subAgentProgress]
|
|
10014
10447
|
);
|
|
10015
10448
|
const hasWorkspace = workspacePath !== null;
|
|
10016
10449
|
const hasAuth = authStatus === "connected";
|
|
@@ -10023,7 +10456,7 @@ function App({
|
|
|
10023
10456
|
const pending = getPendingQuestion();
|
|
10024
10457
|
if (pending && (!agentQuestion || pending.question.id !== agentQuestion.question.id)) {
|
|
10025
10458
|
setAgentQuestion(pending);
|
|
10026
|
-
setComposerFocused(
|
|
10459
|
+
setComposerFocused(false);
|
|
10027
10460
|
}
|
|
10028
10461
|
}, 200);
|
|
10029
10462
|
return () => clearInterval(interval);
|
|
@@ -10078,15 +10511,16 @@ function App({
|
|
|
10078
10511
|
}
|
|
10079
10512
|
};
|
|
10080
10513
|
}, []);
|
|
10081
|
-
const [selectedSuggestion, setSelectedSuggestion] =
|
|
10082
|
-
const atMention =
|
|
10083
|
-
const
|
|
10514
|
+
const [selectedSuggestion, setSelectedSuggestion] = useState7(-1);
|
|
10515
|
+
const atMention = useMemo4(() => extractAtMention(input2), [input2]);
|
|
10516
|
+
const slashTrigger = useMemo4(() => extractSlashTrigger(input2), [input2]);
|
|
10517
|
+
const suggestions = useMemo4(() => {
|
|
10084
10518
|
if (atMention) {
|
|
10085
10519
|
return getFileSuggestions(atMention.partial, workspaceFiles);
|
|
10086
10520
|
}
|
|
10087
|
-
if (!
|
|
10088
|
-
return getUnifiedSuggestions(
|
|
10089
|
-
}, [input2, skills2, atMention, workspaceFiles]);
|
|
10521
|
+
if (!slashTrigger) return [];
|
|
10522
|
+
return getUnifiedSuggestions(`/${slashTrigger.partial}`, skills2);
|
|
10523
|
+
}, [input2, skills2, atMention, slashTrigger, workspaceFiles]);
|
|
10090
10524
|
useEffect4(() => {
|
|
10091
10525
|
setSelectedSuggestion(-1);
|
|
10092
10526
|
}, [suggestions.length, input2]);
|
|
@@ -10095,8 +10529,9 @@ function App({
|
|
|
10095
10529
|
if (s.kind === "file" && atMention) {
|
|
10096
10530
|
const before = input2.slice(0, atMention.start);
|
|
10097
10531
|
setInput(`${before}@${s.path} `);
|
|
10098
|
-
} else if (s.kind === "command" || s.kind === "skill") {
|
|
10099
|
-
|
|
10532
|
+
} else if ((s.kind === "command" || s.kind === "skill") && slashTrigger) {
|
|
10533
|
+
const before = input2.slice(0, slashTrigger.start);
|
|
10534
|
+
setInput(`${before}/${s.name}`);
|
|
10100
10535
|
}
|
|
10101
10536
|
setSelectedSuggestion(-1);
|
|
10102
10537
|
setCursorToEnd((c) => c + 1);
|
|
@@ -10153,10 +10588,8 @@ function App({
|
|
|
10153
10588
|
});
|
|
10154
10589
|
}
|
|
10155
10590
|
function replaceMessages(nextMessages) {
|
|
10156
|
-
|
|
10157
|
-
|
|
10158
|
-
setMessages(nextMessages);
|
|
10159
|
-
});
|
|
10591
|
+
setMessages(nextMessages);
|
|
10592
|
+
setMessageRenderVersion((current) => current + 1);
|
|
10160
10593
|
}
|
|
10161
10594
|
const slashCtx = {
|
|
10162
10595
|
homeDir,
|
|
@@ -10220,6 +10653,19 @@ function App({
|
|
|
10220
10653
|
addSystemMessage(`Rejected: ${next.summary}`);
|
|
10221
10654
|
});
|
|
10222
10655
|
}
|
|
10656
|
+
function feedbackOnPendingUpdate(feedback) {
|
|
10657
|
+
if (pendingUpdates.length === 0 || !workspacePath) return;
|
|
10658
|
+
const [next, ...rest] = pendingUpdates;
|
|
10659
|
+
void appendSessionEvent(workspacePath, sessionId2, {
|
|
10660
|
+
type: "update.rejected",
|
|
10661
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10662
|
+
payload: { key: next.key, summary: next.summary, feedback }
|
|
10663
|
+
});
|
|
10664
|
+
startTransition2(() => {
|
|
10665
|
+
setPendingUpdates(rest);
|
|
10666
|
+
addSystemMessage(`Feedback on "${next.summary}": ${feedback}`);
|
|
10667
|
+
});
|
|
10668
|
+
}
|
|
10223
10669
|
function clearCtrlCPending() {
|
|
10224
10670
|
if (ctrlCTimerRef.current) {
|
|
10225
10671
|
clearTimeout(ctrlCTimerRef.current);
|
|
@@ -10295,7 +10741,7 @@ function App({
|
|
|
10295
10741
|
setPlanningState({ status: "idle", planningHistory: [] });
|
|
10296
10742
|
addSystemMessage("Charter cancelled. Planning reset.");
|
|
10297
10743
|
}
|
|
10298
|
-
|
|
10744
|
+
useInput5((key, inputKey) => {
|
|
10299
10745
|
if (inputKey.ctrl && key === "c") {
|
|
10300
10746
|
if (busy) {
|
|
10301
10747
|
clearCtrlCPending();
|
|
@@ -10368,14 +10814,7 @@ function App({
|
|
|
10368
10814
|
return;
|
|
10369
10815
|
}
|
|
10370
10816
|
}
|
|
10371
|
-
if (
|
|
10372
|
-
void acceptNextPendingUpdate();
|
|
10373
|
-
return;
|
|
10374
|
-
}
|
|
10375
|
-
if (key === "r" && pendingUpdates.length > 0) {
|
|
10376
|
-
rejectNextPendingUpdate();
|
|
10377
|
-
return;
|
|
10378
|
-
}
|
|
10817
|
+
if (pendingUpdates.length > 0 && !agentQuestion || agentQuestion) return;
|
|
10379
10818
|
if (key === "i" || key.length === 1 && !inputKey.ctrl && !inputKey.meta && !inputKey.tab) {
|
|
10380
10819
|
setComposerFocused(true);
|
|
10381
10820
|
if (key !== "i") setInput((c) => c + key);
|
|
@@ -10387,24 +10826,9 @@ function App({
|
|
|
10387
10826
|
if (handleDropdownSelect()) return;
|
|
10388
10827
|
const trimmed = value.trim();
|
|
10389
10828
|
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
|
-
}
|
|
10829
|
+
if (agentQuestion) return;
|
|
10406
10830
|
if (busy) return;
|
|
10407
|
-
if (
|
|
10831
|
+
if (dropdownVisible && applyAutocomplete()) {
|
|
10408
10832
|
return;
|
|
10409
10833
|
}
|
|
10410
10834
|
setInput("");
|
|
@@ -10447,9 +10871,11 @@ function App({
|
|
|
10447
10871
|
if (!workspacePath) return;
|
|
10448
10872
|
turnToolLogRef.current = [];
|
|
10449
10873
|
setTurnToolCount(0);
|
|
10450
|
-
|
|
10874
|
+
setActiveToolActivities({});
|
|
10875
|
+
setSubAgentProgress({});
|
|
10451
10876
|
const controller = new AbortController();
|
|
10452
10877
|
let streamBuffer = null;
|
|
10878
|
+
let focusPendingReviewOnComplete = false;
|
|
10453
10879
|
abortRef.current = controller;
|
|
10454
10880
|
setBusy(true);
|
|
10455
10881
|
startTransition2(() => {
|
|
@@ -10489,9 +10915,16 @@ function App({
|
|
|
10489
10915
|
onToolActivity: (activity) => {
|
|
10490
10916
|
streamBuffer?.flush();
|
|
10491
10917
|
if (activity.type === "tool_start") {
|
|
10492
|
-
|
|
10918
|
+
setActiveToolActivities((current) => ({
|
|
10919
|
+
...current,
|
|
10920
|
+
[activity.toolCallId]: activity.description ?? activity.name
|
|
10921
|
+
}));
|
|
10493
10922
|
} else {
|
|
10494
|
-
|
|
10923
|
+
setActiveToolActivities((current) => {
|
|
10924
|
+
const next = { ...current };
|
|
10925
|
+
delete next[activity.toolCallId];
|
|
10926
|
+
return next;
|
|
10927
|
+
});
|
|
10495
10928
|
turnToolLogRef.current.push({
|
|
10496
10929
|
name: activity.name,
|
|
10497
10930
|
description: activity.description ?? activity.name,
|
|
@@ -10505,9 +10938,16 @@ function App({
|
|
|
10505
10938
|
},
|
|
10506
10939
|
onSubAgentProgress: (progress) => {
|
|
10507
10940
|
if (progress.status === "done") {
|
|
10508
|
-
setSubAgentProgress(
|
|
10941
|
+
setSubAgentProgress((current) => {
|
|
10942
|
+
const next = { ...current };
|
|
10943
|
+
delete next[progress.agentId];
|
|
10944
|
+
return next;
|
|
10945
|
+
});
|
|
10509
10946
|
} else {
|
|
10510
|
-
setSubAgentProgress(
|
|
10947
|
+
setSubAgentProgress((current) => ({
|
|
10948
|
+
...current,
|
|
10949
|
+
[progress.agentId]: { ...progress }
|
|
10950
|
+
}));
|
|
10511
10951
|
}
|
|
10512
10952
|
},
|
|
10513
10953
|
onMemoryExtracted: (mems) => {
|
|
@@ -10554,7 +10994,8 @@ function App({
|
|
|
10554
10994
|
}
|
|
10555
10995
|
}
|
|
10556
10996
|
if (reviewRequired.length > 0) {
|
|
10557
|
-
|
|
10997
|
+
focusPendingReviewOnComplete = true;
|
|
10998
|
+
setPendingUpdates((current) => [...current, ...reviewRequired]);
|
|
10558
10999
|
}
|
|
10559
11000
|
await appendSessionEvent(workspacePath, sessionId2, {
|
|
10560
11001
|
type: "chat.turn",
|
|
@@ -10586,8 +11027,10 @@ ${error.stack}` : String(error)}` }
|
|
|
10586
11027
|
} finally {
|
|
10587
11028
|
streamBuffer?.dispose();
|
|
10588
11029
|
abortRef.current = null;
|
|
11030
|
+
setActiveToolActivities({});
|
|
11031
|
+
setSubAgentProgress({});
|
|
10589
11032
|
setBusy(false);
|
|
10590
|
-
setComposerFocused(
|
|
11033
|
+
setComposerFocused(!focusPendingReviewOnComplete);
|
|
10591
11034
|
if (controller.signal.aborted) {
|
|
10592
11035
|
addSystemMessage("Agent interrupted.");
|
|
10593
11036
|
}
|
|
@@ -10694,10 +11137,10 @@ ${error.stack}` : String(error)}` }
|
|
|
10694
11137
|
else statusParts.push("no workspace");
|
|
10695
11138
|
if (skills2.length > 0) statusParts.push(`${skills2.length} skills`);
|
|
10696
11139
|
statusParts.push(agentMode);
|
|
10697
|
-
if (
|
|
11140
|
+
if (pendingUpdates.length > 0) statusParts.push(`${pendingUpdates.length} pending`);
|
|
10698
11141
|
const themeColors = getThemeColors(theme);
|
|
10699
|
-
const statusColor = busy ? themeColors.warning : ctrlCPending ? themeColors.warning : !hasAuth ? themeColors.error :
|
|
10700
|
-
const configItems =
|
|
11142
|
+
const statusColor = busy ? themeColors.warning : ctrlCPending ? themeColors.warning : !hasAuth ? themeColors.error : pendingUpdates.length > 0 ? themeColors.pending : themeColors.secondary;
|
|
11143
|
+
const configItems = useMemo4(() => [
|
|
10701
11144
|
{ key: "defaults.model", label: "Model", values: [...getAvailableModels()], current: config?.defaults.model ?? "gpt-5.4" },
|
|
10702
11145
|
{ key: "theme", label: "Theme", values: [...themeValues], current: theme },
|
|
10703
11146
|
{ key: "defaults.reasoningEffort", label: "Reasoning effort", values: ["low", "medium", "high", "xhigh"], current: config?.defaults.reasoningEffort ?? "medium" },
|
|
@@ -10731,11 +11174,8 @@ ${error.stack}` : String(error)}` }
|
|
|
10731
11174
|
onSelect: async (session) => {
|
|
10732
11175
|
try {
|
|
10733
11176
|
const restored = await loadSessionHistory(workspacePath, session.id);
|
|
10734
|
-
|
|
10735
|
-
|
|
10736
|
-
setMessages(restored.messages);
|
|
10737
|
-
setHistory(restored.llmHistory);
|
|
10738
|
-
});
|
|
11177
|
+
replaceMessages(restored.messages);
|
|
11178
|
+
startTransition2(() => setHistory(restored.llmHistory));
|
|
10739
11179
|
addSystemMessage(`Resumed session (${session.turnCount} turns). Continue where you left off.`);
|
|
10740
11180
|
} catch (err) {
|
|
10741
11181
|
addSystemMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -10768,23 +11208,28 @@ ${error.stack}` : String(error)}` }
|
|
|
10768
11208
|
width: contentWidth
|
|
10769
11209
|
}
|
|
10770
11210
|
),
|
|
10771
|
-
|
|
10772
|
-
|
|
10773
|
-
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
|
|
10777
|
-
|
|
11211
|
+
staticRenderItems.length > 0 && /* @__PURE__ */ jsx6(
|
|
11212
|
+
Static,
|
|
11213
|
+
{
|
|
11214
|
+
items: staticRenderItems,
|
|
11215
|
+
children: (item, index) => /* @__PURE__ */ jsx6(React6.Fragment, { children: item }, `conversation-static-item-${messageRenderVersion}-${index}`)
|
|
11216
|
+
},
|
|
11217
|
+
`conversation-static-${messageRenderVersion}`
|
|
11218
|
+
),
|
|
11219
|
+
dynamicRenderItems.length > 0 && /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", marginBottom: 1, width: contentWidth, children: dynamicRenderItems }),
|
|
11220
|
+
showThinking && /* @__PURE__ */ jsx6(ThinkingIndicator, { frame: activityFrame, width: contentWidth }),
|
|
11221
|
+
visibleSubAgents.map((progress) => /* @__PURE__ */ jsx6(
|
|
10778
11222
|
SubAgentIndicator,
|
|
10779
11223
|
{
|
|
10780
|
-
agentType:
|
|
10781
|
-
goal:
|
|
10782
|
-
currentTool:
|
|
10783
|
-
toolCount:
|
|
11224
|
+
agentType: progress.agentType,
|
|
11225
|
+
goal: progress.goal,
|
|
11226
|
+
currentTool: progress.currentTool,
|
|
11227
|
+
toolCount: progress.toolCount,
|
|
10784
11228
|
frame: activityFrame,
|
|
10785
11229
|
width: contentWidth
|
|
10786
|
-
}
|
|
10787
|
-
|
|
11230
|
+
},
|
|
11231
|
+
progress.agentId
|
|
11232
|
+
)),
|
|
10788
11233
|
taskPanelVisible && getVisibleTasks().length > 0 && /* @__PURE__ */ jsx6(
|
|
10789
11234
|
TaskPanel,
|
|
10790
11235
|
{
|
|
@@ -10793,11 +11238,28 @@ ${error.stack}` : String(error)}` }
|
|
|
10793
11238
|
width: contentWidth
|
|
10794
11239
|
}
|
|
10795
11240
|
),
|
|
10796
|
-
|
|
11241
|
+
visiblePendingUpdates.length > 0 && /* @__PURE__ */ jsx6(
|
|
10797
11242
|
PendingUpdateCard,
|
|
10798
11243
|
{
|
|
10799
|
-
count:
|
|
10800
|
-
summary: truncate3(
|
|
11244
|
+
count: pendingUpdates.length,
|
|
11245
|
+
summary: truncate3(visiblePendingUpdates[0].summary, Math.max(24, insetWidth(contentWidth, 8))),
|
|
11246
|
+
fileName: visiblePendingUpdates[0].key,
|
|
11247
|
+
updateType: visiblePendingUpdates[0].type,
|
|
11248
|
+
oldContent: visiblePendingUpdates[0].oldContent,
|
|
11249
|
+
newContent: visiblePendingUpdates[0].content,
|
|
11250
|
+
active: !composerFocused && !agentQuestion,
|
|
11251
|
+
onAccept: () => {
|
|
11252
|
+
void acceptNextPendingUpdate();
|
|
11253
|
+
if (pendingUpdates.length <= 1) setComposerFocused(true);
|
|
11254
|
+
},
|
|
11255
|
+
onReject: () => {
|
|
11256
|
+
rejectNextPendingUpdate();
|
|
11257
|
+
if (pendingUpdates.length <= 1) setComposerFocused(true);
|
|
11258
|
+
},
|
|
11259
|
+
onFeedback: (fb) => {
|
|
11260
|
+
feedbackOnPendingUpdate(fb);
|
|
11261
|
+
if (pendingUpdates.length <= 1) setComposerFocused(true);
|
|
11262
|
+
},
|
|
10801
11263
|
width: contentWidth
|
|
10802
11264
|
}
|
|
10803
11265
|
),
|
|
@@ -10841,7 +11303,23 @@ ${error.stack}` : String(error)}` }
|
|
|
10841
11303
|
] }) })
|
|
10842
11304
|
] }),
|
|
10843
11305
|
dropdownVisible && /* @__PURE__ */ jsx6(SuggestionDropdown, { width: contentWidth, items: suggestions, selectedIndex: selectedSuggestion }),
|
|
10844
|
-
agentQuestion && /* @__PURE__ */ jsx6(
|
|
11306
|
+
agentQuestion && /* @__PURE__ */ jsx6(
|
|
11307
|
+
QuestionCard,
|
|
11308
|
+
{
|
|
11309
|
+
width: contentWidth,
|
|
11310
|
+
question: agentQuestion.question.question,
|
|
11311
|
+
options: agentQuestion.question.options,
|
|
11312
|
+
active: !composerFocused,
|
|
11313
|
+
onSelect: (answer, isCustom) => {
|
|
11314
|
+
addSystemMessage(`> ${answer}`);
|
|
11315
|
+
agentQuestion.resolve({ questionId: agentQuestion.question.id, answer, isCustom });
|
|
11316
|
+
clearPendingQuestion();
|
|
11317
|
+
const nextQuestion = getPendingQuestion();
|
|
11318
|
+
setAgentQuestion(nextQuestion);
|
|
11319
|
+
setComposerFocused(nextQuestion === null);
|
|
11320
|
+
}
|
|
11321
|
+
}
|
|
11322
|
+
),
|
|
10845
11323
|
/* @__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
11324
|
/* @__PURE__ */ jsx6(PromptPrefix, { busy, frame: activityFrame, hasQuestion: !!agentQuestion, mode: agentMode }),
|
|
10847
11325
|
/* @__PURE__ */ jsx6(
|
|
@@ -10857,7 +11335,7 @@ ${error.stack}` : String(error)}` }
|
|
|
10857
11335
|
cursorToEnd,
|
|
10858
11336
|
accentColor: themeColors.accent,
|
|
10859
11337
|
mutedColor: themeColors.muted,
|
|
10860
|
-
placeholder: agentQuestion ? "
|
|
11338
|
+
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
11339
|
}
|
|
10862
11340
|
)
|
|
10863
11341
|
] }) }),
|
|
@@ -10886,6 +11364,35 @@ ${error.stack}` : String(error)}` }
|
|
|
10886
11364
|
] }) });
|
|
10887
11365
|
}
|
|
10888
11366
|
|
|
11367
|
+
// src/tui/ink-stdout.ts
|
|
11368
|
+
function getStableDimension(current, fallback) {
|
|
11369
|
+
return typeof current === "number" && current > 0 ? current : fallback;
|
|
11370
|
+
}
|
|
11371
|
+
function createStableInkStdout(stdout, options) {
|
|
11372
|
+
const forceFullRedraw = options?.forceFullRedraw ?? process.env.OPEN_RESEARCH_FORCE_FULL_REDRAW === "1";
|
|
11373
|
+
let lastRows = getStableDimension(stdout.rows, 24);
|
|
11374
|
+
let lastColumns = getStableDimension(stdout.columns, 80);
|
|
11375
|
+
return new Proxy(stdout, {
|
|
11376
|
+
get(target, prop, receiver) {
|
|
11377
|
+
if (prop === "rows") {
|
|
11378
|
+
if (forceFullRedraw) {
|
|
11379
|
+
return 0;
|
|
11380
|
+
}
|
|
11381
|
+
const rows = Reflect.get(target, prop, receiver);
|
|
11382
|
+
lastRows = getStableDimension(rows, lastRows);
|
|
11383
|
+
return lastRows;
|
|
11384
|
+
}
|
|
11385
|
+
if (prop === "columns") {
|
|
11386
|
+
const columns = Reflect.get(target, prop, receiver);
|
|
11387
|
+
lastColumns = getStableDimension(columns, lastColumns);
|
|
11388
|
+
return lastColumns;
|
|
11389
|
+
}
|
|
11390
|
+
const value = Reflect.get(target, prop, receiver);
|
|
11391
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
11392
|
+
}
|
|
11393
|
+
});
|
|
11394
|
+
}
|
|
11395
|
+
|
|
10889
11396
|
// src/cli.ts
|
|
10890
11397
|
var program = new Command();
|
|
10891
11398
|
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 +11401,7 @@ program.name("open-research").version(getPackageVersion()).description("Local-fi
|
|
|
10894
11401
|
const project = await loadWorkspaceProject(target);
|
|
10895
11402
|
const hasProvider = await hasConfiguredProvider();
|
|
10896
11403
|
render(
|
|
10897
|
-
|
|
11404
|
+
React7.createElement(App, {
|
|
10898
11405
|
initialState: {
|
|
10899
11406
|
authStatus: hasProvider ? "connected" : "missing",
|
|
10900
11407
|
workspacePath: project ? target : null,
|
|
@@ -10902,7 +11409,10 @@ program.name("open-research").version(getPackageVersion()).description("Local-fi
|
|
|
10902
11409
|
pendingUpdates: []
|
|
10903
11410
|
}
|
|
10904
11411
|
}),
|
|
10905
|
-
{
|
|
11412
|
+
{
|
|
11413
|
+
exitOnCtrlC: false,
|
|
11414
|
+
stdout: createStableInkStdout(process.stdout)
|
|
11415
|
+
}
|
|
10906
11416
|
);
|
|
10907
11417
|
});
|
|
10908
11418
|
program.command("init").argument("[workspacePath]").description("Initialize an Open Research workspace.").action(async (workspacePath) => {
|