@glbgpt/cli 0.2.10 → 0.2.12
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/src/coding/projectContext.js +4 -8
- package/dist/src/coding/projectContext.js.map +1 -1
- package/dist/src/core/contextPrune.d.ts +4 -4
- package/dist/src/core/contextPrune.js +22 -18
- package/dist/src/core/contextPrune.js.map +1 -1
- package/dist/src/fs/limits.d.ts +1 -1
- package/dist/src/fs/limits.js +1 -1
- package/dist/src/fs/limits.js.map +1 -1
- package/dist/src/tui/App.js +63 -32
- package/dist/src/tui/App.js.map +1 -1
- package/dist/src/tui/atPopup.d.ts +6 -5
- package/dist/src/tui/atPopup.js +116 -3
- package/dist/src/tui/atPopup.js.map +1 -1
- package/dist/src/tui/attachments.d.ts +13 -0
- package/dist/src/tui/attachments.js +3 -15
- package/dist/src/tui/attachments.js.map +1 -1
- package/dist/src/tui/attentionBell.d.ts +19 -0
- package/dist/src/tui/attentionBell.js +32 -0
- package/dist/src/tui/attentionBell.js.map +1 -0
- package/dist/src/tui/chatController.d.ts +3 -0
- package/dist/src/tui/chatController.js +8 -2
- package/dist/src/tui/chatController.js.map +1 -1
- package/dist/src/tui/footerStatus.d.ts +12 -0
- package/dist/src/tui/footerStatus.js +19 -0
- package/dist/src/tui/footerStatus.js.map +1 -0
- package/dist/src/tui/run.js +7 -3
- package/dist/src/tui/run.js.map +1 -1
- package/package.json +2 -2
|
@@ -87,14 +87,10 @@ export function buildCodingSystemMessage(opts) {
|
|
|
87
87
|
'- Prefer the dedicated tools over bash equivalents: read_file over cat/head/tail/sed, ' +
|
|
88
88
|
'grep over grep/rg, glob over find, list_dir over ls, edit_file over sed/awk, ' +
|
|
89
89
|
'write_file over echo/heredoc redirection. They are safer and their output is easier to review.',
|
|
90
|
-
'- Use edit_file for targeted changes
|
|
91
|
-
|
|
92
|
-
'-
|
|
93
|
-
|
|
94
|
-
'persist between bash calls and the working directory is always the workspace root — use ' +
|
|
95
|
-
'absolute paths or `cd` within a single command.',
|
|
96
|
-
'- For long-running commands (dev servers, watchers) use bash with run_in_background: true, ' +
|
|
97
|
-
'then poll bash_output and stop with bash_kill when done.',
|
|
90
|
+
'- Use edit_file for targeted changes; use write_file only for new files or complete rewrites.',
|
|
91
|
+
'- Use bash for real commands (builds, tests, git, package managers).',
|
|
92
|
+
'- `@path` in a user message refers to that file, relative to the workspace root (`@"path"` when it has spaces). ' +
|
|
93
|
+
'Read it with read_file when you need its content.',
|
|
98
94
|
'- Before reporting completion, verify that the requested deliverable exists and inspect the resulting ' +
|
|
99
95
|
'files or tool results. Run relevant tests or builds when feasible. A successful write alone does not ' +
|
|
100
96
|
'prove the change works; a failed, interrupted, or unstarted command is not a passed check.',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projectContext.js","sourceRoot":"","sources":["../../../src/coding/projectContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;;;;;;;;GASG;AAEH,MAAM,uBAAuB,GAAG,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AAC3D,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,GAAG,IAAI,CAAC;AAOnD,KAAK,UAAU,kBAAkB,CAAC,GAAW;IAC3C,KAAK,MAAM,IAAI,IAAI,uBAAuB,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;gBAAE,SAAS;YAC7B,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;YACzE,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YAC1C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,+CAA+C;QACjD,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,GAAW;IACnC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,aAAqB,EACrB,WAAmB,yBAAyB;IAE5C,6EAA6E;IAC7E,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,GAAG,GAAG,aAAa,CAAC;IACxB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACf,IAAI,MAAM,UAAU,CAAC,GAAG,CAAC;YAAE,MAAM;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM;QAC1B,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IACD,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,aAAa;IAE7B,MAAM,KAAK,GAAyB,EAAE,CAAC;IACvC,IAAI,MAAM,GAAG,QAAQ,CAAC;IACtB,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,CAAC,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACtD,IAAI,KAAK,GAAG,MAAM;YAAE,SAAS;QAC7B,MAAM,IAAI,KAAK,CAAC;QAChB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAGxC;IACC,MAAM,KAAK,GAAa;QACtB,mEAAmE;QACnE,yFAAyF;YACvF,uHAAuH;YACvH,4EAA4E;QAC9E,wFAAwF;YACtF,+EAA+E;YAC/E,gGAAgG;QAClG
|
|
1
|
+
{"version":3,"file":"projectContext.js","sourceRoot":"","sources":["../../../src/coding/projectContext.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { ChatMessage } from './types.js';
|
|
2
2
|
import type { Session } from './session.js';
|
|
3
3
|
/**
|
|
4
|
-
* The ids to clear at this trigger:
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* The ids to clear at this trigger: oldest eligible results first, until `excessTokens`
|
|
5
|
+
* are freed. ALL results in the latest batch stay: a parallel batch must reach the model
|
|
6
|
+
* once before any of its results are cleared.
|
|
7
7
|
*/
|
|
8
|
-
export declare function selectPrunable(messages: ChatMessage[], alreadyPruned: ReadonlySet<string>, protectedIds?: ReadonlySet<string>): string[];
|
|
8
|
+
export declare function selectPrunable(messages: ChatMessage[], alreadyPruned: ReadonlySet<string>, excessTokens: number, protectedIds?: ReadonlySet<string>): string[];
|
|
9
9
|
/**
|
|
10
10
|
* The request-time projection: replace old read results or shorten old command output.
|
|
11
11
|
* Assistant calls and their arguments stay intact, along with mutation confirmations.
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { FS_TOOL_NAMES } from '../fs/index.js';
|
|
2
2
|
import { CODING_TOOL_NAMES } from '../coding/index.js';
|
|
3
3
|
import { cutToBytesFromEnd } from '../coding/truncate.js';
|
|
4
|
-
import {
|
|
4
|
+
import { PRUNE_MIN_CONTENT_BYTES, PRUNE_PLACEHOLDER, PRUNE_TARGET_TOKENS, PRUNE_TRIGGER_TOKENS } from '../fs/limits.js';
|
|
5
5
|
import { estimateMessageTokens } from './compaction.js';
|
|
6
6
|
import { getConfigValueSync } from '../config/configFile.js';
|
|
7
7
|
/**
|
|
8
8
|
* Microcompact selection and projection (spec: 2026-07-19-context-pruning-design.md).
|
|
9
9
|
*
|
|
10
10
|
* Selection and projection are pure. Selection runs only at trigger events (context over
|
|
11
|
-
* threshold)
|
|
12
|
-
*
|
|
11
|
+
* threshold) and clears down to a target well below it, so the context has to grow again
|
|
12
|
+
* before the next trigger. The returned ids join the session's persisted decision set,
|
|
13
|
+
* which only ever grows — so between triggers the projection is byte-stable and the
|
|
13
14
|
* upstream prompt cache keeps hitting.
|
|
14
15
|
*/
|
|
15
16
|
/**
|
|
@@ -67,24 +68,28 @@ function isPrunable(m) {
|
|
|
67
68
|
return true;
|
|
68
69
|
}
|
|
69
70
|
/**
|
|
70
|
-
* The ids to clear at this trigger:
|
|
71
|
-
*
|
|
72
|
-
*
|
|
71
|
+
* The ids to clear at this trigger: oldest eligible results first, until `excessTokens`
|
|
72
|
+
* are freed. ALL results in the latest batch stay: a parallel batch must reach the model
|
|
73
|
+
* once before any of its results are cleared.
|
|
73
74
|
*/
|
|
74
|
-
export function selectPrunable(messages, alreadyPruned, protectedIds = latestToolBatchIds(messages)) {
|
|
75
|
-
const
|
|
75
|
+
export function selectPrunable(messages, alreadyPruned, excessTokens, protectedIds = latestToolBatchIds(messages)) {
|
|
76
|
+
const ids = [];
|
|
77
|
+
let freed = 0;
|
|
76
78
|
for (const m of messages) {
|
|
77
|
-
|
|
79
|
+
if (freed >= excessTokens)
|
|
80
|
+
break;
|
|
81
|
+
// Cheap O(1) set checks FIRST: already-pruned messages keep their full raw
|
|
78
82
|
// content forever, and re-running isPrunable's JSON.parse over them on every
|
|
79
83
|
// trigger would grow unboundedly — the very cost this feature exists to cut.
|
|
80
84
|
if (m.role !== 'tool' || !m.tool_call_id || alreadyPruned.has(m.tool_call_id))
|
|
81
85
|
continue;
|
|
82
|
-
if (isPrunable(m))
|
|
83
|
-
|
|
86
|
+
if (protectedIds.has(m.tool_call_id) || !isPrunable(m))
|
|
87
|
+
continue;
|
|
88
|
+
ids.push(m.tool_call_id);
|
|
89
|
+
const [projected] = applyPruning([m], new Set([m.tool_call_id]));
|
|
90
|
+
freed += estimateMessageTokens(m) - estimateMessageTokens(projected);
|
|
84
91
|
}
|
|
85
|
-
return
|
|
86
|
-
.slice(0, Math.max(0, candidates.length - PRUNE_KEEP_RECENT))
|
|
87
|
-
.filter((id) => !protectedIds.has(id));
|
|
92
|
+
return ids;
|
|
88
93
|
}
|
|
89
94
|
function latestToolBatchIds(messages) {
|
|
90
95
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -136,16 +141,15 @@ export function applyPruning(messages, prunedIds) {
|
|
|
136
141
|
*/
|
|
137
142
|
export function pruneSessionContext(session, lastPromptTokens = 0) {
|
|
138
143
|
const messages = session.requestMessages();
|
|
139
|
-
|
|
140
|
-
|
|
144
|
+
const contextTokens = Math.max(lastPromptTokens, messages.reduce((sum, m) => sum + estimateMessageTokens(m), 0));
|
|
145
|
+
if (contextTokens <= PRUNE_TRIGGER_TOKENS)
|
|
141
146
|
return null;
|
|
142
|
-
}
|
|
143
147
|
// Match config precedence: an explicit environment value overrides the stored value.
|
|
144
148
|
const enabled = process.env.GLBGPT_CONTEXT_PRUNING ?? getConfigValueSync('context-pruning');
|
|
145
149
|
if (enabled === 'false')
|
|
146
150
|
return null;
|
|
147
151
|
// Select from the projection so already summarized history cannot trigger a trim note.
|
|
148
|
-
const ids = selectPrunable(messages, session.prunedToolCallIds);
|
|
152
|
+
const ids = selectPrunable(messages, session.prunedToolCallIds, contextTokens - PRUNE_TARGET_TOKENS);
|
|
149
153
|
if (ids.length === 0)
|
|
150
154
|
return null;
|
|
151
155
|
const idSet = new Set(ids);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contextPrune.js","sourceRoot":"","sources":["../../../src/core/contextPrune.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"contextPrune.js","sourceRoot":"","sources":["../../../src/core/contextPrune.ts"],"names":[],"mappings":"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"}
|
package/dist/src/fs/limits.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export declare const IGNORED_DIRS: Set<string>;
|
|
|
26
26
|
export declare const IGNORED_FILES: Set<string>;
|
|
27
27
|
export declare const BUDGET_EXHAUSTED_MESSAGE = "Tool budget for this turn is exhausted. Summarize with what you have.";
|
|
28
28
|
export declare const PRUNE_TRIGGER_TOKENS = 30000;
|
|
29
|
-
export declare const
|
|
29
|
+
export declare const PRUNE_TARGET_TOKENS = 12000;
|
|
30
30
|
export declare const PRUNE_MIN_CONTENT_BYTES = 200;
|
|
31
31
|
export declare const PRUNE_PLACEHOLDER = "[Old tool result cleared to save context \u2014 re-run the tool if needed.]";
|
|
32
32
|
export declare const DEFAULT_SESSION_MAX_CREDITS = 4000;
|
package/dist/src/fs/limits.js
CHANGED
|
@@ -57,7 +57,7 @@ export const BUDGET_EXHAUSTED_MESSAGE = 'Tool budget for this turn is exhausted.
|
|
|
57
57
|
// billing is flat per prompt_tokens (verified in yanfa UsageCapture/settlement),
|
|
58
58
|
// so pruning is pure user savings; cache stability protects latency and margin.
|
|
59
59
|
export const PRUNE_TRIGGER_TOKENS = 30_000; // last prompt_tokens above this → prune batch
|
|
60
|
-
export const
|
|
60
|
+
export const PRUNE_TARGET_TOKENS = 12_000; // clear down to this, so the next trigger is a batch away
|
|
61
61
|
export const PRUNE_MIN_CONTENT_BYTES = 200; // smaller results are cheaper kept than cleared
|
|
62
62
|
export const PRUNE_PLACEHOLDER = '[Old tool result cleared to save context — re-run the tool if needed.]';
|
|
63
63
|
// --- Unattended media budget (spec 2026-07-19-mcp-media-tools-design.md) ---
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"limits.js","sourceRoot":"","sources":["../../../src/fs/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,kCAAkC;AAClF,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,wDAAwD;AACnH,0FAA0F;AAC1F,wFAAwF;AACxF,4FAA4F;AAC5F,kFAAkF;AAClF,wFAAwF;AACxF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,CAAC,mCAAmC;AACvE,mFAAmF;AACnF,+EAA+E;AAC/E,4EAA4E;AAC5E,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC,6CAA6C;AAC9F,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,CAAC,0CAA0C;AAC9E,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAC,CAAC,WAAW;AAC/C,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC,CAAC,uDAAuD;AAC5F,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC,CAAC,uDAAuD;AAC1F,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC,CAAC,OAAO;AAC5C,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC,CAAC,8BAA8B;AACtE,+EAA+E;AAC/E,iFAAiF;AACjF,gFAAgF;AAChF,gFAAgF;AAChF,+EAA+E;AAC/E,8EAA8E;AAC9E,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC;AACrC,0FAA0F;AAC1F,2FAA2F;AAC3F,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,CAAC,CAAC,qCAAqC;AAEhF,uEAAuE;AACvE,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC;IAClC,cAAc;IACd,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,aAAa;IACb,OAAO;CACR,CAAC,CAAC;AACH,0CAA0C;AAC1C,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAEpD,MAAM,CAAC,MAAM,wBAAwB,GACnC,uEAAuE,CAAC;AAE1E,oFAAoF;AACpF,+EAA+E;AAC/E,+EAA+E;AAC/E,gFAAgF;AAChF,iFAAiF;AACjF,gFAAgF;AAChF,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,CAAC,8CAA8C;AAC1F,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"limits.js","sourceRoot":"","sources":["../../../src/fs/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,kCAAkC;AAClF,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,wDAAwD;AACnH,0FAA0F;AAC1F,wFAAwF;AACxF,4FAA4F;AAC5F,kFAAkF;AAClF,wFAAwF;AACxF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,CAAC,mCAAmC;AACvE,mFAAmF;AACnF,+EAA+E;AAC/E,4EAA4E;AAC5E,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC,6CAA6C;AAC9F,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,CAAC,0CAA0C;AAC9E,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAC,CAAC,WAAW;AAC/C,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC,CAAC,uDAAuD;AAC5F,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC,CAAC,uDAAuD;AAC1F,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC,CAAC,OAAO;AAC5C,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC,CAAC,8BAA8B;AACtE,+EAA+E;AAC/E,iFAAiF;AACjF,gFAAgF;AAChF,gFAAgF;AAChF,+EAA+E;AAC/E,8EAA8E;AAC9E,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC;AACrC,0FAA0F;AAC1F,2FAA2F;AAC3F,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,CAAC,CAAC,qCAAqC;AAEhF,uEAAuE;AACvE,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC;IAClC,cAAc;IACd,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,aAAa;IACb,OAAO;CACR,CAAC,CAAC;AACH,0CAA0C;AAC1C,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAEpD,MAAM,CAAC,MAAM,wBAAwB,GACnC,uEAAuE,CAAC;AAE1E,oFAAoF;AACpF,+EAA+E;AAC/E,+EAA+E;AAC/E,gFAAgF;AAChF,iFAAiF;AACjF,gFAAgF;AAChF,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,CAAC,8CAA8C;AAC1F,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,CAAC,0DAA0D;AACrG,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC,CAAC,gDAAgD;AAC5F,MAAM,CAAC,MAAM,iBAAiB,GAC5B,wEAAwE,CAAC;AAE3E,8EAA8E;AAC9E,kFAAkF;AAClF,8EAA8E;AAC9E,kEAAkE;AAClE,MAAM,CAAC,MAAM,2BAA2B,GAAG,IAAI,CAAC;AAChD,uFAAuF;AACvF,yFAAyF;AACzF,oFAAoF;AACpF,mFAAmF;AACnF,wFAAwF;AACxF,2EAA2E;AAC3E,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAC1C,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,CAAC,oDAAoD"}
|
package/dist/src/tui/App.js
CHANGED
|
@@ -11,6 +11,7 @@ import { findModel } from '../media/manifest.js';
|
|
|
11
11
|
import { ParamEditor, displayMediaRef } from './ParamEditor.js';
|
|
12
12
|
import { filterCommands, SLASH_COMMANDS } from './commands.js';
|
|
13
13
|
import { LOGO_FRAMES, TAGLINE, brandTitle, supportsTruecolor } from './branding.js';
|
|
14
|
+
import { footerHintFits, nextPermissionMode, turnBudgetBar } from './footerStatus.js';
|
|
14
15
|
import { applyMarkdown } from './markdown.js';
|
|
15
16
|
import { hyperlink, fileUrl } from '../util/hyperlink.js';
|
|
16
17
|
import { atCandidates } from './atPopup.js';
|
|
@@ -79,8 +80,8 @@ export function App({ controller, confirmationBridge, approvalBridge, questionBr
|
|
|
79
80
|
: [];
|
|
80
81
|
const showSuggestions = suggestions.length > 0;
|
|
81
82
|
const selectedSuggestion = suggestions[Math.min(sugIndex, suggestions.length - 1)];
|
|
82
|
-
// @
|
|
83
|
-
//
|
|
83
|
+
// @ popup: active while the input ENDS with "@<partial>" (image keywords, browsed files and
|
|
84
|
+
// dirs, and a fuzzy project-file search; Claude Code's file-mention pattern).
|
|
84
85
|
// `@"…` opens a QUOTED token so filenames with spaces (macOS screenshots) stay one token.
|
|
85
86
|
const atMatch = !showSuggestions &&
|
|
86
87
|
!pending &&
|
|
@@ -95,9 +96,15 @@ export function App({ controller, confirmationBridge, approvalBridge, questionBr
|
|
|
95
96
|
const atPartial = atMatch ? (atMatch[2] ?? atMatch[3]) : undefined;
|
|
96
97
|
const [atCands, setAtCands] = useState([]);
|
|
97
98
|
const [atIndex, setAtIndex] = useState(0);
|
|
99
|
+
// Set once the user picks with the arrows: from then on Enter takes that row, whatever matched it.
|
|
100
|
+
const [atPicked, setAtPicked] = useState(false);
|
|
101
|
+
// The partial the user closed the popup on with Esc; typing anything else reopens it.
|
|
102
|
+
const [atDismissed, setAtDismissed] = useState(null);
|
|
98
103
|
useEffect(() => {
|
|
104
|
+
setAtPicked(false);
|
|
99
105
|
if (atPartial === undefined) {
|
|
100
106
|
setAtCands([]);
|
|
107
|
+
setAtDismissed(null);
|
|
101
108
|
return;
|
|
102
109
|
}
|
|
103
110
|
let alive = true;
|
|
@@ -113,7 +120,7 @@ export function App({ controller, confirmationBridge, approvalBridge, questionBr
|
|
|
113
120
|
alive = false;
|
|
114
121
|
};
|
|
115
122
|
}, [atPartial]);
|
|
116
|
-
const showAt = atPartial !== undefined && atCands.length > 0;
|
|
123
|
+
const showAt = atPartial !== undefined && atCands.length > 0 && atPartial !== atDismissed;
|
|
117
124
|
const selectedAt = atCands[Math.min(atIndex, atCands.length - 1)];
|
|
118
125
|
const applyAtCompletion = () => {
|
|
119
126
|
if (!selectedAt || atPartial === undefined)
|
|
@@ -238,7 +245,7 @@ export function App({ controller, confirmationBridge, approvalBridge, questionBr
|
|
|
238
245
|
useInput((_i, key) => {
|
|
239
246
|
if (key.escape)
|
|
240
247
|
controller.interrupt();
|
|
241
|
-
}, { isActive: state.busy && !pending && !pendingApproval && !pendingQuestion && !selecting && !sessions });
|
|
248
|
+
}, { isActive: state.busy && !pending && !pendingApproval && !pendingQuestion && !selecting && !sessions && !showAt });
|
|
242
249
|
// Ctrl+C: never an instant kill. First press clears the draft (or interrupts a busy turn)
|
|
243
250
|
// and arms a 2s exit window; a second press within it exits (Claude Code semantics).
|
|
244
251
|
const [exitArmed, setExitArmed] = useState(false);
|
|
@@ -310,14 +317,17 @@ export function App({ controller, confirmationBridge, approvalBridge, questionBr
|
|
|
310
317
|
const file = pastedImages.get(m);
|
|
311
318
|
return file ? `@${file}` : m;
|
|
312
319
|
});
|
|
313
|
-
// @ popup navigation: ↑/↓ select, Tab/Enter complete (Enter is intercepted in onSubmit).
|
|
320
|
+
// @ popup navigation: ↑/↓ select, Tab/Enter complete (Enter is intercepted in onSubmit), Esc closes.
|
|
314
321
|
useInput((_i, key) => {
|
|
315
|
-
if (key.upArrow)
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
322
|
+
if (key.upArrow || key.downArrow) {
|
|
323
|
+
const step = key.upArrow ? atCands.length - 1 : 1;
|
|
324
|
+
setAtIndex((n) => (n + step) % atCands.length);
|
|
325
|
+
setAtPicked(true);
|
|
326
|
+
}
|
|
327
|
+
else if (key.tab && !key.shift)
|
|
320
328
|
applyAtCompletion();
|
|
329
|
+
else if (key.escape)
|
|
330
|
+
setAtDismissed(atPartial ?? null);
|
|
321
331
|
}, { isActive: showAt });
|
|
322
332
|
// Command popup navigation: ↑/↓ select, Tab completes into the input (Enter executes via onSubmit).
|
|
323
333
|
useInput((_i, key) => {
|
|
@@ -325,9 +335,26 @@ export function App({ controller, confirmationBridge, approvalBridge, questionBr
|
|
|
325
335
|
setSugIndex((n) => (n - 1 + suggestions.length) % suggestions.length);
|
|
326
336
|
else if (key.downArrow)
|
|
327
337
|
setSugIndex((n) => (n + 1) % suggestions.length);
|
|
328
|
-
else if (key.tab && selectedSuggestion)
|
|
338
|
+
else if (key.tab && !key.shift && selectedSuggestion)
|
|
329
339
|
setInput(`/${selectedSuggestion.name} `);
|
|
330
340
|
}, { isActive: showSuggestions });
|
|
341
|
+
// Shift+Tab switches the permission mode (the gate holds it, so re-render to show the change).
|
|
342
|
+
const [, bumpPermissionView] = useState(0);
|
|
343
|
+
useInput((_i, key) => {
|
|
344
|
+
if (!permissions || !(key.tab && key.shift))
|
|
345
|
+
return;
|
|
346
|
+
permissions.set(nextPermissionMode(permissions.get()));
|
|
347
|
+
bumpPermissionView((n) => n + 1);
|
|
348
|
+
}, {
|
|
349
|
+
isActive: !!permissions &&
|
|
350
|
+
!pending &&
|
|
351
|
+
!pendingApproval &&
|
|
352
|
+
!pendingQuestion &&
|
|
353
|
+
!selecting &&
|
|
354
|
+
!sessions &&
|
|
355
|
+
!showAt &&
|
|
356
|
+
!showSuggestions,
|
|
357
|
+
});
|
|
331
358
|
// Model selector navigation.
|
|
332
359
|
useInput((_i, key) => {
|
|
333
360
|
if (!selecting)
|
|
@@ -367,9 +394,9 @@ export function App({ controller, confirmationBridge, approvalBridge, questionBr
|
|
|
367
394
|
}
|
|
368
395
|
}, { isActive: !!sessions && sessions.length > 0 });
|
|
369
396
|
const onSubmit = (value) => {
|
|
370
|
-
if (showAt && selectedAt && selectedAt.insert !== atPartial) {
|
|
371
|
-
// Enter completes the highlighted
|
|
372
|
-
//
|
|
397
|
+
if (showAt && selectedAt && selectedAt.insert !== atPartial && (!selectedAt.scattered || atPicked)) {
|
|
398
|
+
// Enter completes the highlighted candidate instead of sending — unless completion wouldn't
|
|
399
|
+
// change the token, or the row only matched as scattered letters (`@bob` is probably just text).
|
|
373
400
|
applyAtCompletion();
|
|
374
401
|
return;
|
|
375
402
|
}
|
|
@@ -496,17 +523,25 @@ export function App({ controller, confirmationBridge, approvalBridge, questionBr
|
|
|
496
523
|
controller.note(`Unknown command: /${cmd}`);
|
|
497
524
|
}
|
|
498
525
|
};
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
526
|
+
const footerHint = state.busy ? 'Enter to steer' : '/ commands · @ files · shift+tab mode';
|
|
527
|
+
const footerMode = permissions && permissions.get() !== 'default' ? permissions.get() : null;
|
|
528
|
+
const footerTurnBar = state.busy && state.turnTokens ? turnBudgetBar(state.turnTokens) : '';
|
|
529
|
+
const footerTurnWarn = !!state.turnTokens && state.turnTokens.usedTokens >= state.turnTokens.limitTokens * 0.8;
|
|
530
|
+
const footerStatus = [
|
|
531
|
+
state.model,
|
|
532
|
+
state.lastPromptTokens > 0 ? ctxGauge(state.lastPromptTokens, state.model) : '',
|
|
533
|
+
state.sessionUsage.mediaCreditsEstimated > 0 ? `~${state.sessionUsage.mediaCreditsEstimated} cr` : '',
|
|
534
|
+
state.runningTasks.length > 0
|
|
535
|
+
? `${state.runningTasks.length} task${state.runningTasks.length > 1 ? 's' : ''} running`
|
|
536
|
+
: '',
|
|
537
|
+
state.busy && state.toolCallsUsed > 0 ? `⚒ tools ${state.toolCallsUsed}/${state.toolCallsLimit}` : '',
|
|
538
|
+
]
|
|
539
|
+
.filter(Boolean)
|
|
540
|
+
.join(' · ');
|
|
541
|
+
const footerStatusWidth = (footerMode ? footerMode.length + 3 : 0) + footerStatus.length + (footerTurnBar ? footerTurnBar.length + 3 : 0);
|
|
542
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Static, { items: staticItems, children: (item, i) => item === 'welcome' ? (
|
|
543
|
+
// Static is absolutely positioned, so nothing else bounds this block to the terminal width.
|
|
544
|
+
_jsx(Box, { width: columns, children: _jsx(WelcomeBlock, { model: state.model, accountLine: accountLine, firstRun: firstRun ?? false, settled: true }) }, "welcome")) : (_jsx(TimelineRow, { item: item, columns: columns }, i)) }, staticEpoch), !conversationStarted && (_jsx(WelcomeBlock, { model: state.model, accountLine: accountLine, firstRun: firstRun ?? false })), liveItems.map((item, i) => (_jsx(TimelineRow, { item: item, columns: columns, awaitingConfirm: !!pending || !!pendingApproval, streamingTail: state.busy && frozen + i === state.streamingIndex }, frozen + i))), state.plan && state.plan.length > 0 && _jsx(PlanPanel, { steps: state.plan }), state.busy && !pending && !pendingApproval && !pendingQuestion && _jsx(BusySpinner, {}), state.runningTasks.length > 0 && _jsx(TaskSummaryBar, { tasks: state.runningTasks }), pending && editingParams ? (_jsx(ParamEditor, { info: pending, columns: columns, onApply: (model, params) => confirmationBridge?.resolve({ action: 'edit', model, params }), onCancel: () => setEditingParams(false), nameFor: (r) => controller.localNameForUrl(r) })) : pending ? (_jsx(ConfirmationBlock, { info: pending, nameFor: (r) => controller.localNameForUrl(r) })) : pendingQuestion ? (_jsx(QuestionBlock, { question: pendingQuestion, selected: questionIndex })) : pendingApproval ? (_jsx(ApprovalBlock, { request: pendingApproval })) : sessions ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "cyan", children: "Resume a conversation (\u2191/\u2193, Enter to choose, Esc to cancel):" }), sessions.map((s, i) => (_jsxs(Text, { color: i === sessIndex ? 'cyan' : undefined, children: [i === sessIndex ? '❯ ' : ' ', s.preview, ' ', _jsxs(Text, { color: "gray", children: ["\u00B7 ", s.model, " \u00B7 ", timeAgo(s.updatedAt)] })] }, s.id)))] })) : selecting ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "cyan", children: "Select a model (\u2191/\u2193, Enter to choose, Esc to cancel):" }), getChatModels().map((m, i) => (_jsxs(Text, { color: i === selIndex ? 'cyan' : undefined, children: [i === selIndex ? '❯ ' : ' ', modelDisplay(m)] }, m.id)))] })) : (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [showSuggestions && (_jsxs(Box, { flexDirection: "column", children: [suggestions.map((c, i) => (_jsxs(Text, { color: c === selectedSuggestion ? 'cyan' : undefined, children: [c === selectedSuggestion ? '❯ ' : ' ', "/", c.name, _jsxs(Text, { color: "gray", children: [c.args ? ` ${c.args}` : '', " \u2014 ", c.description] })] }, c.name))), _jsx(Text, { color: "gray", dimColor: true, children: "\u2191/\u2193 select \u00B7 Tab complete \u00B7 Enter run" })] })), showAt && (_jsxs(Box, { flexDirection: "column", children: [atCands.map((c) => (_jsxs(Text, { color: c === selectedAt ? 'cyan' : undefined, children: [c === selectedAt ? '❯ ' : ' ', c.label, _jsxs(Text, { color: "gray", children: [" \u2014 ", c.hint] })] }, c.label))), _jsx(Text, { color: "gray", dimColor: true, children: "\u2191/\u2193 select \u00B7 Tab/Enter complete" })] })), state.queued.map((q, i) => (_jsxs(Text, { color: "gray", dimColor: true, children: [' ↳ queued: ', q.display] }, i))), _jsxs(Box, { borderStyle: "round", borderLeft: false, borderRight: false, borderColor: "gray", paddingLeft: 1, children: [_jsx(Text, { color: "cyan", children: '› ' }), _jsx(MultilineInput, { value: input, onChange: onInputChange, onSubmit: onSubmit, onHistoryUp: onHistoryUp, onHistoryDown: onHistoryDown, recallActive: recallActive, columns: Math.max(20, columns - 4), verticalNav: !showAt && !showSuggestions, placeholder: 'Type a message, or /help for commands (\\ + Enter for a new line)' })] }), _jsxs(Box, { justifyContent: "space-between", children: [exitArmed ? (_jsx(Text, { color: "yellow", wrap: "truncate", children: "Press ctrl+c again to exit" })) : footerHintFits(footerHint, footerStatusWidth, columns) ? (_jsx(Text, { color: "gray", dimColor: true, wrap: "truncate", children: footerHint })) : (_jsx(Text, { children: " " })), _jsxs(Text, { color: "gray", dimColor: true, wrap: "truncate", children: [footerMode ? _jsxs(Text, { color: footerMode === 'yolo' ? 'red' : 'yellow', children: [footerMode, " \u00B7 "] }) : null, footerStatus, footerTurnBar ? (_jsxs(Text, { color: footerTurnWarn ? 'yellow' : 'gray', dimColor: !footerTurnWarn, children: [' · ', footerTurnBar] })) : null] })] })] }))] }));
|
|
510
545
|
}
|
|
511
546
|
/**
|
|
512
547
|
* Full brand welcome area shown until the conversation starts (baseline §2/§3): logo raster
|
|
@@ -523,7 +558,7 @@ function WelcomeBlock({ model, accountLine, firstRun, settled = false, }) {
|
|
|
523
558
|
const t = setTimeout(() => setFrame((f) => f + 1), 60);
|
|
524
559
|
return () => clearTimeout(t);
|
|
525
560
|
}, [settled, logo, frame]);
|
|
526
|
-
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { children: [logo && (_jsx(Box, { flexDirection: "column", marginRight: 2, width: 11, children: LOGO_FRAMES[frame].map((line, i) => (_jsx(Text, { children: line || ' ' }, i))) })), _jsxs(Box, { flexDirection: "column", justifyContent: "center", children: [_jsx(Text, { children: brandTitle() }), _jsx(Text, { color: "gray", children: TAGLINE }), _jsxs(Text, { color: "gray", children: ["model: ", model] }), accountLine && _jsx(Text, { color: "gray", children: accountLine })] })] }), firstRun && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "cyan", children: "Getting started:" }), SLASH_COMMANDS.slice(0, 5).map((c) => (_jsxs(Text, { color: "gray", children: [' ', "/", c.name.padEnd(7), " ", c.description] }, c.name))), _jsxs(Text, { color: "gray", children: [' ', "Type ", _jsx(Text, { color: "cyan", children: "/" }), " to see every command, or just start chatting."] })] }))] }));
|
|
561
|
+
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { children: [logo && (_jsx(Box, { flexDirection: "column", flexShrink: 0, marginRight: 2, width: 11, children: LOGO_FRAMES[frame].map((line, i) => (_jsx(Text, { children: line || ' ' }, i))) })), _jsxs(Box, { flexDirection: "column", justifyContent: "center", children: [_jsx(Text, { children: brandTitle() }), _jsx(Text, { color: "gray", children: TAGLINE }), _jsxs(Text, { color: "gray", children: ["model: ", model] }), accountLine && _jsx(Text, { color: "gray", children: accountLine })] })] }), firstRun && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "cyan", children: "Getting started:" }), SLASH_COMMANDS.slice(0, 5).map((c) => (_jsxs(Text, { color: "gray", children: [' ', "/", c.name.padEnd(7), " ", c.description] }, c.name))), _jsxs(Text, { color: "gray", children: [' ', "Type ", _jsx(Text, { color: "cyan", children: "/" }), " to see every command, or just start chatting."] })] }))] }));
|
|
527
562
|
}
|
|
528
563
|
/** One-line summary of background generations, shown above the input while any are running. */
|
|
529
564
|
function TaskSummaryBar({ tasks }) {
|
|
@@ -755,14 +790,10 @@ function hostOfUrl(url) {
|
|
|
755
790
|
return url;
|
|
756
791
|
}
|
|
757
792
|
}
|
|
758
|
-
/**
|
|
759
|
-
/** Context occupancy for the footer: " · ctx 42%" once it starts to matter (>=25%). */
|
|
793
|
+
/** Context occupancy for the footer: "ctx 42%" once it starts to matter (>=25%). */
|
|
760
794
|
function ctxGauge(lastPromptTokens, model) {
|
|
761
795
|
const pct = Math.round((lastPromptTokens / contextWindowFor(model, modelContextWindow(model))) * 100);
|
|
762
|
-
return pct >= 25 ? `
|
|
763
|
-
}
|
|
764
|
-
function formatTokens(n) {
|
|
765
|
-
return n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n);
|
|
796
|
+
return pct >= 25 ? `ctx ${Math.min(pct, 100)}%` : '';
|
|
766
797
|
}
|
|
767
798
|
/** Compact argument preview for a tool row (the prompt, truncated, plus notable params). */
|
|
768
799
|
function summarizeArgs(args) {
|