thatgfsj-code 3.0.4 → 3.0.7
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/README.md +64 -21
- package/dist/app/index.d.ts +93 -22
- package/dist/app/index.d.ts.map +1 -1
- package/dist/app/index.js +232 -40
- package/dist/app/index.js.map +1 -1
- package/dist/cmd/index.d.ts +12 -20
- package/dist/cmd/index.d.ts.map +1 -1
- package/dist/cmd/index.js +192 -146
- package/dist/cmd/index.js.map +1 -1
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +5 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/types.d.ts +5 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/llm/anthropic.d.ts +1 -1
- package/dist/llm/anthropic.d.ts.map +1 -1
- package/dist/llm/anthropic.js +116 -84
- package/dist/llm/anthropic.js.map +1 -1
- package/dist/llm/gemini.d.ts +27 -3
- package/dist/llm/gemini.d.ts.map +1 -1
- package/dist/llm/gemini.js +196 -73
- package/dist/llm/gemini.js.map +1 -1
- package/dist/llm/index.d.ts +20 -1
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/llm/index.js +66 -6
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/openai.d.ts +5 -1
- package/dist/llm/openai.d.ts.map +1 -1
- package/dist/llm/openai.js +126 -66
- package/dist/llm/openai.js.map +1 -1
- package/dist/mcp/client.d.ts +84 -34
- package/dist/mcp/client.d.ts.map +1 -1
- package/dist/mcp/client.js +291 -126
- package/dist/mcp/client.js.map +1 -1
- package/dist/session/compactor.d.ts +27 -7
- package/dist/session/compactor.d.ts.map +1 -1
- package/dist/session/compactor.js +78 -23
- package/dist/session/compactor.js.map +1 -1
- package/dist/session/index.d.ts +96 -33
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +278 -60
- package/dist/session/index.js.map +1 -1
- package/dist/tools/file.d.ts +10 -2
- package/dist/tools/file.d.ts.map +1 -1
- package/dist/tools/file.js +54 -5
- package/dist/tools/file.js.map +1 -1
- package/dist/tools/git.d.ts +16 -2
- package/dist/tools/git.d.ts.map +1 -1
- package/dist/tools/git.js +61 -18
- package/dist/tools/git.js.map +1 -1
- package/dist/tools/nwt.d.ts.map +1 -1
- package/dist/tools/nwt.js +8 -1
- package/dist/tools/nwt.js.map +1 -1
- package/dist/tools/search.d.ts +8 -1
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +105 -34
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/shell.d.ts +0 -4
- package/dist/tools/shell.d.ts.map +1 -1
- package/dist/tools/shell.js +11 -26
- package/dist/tools/shell.js.map +1 -1
- package/dist/tools/types.d.ts +7 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js.map +1 -1
- package/dist/tui/app.d.ts.map +1 -1
- package/dist/tui/app.js +90 -18
- package/dist/tui/app.js.map +1 -1
- package/dist/tui/components/ChatMessage.d.ts.map +1 -1
- package/dist/tui/components/ChatMessage.js +9 -2
- package/dist/tui/components/ChatMessage.js.map +1 -1
- package/dist/tui/components/ConfirmPrompt.d.ts +21 -0
- package/dist/tui/components/ConfirmPrompt.d.ts.map +1 -0
- package/dist/tui/components/ConfirmPrompt.js +45 -0
- package/dist/tui/components/ConfirmPrompt.js.map +1 -0
- package/dist/tui/components/Header.d.ts +10 -5
- package/dist/tui/components/Header.d.ts.map +1 -1
- package/dist/tui/components/Header.js +13 -5
- package/dist/tui/components/Header.js.map +1 -1
- package/dist/tui/components/StatusBar.d.ts +7 -0
- package/dist/tui/components/StatusBar.d.ts.map +1 -1
- package/dist/tui/components/StatusBar.js +8 -3
- package/dist/tui/components/StatusBar.js.map +1 -1
- package/dist/tui/components/Thinking.d.ts +5 -0
- package/dist/tui/components/Thinking.d.ts.map +1 -1
- package/dist/tui/components/Thinking.js +24 -2
- package/dist/tui/components/Thinking.js.map +1 -1
- package/dist/tui/components/ToolCall.d.ts +6 -1
- package/dist/tui/components/ToolCall.d.ts.map +1 -1
- package/dist/tui/components/ToolCall.js +50 -22
- package/dist/tui/components/ToolCall.js.map +1 -1
- package/dist/tui/components/UserInput.d.ts +5 -0
- package/dist/tui/components/UserInput.d.ts.map +1 -1
- package/dist/tui/components/UserInput.js +9 -13
- package/dist/tui/components/UserInput.js.map +1 -1
- package/dist/tui/hooks/useChat.d.ts +1 -0
- package/dist/tui/hooks/useChat.d.ts.map +1 -1
- package/dist/tui/hooks/useChat.js +36 -16
- package/dist/tui/hooks/useChat.js.map +1 -1
- package/dist/tui/hooks/useCommands.d.ts +7 -1
- package/dist/tui/hooks/useCommands.d.ts.map +1 -1
- package/dist/tui/hooks/useCommands.js +77 -41
- package/dist/tui/hooks/useCommands.js.map +1 -1
- package/dist/tui/theme.d.ts +34 -0
- package/dist/tui/theme.d.ts.map +1 -0
- package/dist/tui/theme.js +34 -0
- package/dist/tui/theme.js.map +1 -0
- package/dist/tui/welcome.d.ts.map +1 -1
- package/dist/tui/welcome.js +9 -7
- package/dist/tui/welcome.js.map +1 -1
- package/dist/types.d.ts +16 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/diff.d.ts +5 -0
- package/dist/utils/diff.d.ts.map +1 -1
- package/dist/utils/diff.js +15 -0
- package/dist/utils/diff.js.map +1 -1
- package/dist/version.d.ts +12 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +29 -0
- package/dist/version.js.map +1 -0
- package/package.json +19 -7
- package/CHANGELOG.md +0 -192
- package/DEVELOPMENT.md +0 -286
- package/ROADMAP.md +0 -91
- package/docs/API_KEY_GUIDE.md +0 -236
- package/docs/FAQ.md +0 -182
- package/install.bat +0 -63
- package/install.ps1 +0 -238
- package/install.sh +0 -113
- package/src/app/index.ts +0 -197
- package/src/cache/fingerprint.ts +0 -101
- package/src/cache/index.ts +0 -21
- package/src/cache/smartModel.ts +0 -133
- package/src/cache/stats.ts +0 -199
- package/src/cache/volatile.ts +0 -47
- package/src/cmd/index.tsx +0 -288
- package/src/config/index.ts +0 -156
- package/src/config/providers.ts +0 -234
- package/src/config/types.ts +0 -71
- package/src/hooks/index.ts +0 -111
- package/src/llm/anthropic.ts +0 -413
- package/src/llm/gemini.ts +0 -169
- package/src/llm/index.ts +0 -303
- package/src/llm/openai.ts +0 -243
- package/src/llm/provider.ts +0 -71
- package/src/mcp/client.ts +0 -330
- package/src/prompts/index.ts +0 -260
- package/src/session/compactor.ts +0 -103
- package/src/session/index.ts +0 -181
- package/src/session/message.ts +0 -42
- package/src/skills/brainstorming.ts +0 -43
- package/src/skills/code-review.ts +0 -45
- package/src/skills/executing-plans.ts +0 -27
- package/src/skills/frontend-design.ts +0 -35
- package/src/skills/git-workflow.ts +0 -36
- package/src/skills/improve-architecture.ts +0 -38
- package/src/skills/index.ts +0 -136
- package/src/skills/neuroweave.ts +0 -47
- package/src/skills/playwright.ts +0 -72
- package/src/skills/prototype.ts +0 -30
- package/src/skills/subagent.ts +0 -28
- package/src/skills/supabase.ts +0 -44
- package/src/skills/systematic-debugging.ts +0 -44
- package/src/skills/tdd.ts +0 -39
- package/src/skills/triage.ts +0 -35
- package/src/skills/verification.ts +0 -31
- package/src/skills/writing-plans.ts +0 -42
- package/src/tools/file.ts +0 -143
- package/src/tools/git.ts +0 -132
- package/src/tools/index.ts +0 -111
- package/src/tools/nwt.ts +0 -598
- package/src/tools/search.ts +0 -263
- package/src/tools/shell.ts +0 -136
- package/src/tools/types.ts +0 -122
- package/src/tui/app.tsx +0 -159
- package/src/tui/components/ChatList.tsx +0 -41
- package/src/tui/components/ChatMessage.tsx +0 -54
- package/src/tui/components/Header.tsx +0 -66
- package/src/tui/components/InitWizard.tsx +0 -247
- package/src/tui/components/Markdown.tsx +0 -35
- package/src/tui/components/ModelSelector.tsx +0 -107
- package/src/tui/components/StatusBar.tsx +0 -30
- package/src/tui/components/Thinking.tsx +0 -17
- package/src/tui/components/ToolCall.tsx +0 -102
- package/src/tui/components/UserInput.tsx +0 -151
- package/src/tui/hooks/useChat.ts +0 -287
- package/src/tui/hooks/useCommands.ts +0 -271
- package/src/tui/index.ts +0 -6
- package/src/tui/welcome.ts +0 -177
- package/src/types.ts +0 -104
- package/src/utils/diff.ts +0 -71
- package/src/utils/project.ts +0 -99
- package/src/utils/stableStringify.ts +0 -47
- package/src/utils/thinking.ts +0 -119
- package/tests/cache/fingerprint.test.ts +0 -75
- package/tests/cache/providerCatalog.test.ts +0 -31
- package/tests/cache/smartModel.test.ts +0 -100
- package/tests/cache/stableStringify.test.ts +0 -43
- package/tests/cache/stats.test.ts +0 -146
- package/tests/cache/volatile.test.ts +0 -75
- package/tests/smoke-pollution.mjs +0 -78
- package/tests/smoke-thinking.mjs +0 -110
- package/tests/smoke-tool-stream.mjs +0 -69
- package/tests/smoke-tool.mjs +0 -117
- package/tsconfig.json +0 -21
package/dist/session/index.js
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Session Manager - Manages conversation history with auto-compaction
|
|
3
|
+
*
|
|
4
|
+
* v3.0.5 additions:
|
|
5
|
+
* - Disk persistence: every completed round can be persisted to
|
|
6
|
+
* ~/.thatgfsj/sessions/<id>.json, and /resume restores a previous
|
|
7
|
+
* session. Files are validated on load (dangling tool_calls are
|
|
8
|
+
* stripped) so a restored history can never produce a provider 400.
|
|
9
|
+
* - reset(): starts a fresh conversation while KEEPING the system prompt
|
|
10
|
+
* (the old clear() dropped it, leaving every later request unprompted).
|
|
11
|
+
* - autoCompact: when history exceeds maxMessages it is compacted once
|
|
12
|
+
* (atomic tool groups, see compactor.ts) instead of being silently
|
|
13
|
+
* truncated every round. The TUI is notified via onAutoCompact.
|
|
3
14
|
*/
|
|
15
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync, unlinkSync, statSync } from 'fs';
|
|
16
|
+
import { join } from 'path';
|
|
17
|
+
import { homedir } from 'os';
|
|
4
18
|
import { ContextCompactor } from './compactor.js';
|
|
5
19
|
/**
|
|
6
20
|
* v2.2.4 (port from v2.1.0): patterns that, if found in an assistant
|
|
@@ -9,19 +23,10 @@ import { ContextCompactor } from './compactor.js';
|
|
|
9
23
|
* turn's LLM sees the marker and starts echoing it back, creating a
|
|
10
24
|
* self-reinforcing "[已中断]" hallucination loop.
|
|
11
25
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* - `[interrupted]` bracketed English equivalent
|
|
17
|
-
* 2. WEAK markers — only drop if the message is also short (<200
|
|
18
|
-
* chars). Long messages mentioning "response truncated" are
|
|
19
|
-
* legitimate conversation (e.g. user complaints about past
|
|
20
|
-
* behavior), not pollution.
|
|
21
|
-
*
|
|
22
|
-
* Earlier drafts matched bare `已中断` substrings and "response
|
|
23
|
-
* truncated" anywhere in the message — both were too greedy and
|
|
24
|
-
* dropped legitimate Chinese/English conversation.
|
|
26
|
+
* Two-tier check:
|
|
27
|
+
* 1. STRONG markers — unambiguous pollution, always drop.
|
|
28
|
+
* 2. WEAK markers — only drop if the message is also short (<200 chars),
|
|
29
|
+
* doesn't end with '?' and has no temporal references.
|
|
25
30
|
*/
|
|
26
31
|
const POLLUTION_STRONG = [
|
|
27
32
|
/\[已中断\]/,
|
|
@@ -38,13 +43,6 @@ function looksPolluted(content) {
|
|
|
38
43
|
return false;
|
|
39
44
|
if (POLLUTION_STRONG.some(p => p.test(content)))
|
|
40
45
|
return true;
|
|
41
|
-
// WEAK pattern gate:
|
|
42
|
-
// - Message must be short (model got cut off mid-stream, so it
|
|
43
|
-
// can't be long)
|
|
44
|
-
// - Message must NOT end with '?' (questions are user complaints
|
|
45
|
-
// about past behavior, not pollution)
|
|
46
|
-
// - Message must NOT contain "last time" / "earlier" / "before"
|
|
47
|
-
// (temporal references indicate user discussing past behavior)
|
|
48
46
|
if (content.length >= 200)
|
|
49
47
|
return false;
|
|
50
48
|
if (/\?\s*$/.test(content.trim()))
|
|
@@ -55,49 +53,100 @@ function looksPolluted(content) {
|
|
|
55
53
|
return true;
|
|
56
54
|
return false;
|
|
57
55
|
}
|
|
56
|
+
export function sessionsDir() {
|
|
57
|
+
return join(homedir(), '.thatgfsj', 'sessions');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* v3.0.5: shared load-time sanitizer. A restored history must never carry a
|
|
61
|
+
* tool_calls block without its results, or the next provider request 400s:
|
|
62
|
+
* - drop orphaned 'tool' messages (no preceding assistant tool_calls)
|
|
63
|
+
* - strip tool_calls from an assistant message whose results were lost
|
|
64
|
+
*/
|
|
65
|
+
export function sanitizeLoadedMessages(messages) {
|
|
66
|
+
const out = [];
|
|
67
|
+
let pendingCalls = 0;
|
|
68
|
+
for (const m of messages) {
|
|
69
|
+
if (m.role === 'tool') {
|
|
70
|
+
if (pendingCalls > 0) {
|
|
71
|
+
out.push(m);
|
|
72
|
+
pendingCalls--;
|
|
73
|
+
}
|
|
74
|
+
// else: orphaned tool result — drop
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (pendingCalls > 0) {
|
|
78
|
+
// A new non-tool message arrived before results completed: the
|
|
79
|
+
// previous assistant's tool_calls have no results — strip them.
|
|
80
|
+
for (let i = out.length - 1; i >= 0; i--) {
|
|
81
|
+
if (out[i].role === 'assistant' && out[i].tool_calls) {
|
|
82
|
+
const fixed = { ...out[i] };
|
|
83
|
+
delete fixed.tool_calls;
|
|
84
|
+
fixed.content = fixed.content || '(tool calls dropped: results missing)';
|
|
85
|
+
out[i] = fixed;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
pendingCalls = 0;
|
|
90
|
+
}
|
|
91
|
+
if (m.role === 'assistant' && m.tool_calls && m.tool_calls.length > 0) {
|
|
92
|
+
pendingCalls = m.tool_calls.length;
|
|
93
|
+
}
|
|
94
|
+
out.push(m);
|
|
95
|
+
}
|
|
96
|
+
// Trailing dangling calls (crash mid-loop) — strip them too.
|
|
97
|
+
if (pendingCalls > 0) {
|
|
98
|
+
for (let i = out.length - 1; i >= 0; i--) {
|
|
99
|
+
if (out[i].role === 'assistant' && out[i].tool_calls) {
|
|
100
|
+
const fixed = { ...out[i] };
|
|
101
|
+
delete fixed.tool_calls;
|
|
102
|
+
fixed.content = fixed.content || '(tool calls dropped: results missing)';
|
|
103
|
+
out[i] = fixed;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return out;
|
|
109
|
+
}
|
|
58
110
|
export class SessionManager {
|
|
59
111
|
messages = [];
|
|
60
112
|
sessionId;
|
|
61
113
|
createdAt;
|
|
62
114
|
compactor;
|
|
63
115
|
maxMessages;
|
|
64
|
-
/** v2.2.4: counter for messages dropped by the pollution filter. */
|
|
65
116
|
droppedCount = 0;
|
|
117
|
+
/** Whether history was compacted and the new-context toast not yet surfaced. */
|
|
118
|
+
lastCompaction = null;
|
|
119
|
+
/** Extra metadata recorded in the session file. */
|
|
120
|
+
meta;
|
|
66
121
|
/**
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* the TUI to suggest the user call /new (start a fresh session) so that
|
|
70
|
-
* the upstream prompt cache keeps a stable prefix. NWT auto-logs every
|
|
71
|
-
* meaningful event, so no history is lost — it just moves out of the
|
|
72
|
-
* live cache window.
|
|
122
|
+
* Called after history exceeded maxMessages and was compacted once.
|
|
123
|
+
* The TUI surfaces a toast; nobody is required to act.
|
|
73
124
|
*/
|
|
74
|
-
|
|
125
|
+
onAutoCompact;
|
|
75
126
|
constructor(maxMessages = 50, options) {
|
|
76
127
|
this.maxMessages = maxMessages;
|
|
77
128
|
this.sessionId = `session_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
78
129
|
this.createdAt = new Date();
|
|
79
130
|
this.compactor = new ContextCompactor({ maxMessages });
|
|
80
|
-
this.
|
|
131
|
+
this.onAutoCompact = options?.onAutoCompact;
|
|
81
132
|
}
|
|
82
133
|
addMessage(role, content, extras) {
|
|
83
134
|
this.messages.push({ role, content, ...extras });
|
|
84
135
|
this.autoCompact();
|
|
85
136
|
}
|
|
86
137
|
/**
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* truncation/abort pollution pattern. Use this for assistant
|
|
90
|
-
* messages whose stream might have been aborted.
|
|
138
|
+
* Same as addMessage but returns false (and skips the push) if the message
|
|
139
|
+
* content matches a known truncation/abort pollution pattern.
|
|
91
140
|
*/
|
|
92
141
|
addMessageSafe(role, content, extras) {
|
|
93
|
-
if (role === 'assistant' && looksPolluted(content)) {
|
|
142
|
+
if (role === 'assistant' && looksPolluted(typeof content === 'string' ? content : JSON.stringify(content))) {
|
|
94
143
|
this.droppedCount++;
|
|
95
144
|
return false;
|
|
96
145
|
}
|
|
97
146
|
this.addMessage(role, content, extras);
|
|
98
147
|
return true;
|
|
99
148
|
}
|
|
100
|
-
/**
|
|
149
|
+
/** Total messages dropped by addMessageSafe since session start. */
|
|
101
150
|
getDroppedCount() {
|
|
102
151
|
return this.droppedCount;
|
|
103
152
|
}
|
|
@@ -107,44 +156,86 @@ export class SessionManager {
|
|
|
107
156
|
getMessageCount() {
|
|
108
157
|
return this.messages.length;
|
|
109
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* v3.0.5: fresh conversation that KEEPS the system prompt. The previous
|
|
161
|
+
* clear() removed it, so every later request ran without the identity /
|
|
162
|
+
* tool / skills instructions until the process restarted.
|
|
163
|
+
*/
|
|
164
|
+
reset() {
|
|
165
|
+
const system = this.messages.find(m => m.role === 'system');
|
|
166
|
+
this.messages = system ? [system] : [];
|
|
167
|
+
this.lastCompaction = null;
|
|
168
|
+
// v3.0.5 fix: fresh id so the next persist() writes a NEW session file
|
|
169
|
+
// instead of overwriting the old conversation (which would make it
|
|
170
|
+
// unrestorable via /resume).
|
|
171
|
+
this.sessionId = `session_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
172
|
+
this.createdAt = new Date();
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* v3.0.5: replace in-memory history (used by /resume). Input is sanitized
|
|
176
|
+
* so a malformed file can not poison the next request.
|
|
177
|
+
*/
|
|
178
|
+
restore(messages, meta) {
|
|
179
|
+
this.messages = sanitizeLoadedMessages(messages);
|
|
180
|
+
if (meta?.id)
|
|
181
|
+
this.sessionId = meta.id;
|
|
182
|
+
if (meta?.createdAt) {
|
|
183
|
+
const d = new Date(meta.createdAt);
|
|
184
|
+
if (!isNaN(d.getTime()))
|
|
185
|
+
this.createdAt = d;
|
|
186
|
+
}
|
|
187
|
+
if (meta?.provider || meta?.model) {
|
|
188
|
+
this.meta = { provider: meta.provider, model: meta.model };
|
|
189
|
+
}
|
|
190
|
+
this.lastCompaction = null;
|
|
191
|
+
}
|
|
110
192
|
clear() {
|
|
111
193
|
this.messages = [];
|
|
112
194
|
}
|
|
113
195
|
/**
|
|
114
|
-
* v3.0.
|
|
115
|
-
* the
|
|
116
|
-
*
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
196
|
+
* v3.0.5: replace the (first) system prompt in place — used when tools or
|
|
197
|
+
* the permission mode change and the prompt must be rebuilt without
|
|
198
|
+
* resetting the conversation.
|
|
199
|
+
*/
|
|
200
|
+
replaceSystemMessage(content) {
|
|
201
|
+
const idx = this.messages.findIndex(m => m.role === 'system');
|
|
202
|
+
if (idx >= 0) {
|
|
203
|
+
this.messages[idx] = { ...this.messages[idx], content };
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
this.messages.unshift({ role: 'system', content });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Compact when over the limit — once per crossing, atomic groups (v3.0.5).
|
|
211
|
+
* The previous design only suggested /new and never touched history, which
|
|
212
|
+
* let sessions grow unbounded (and the /compact path silently rewrote
|
|
213
|
+
* history every round). Now: compact at the threshold, notify once.
|
|
131
214
|
*/
|
|
132
215
|
autoCompact() {
|
|
133
216
|
if (this.messages.length <= this.maxMessages)
|
|
134
217
|
return;
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
218
|
+
const { compacted } = this.compactor.compact(this.messages);
|
|
219
|
+
if (compacted.length >= this.messages.length)
|
|
220
|
+
return; // nothing removable
|
|
221
|
+
const before = this.messages.length;
|
|
222
|
+
this.messages = compacted;
|
|
223
|
+
this.lastCompaction = { before, after: compacted.length };
|
|
138
224
|
try {
|
|
139
|
-
this.
|
|
140
|
-
currentLength: this.messages.length,
|
|
141
|
-
max: this.maxMessages,
|
|
142
|
-
});
|
|
225
|
+
this.onAutoCompact?.(this.lastCompaction);
|
|
143
226
|
}
|
|
144
227
|
catch {
|
|
145
228
|
// Callback failure must not break the chat loop.
|
|
146
229
|
}
|
|
147
|
-
|
|
230
|
+
}
|
|
231
|
+
/** v3.0.5: explicit compaction (the /compact command). */
|
|
232
|
+
compactNow() {
|
|
233
|
+
const { compacted, result } = this.compactor.compact(this.messages);
|
|
234
|
+
if (result.removedCount <= 0)
|
|
235
|
+
return null;
|
|
236
|
+
const before = this.messages.length;
|
|
237
|
+
this.messages = compacted;
|
|
238
|
+
return { before, after: compacted.length };
|
|
148
239
|
}
|
|
149
240
|
truncate(maxMessages) {
|
|
150
241
|
if (maxMessages) {
|
|
@@ -164,6 +255,133 @@ export class SessionManager {
|
|
|
164
255
|
createdAt: this.createdAt,
|
|
165
256
|
};
|
|
166
257
|
}
|
|
258
|
+
// ==================== Persistence (v3.0.5) ====================
|
|
259
|
+
/**
|
|
260
|
+
* Write the current history to ~/.thatgfsj/sessions/<id>.json and prune
|
|
261
|
+
* old sessions. Fire-and-forget friendly: errors are swallowed by the
|
|
262
|
+
* caller — a full disk must never kill a chat round.
|
|
263
|
+
*/
|
|
264
|
+
persist() {
|
|
265
|
+
try {
|
|
266
|
+
const dir = sessionsDir();
|
|
267
|
+
if (!existsSync(dir))
|
|
268
|
+
mkdirSync(dir, { recursive: true });
|
|
269
|
+
const file = {
|
|
270
|
+
version: 1,
|
|
271
|
+
id: this.sessionId,
|
|
272
|
+
createdAt: this.createdAt.toISOString(),
|
|
273
|
+
updatedAt: new Date().toISOString(),
|
|
274
|
+
provider: this.meta?.provider,
|
|
275
|
+
model: this.meta?.model,
|
|
276
|
+
messages: this.messages,
|
|
277
|
+
};
|
|
278
|
+
writeFileSync(join(dir, `${this.sessionId}.json`), JSON.stringify(file, null, 2), 'utf-8');
|
|
279
|
+
pruneSessions(20);
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
// best-effort
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Restore a previously persisted session into THIS manager (in place).
|
|
287
|
+
*/
|
|
288
|
+
loadFrom(file) {
|
|
289
|
+
this.restore(file.messages || [], {
|
|
290
|
+
id: file.id,
|
|
291
|
+
createdAt: file.createdAt,
|
|
292
|
+
provider: file.provider,
|
|
293
|
+
model: file.model,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
/** List the most recent persisted sessions, newest first. */
|
|
297
|
+
static list(limit = 10) {
|
|
298
|
+
const dir = sessionsDir();
|
|
299
|
+
if (!existsSync(dir))
|
|
300
|
+
return [];
|
|
301
|
+
try {
|
|
302
|
+
const files = readdirSync(dir)
|
|
303
|
+
.filter(f => f.endsWith('.json'))
|
|
304
|
+
.map(f => {
|
|
305
|
+
const full = join(dir, f);
|
|
306
|
+
try {
|
|
307
|
+
return { full, mtime: statSync(full).mtimeMs };
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
})
|
|
313
|
+
.filter((x) => x !== null)
|
|
314
|
+
.sort((a, b) => b.mtime - a.mtime)
|
|
315
|
+
.slice(0, limit);
|
|
316
|
+
const out = [];
|
|
317
|
+
for (const f of files) {
|
|
318
|
+
try {
|
|
319
|
+
const data = JSON.parse(readFileSync(f.full, 'utf-8'));
|
|
320
|
+
const firstUser = (data.messages || []).find(m => m.role === 'user' && typeof m.content === 'string');
|
|
321
|
+
out.push({
|
|
322
|
+
id: data.id,
|
|
323
|
+
updatedAt: new Date(data.updatedAt || data.createdAt || Date.now()),
|
|
324
|
+
messageCount: (data.messages || []).length,
|
|
325
|
+
preview: firstUser ? firstUser.content.slice(0, 60).replace(/\s+/g, ' ') : '(no user messages)',
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
// skip corrupted file
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return out;
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
return [];
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
/** Load a persisted session file by id (or filename). */
|
|
339
|
+
static load(id) {
|
|
340
|
+
const dir = sessionsDir();
|
|
341
|
+
const filename = id.endsWith('.json') ? id : `${id}.json`;
|
|
342
|
+
const full = join(dir, filename);
|
|
343
|
+
if (!existsSync(full))
|
|
344
|
+
return null;
|
|
345
|
+
try {
|
|
346
|
+
const data = JSON.parse(readFileSync(full, 'utf-8'));
|
|
347
|
+
if (!data || !Array.isArray(data.messages))
|
|
348
|
+
return null;
|
|
349
|
+
return data;
|
|
350
|
+
}
|
|
351
|
+
catch {
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
/** Keep only the newest `keep` session files. */
|
|
357
|
+
function pruneSessions(keep) {
|
|
358
|
+
const dir = sessionsDir();
|
|
359
|
+
if (!existsSync(dir))
|
|
360
|
+
return;
|
|
361
|
+
try {
|
|
362
|
+
const files = readdirSync(dir)
|
|
363
|
+
.filter(f => f.endsWith('.json'))
|
|
364
|
+
.map(f => {
|
|
365
|
+
const full = join(dir, f);
|
|
366
|
+
try {
|
|
367
|
+
return { full, mtime: statSync(full).mtimeMs };
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
})
|
|
373
|
+
.filter((x) => x !== null)
|
|
374
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
375
|
+
for (const f of files.slice(keep)) {
|
|
376
|
+
try {
|
|
377
|
+
unlinkSync(f.full);
|
|
378
|
+
}
|
|
379
|
+
catch { /* best-effort */ }
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
// best-effort
|
|
384
|
+
}
|
|
167
385
|
}
|
|
168
386
|
export { ContextCompactor } from './compactor.js';
|
|
169
387
|
export * from './message.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/file.d.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* File Tool - File operations
|
|
3
|
+
*
|
|
4
|
+
* v3.0.5: write and delete now route through the permission pipeline.
|
|
5
|
+
* - write shows a line diff (utils/diff.ts, previously dead code) via
|
|
6
|
+
* ctx.confirmEdit before touching the file
|
|
7
|
+
* - delete asks via ctx.confirmAction
|
|
8
|
+
* - read/list/exists/mkdir stay silent (read-class operations)
|
|
9
|
+
* With no context wired (should not happen — App always installs one) we
|
|
10
|
+
* fail closed for destructive actions instead of silently executing.
|
|
3
11
|
*/
|
|
4
|
-
import type { Tool, ToolResult } from './types.js';
|
|
12
|
+
import type { Tool, ToolResult, ToolContext } from './types.js';
|
|
5
13
|
export declare class FileTool implements Tool {
|
|
6
14
|
name: string;
|
|
7
15
|
description: string;
|
|
@@ -35,7 +43,7 @@ export declare class FileTool implements Tool {
|
|
|
35
43
|
description: string;
|
|
36
44
|
required: boolean;
|
|
37
45
|
}[];
|
|
38
|
-
execute(params: Record<string, any
|
|
46
|
+
execute(params: Record<string, any>, ctx?: ToolContext): Promise<ToolResult>;
|
|
39
47
|
private readFile;
|
|
40
48
|
private writeFile;
|
|
41
49
|
private listDir;
|
package/dist/tools/file.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/tools/file.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/tools/file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAKhE,qBAAa,QAAS,YAAW,IAAI;IACnC,IAAI,SAAU;IACd,WAAW,SAA8D;IAEzE,WAAW;;;;;;;;;;;;;;;;;MAQT;IAEF,QAAQ;qBAC4B,CAAC,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC,EAAE;;;;MAI9E;IAEF,UAAU;;;;;QAIR;IAEI,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAyBlF,OAAO,CAAC,QAAQ;YAmCF,SAAS;IAmCvB,OAAO,CAAC,OAAO;YAoBD,UAAU;IAmBxB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,KAAK;CAId"}
|
package/dist/tools/file.js
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* File Tool - File operations
|
|
3
|
+
*
|
|
4
|
+
* v3.0.5: write and delete now route through the permission pipeline.
|
|
5
|
+
* - write shows a line diff (utils/diff.ts, previously dead code) via
|
|
6
|
+
* ctx.confirmEdit before touching the file
|
|
7
|
+
* - delete asks via ctx.confirmAction
|
|
8
|
+
* - read/list/exists/mkdir stay silent (read-class operations)
|
|
9
|
+
* With no context wired (should not happen — App always installs one) we
|
|
10
|
+
* fail closed for destructive actions instead of silently executing.
|
|
3
11
|
*/
|
|
4
12
|
import { readFileSync, writeFileSync, existsSync, readdirSync, statSync, mkdirSync, unlinkSync } from 'fs';
|
|
5
13
|
import { join, dirname } from 'path';
|
|
14
|
+
import { DiffPreview } from '../utils/diff.js';
|
|
6
15
|
export class FileTool {
|
|
7
16
|
name = 'file';
|
|
8
17
|
description = 'Perform file operations: read, write, list, delete, etc.';
|
|
@@ -26,18 +35,18 @@ export class FileTool {
|
|
|
26
35
|
{ name: 'path', type: 'string', description: 'File or directory path', required: true },
|
|
27
36
|
{ name: 'content', type: 'string', description: 'Content to write (for write action)', required: false }
|
|
28
37
|
];
|
|
29
|
-
async execute(params) {
|
|
38
|
+
async execute(params, ctx) {
|
|
30
39
|
const { action, path, content } = params;
|
|
31
40
|
try {
|
|
32
41
|
switch (action) {
|
|
33
42
|
case 'read':
|
|
34
43
|
return this.readFile(path);
|
|
35
44
|
case 'write':
|
|
36
|
-
return this.writeFile(path, content || '');
|
|
45
|
+
return await this.writeFile(path, content || '', ctx);
|
|
37
46
|
case 'list':
|
|
38
47
|
return this.listDir(path);
|
|
39
48
|
case 'delete':
|
|
40
|
-
return this.deleteFile(path);
|
|
49
|
+
return await this.deleteFile(path, ctx);
|
|
41
50
|
case 'exists':
|
|
42
51
|
return this.checkExists(path);
|
|
43
52
|
case 'mkdir':
|
|
@@ -81,7 +90,37 @@ export class FileTool {
|
|
|
81
90
|
}
|
|
82
91
|
return { success: true, output: content };
|
|
83
92
|
}
|
|
84
|
-
writeFile(path, content) {
|
|
93
|
+
async writeFile(path, content, ctx) {
|
|
94
|
+
// v3.0.5: permission gate with diff preview. Fail closed when no
|
|
95
|
+
// confirmation channel is available at all.
|
|
96
|
+
if (ctx?.confirmEdit) {
|
|
97
|
+
const original = existsSync(path) ? (() => {
|
|
98
|
+
try {
|
|
99
|
+
return readFileSync(path, 'utf-8');
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return '';
|
|
103
|
+
}
|
|
104
|
+
})() : '';
|
|
105
|
+
const diff = DiffPreview.diff(original, content);
|
|
106
|
+
const status = existsSync(path)
|
|
107
|
+
? `修改文件 (−${diff.removed} / +${diff.added} 行)`
|
|
108
|
+
: `新建文件 (+${diff.added} 行)`;
|
|
109
|
+
const preview = diff.added + diff.removed > 400
|
|
110
|
+
? DiffPreview.truncate(diff)
|
|
111
|
+
: DiffPreview.format(diff);
|
|
112
|
+
const ok = await ctx.confirmEdit({
|
|
113
|
+
message: `${status}: ${path}\n\n${preview}`,
|
|
114
|
+
});
|
|
115
|
+
if (!ok) {
|
|
116
|
+
return { success: false, error: 'File write cancelled by user' };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// v3.0.5 fix: symmetric fail-closed — no confirmation channel at all
|
|
121
|
+
// (not even a context) means no writes, same as deleteFile.
|
|
122
|
+
return { success: false, error: 'File write requires confirmation, but no confirmation channel is available' };
|
|
123
|
+
}
|
|
85
124
|
const dir = dirname(path);
|
|
86
125
|
if (!existsSync(dir)) {
|
|
87
126
|
mkdirSync(dir, { recursive: true });
|
|
@@ -106,10 +145,20 @@ export class FileTool {
|
|
|
106
145
|
});
|
|
107
146
|
return { success: true, output: JSON.stringify(items, null, 2) };
|
|
108
147
|
}
|
|
109
|
-
deleteFile(path) {
|
|
148
|
+
async deleteFile(path, ctx) {
|
|
110
149
|
if (!existsSync(path)) {
|
|
111
150
|
return { success: false, error: `Path not found: ${path}` };
|
|
112
151
|
}
|
|
152
|
+
// v3.0.5: delete is destructive — always ask, fail closed without a channel.
|
|
153
|
+
if (ctx?.confirmAction) {
|
|
154
|
+
const ok = await ctx.confirmAction(`删除文件: ${path}`);
|
|
155
|
+
if (!ok) {
|
|
156
|
+
return { success: false, error: 'File deletion cancelled by user' };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
return { success: false, error: 'File deletion requires confirmation, but no confirmation channel is available' };
|
|
161
|
+
}
|
|
113
162
|
unlinkSync(path);
|
|
114
163
|
return { success: true, output: `Deleted: ${path}` };
|
|
115
164
|
}
|
package/dist/tools/file.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.js","sourceRoot":"","sources":["../../src/tools/file.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"file.js","sourceRoot":"","sources":["../../src/tools/file.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/git.d.ts
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Git Tool - Git operations
|
|
3
|
+
*
|
|
4
|
+
* v3.0.5:
|
|
5
|
+
* - Command injection fixed: user/model-controlled values (commit
|
|
6
|
+
* messages, branch names, extra args) were interpolated into a shell
|
|
7
|
+
* string executed via cmd.exe. All calls now go through execFile with
|
|
8
|
+
* an argument array, so values are passed verbatim and never parsed
|
|
9
|
+
* by a shell.
|
|
10
|
+
* - Write actions (commit/push/pull/checkout/add) require confirmation
|
|
11
|
+
* via ctx.confirmAction; read-only actions (status/log/diff/branch)
|
|
12
|
+
* run silently. App.requestConfirmation owns the mode decision.
|
|
3
13
|
*/
|
|
4
|
-
import type { Tool, ToolResult } from './types.js';
|
|
14
|
+
import type { Tool, ToolResult, ToolContext } from './types.js';
|
|
5
15
|
export declare class GitTool implements Tool {
|
|
6
16
|
name: string;
|
|
7
17
|
description: string;
|
|
@@ -38,7 +48,11 @@ export declare class GitTool implements Tool {
|
|
|
38
48
|
description: string;
|
|
39
49
|
required: boolean;
|
|
40
50
|
}[];
|
|
41
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Run git with an argument array (no shell interpolation).
|
|
53
|
+
*/
|
|
54
|
+
private git;
|
|
55
|
+
execute(params: Record<string, any>, ctx?: ToolContext): Promise<ToolResult>;
|
|
42
56
|
private status;
|
|
43
57
|
private log;
|
|
44
58
|
private diff;
|
package/dist/tools/git.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/tools/git.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/tools/git.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAWhE,qBAAa,OAAQ,YAAW,IAAI;IAClC,IAAI,SAAS;IACb,WAAW,SAA6D;IAExE,WAAW;;;;;;;;;;;;;;;;;;;;;MAST;IAEF,QAAQ;qBACsB,CAAC,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC,EAAE;;;MAGxE;IAEF,UAAU;;;;;QAKR;IAEF;;OAEG;YACW,GAAG;IASX,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;YAoDpE,MAAM;YAKN,GAAG;YAQH,IAAI;YAMJ,MAAM;YAYN,MAAM;YAKN,QAAQ;YASR,IAAI;YAKJ,IAAI;YAKJ,GAAG;CAIlB"}
|