features: /changes, /search, /fork, web_search, prompt memoization, per-turn spend cap, workspace refresh
ci / check (macos-latest) (push) Canceled after 0s
ci / check (ubuntu-latest) (push) Canceled after 0s
ci / check (windows-latest) (push) Canceled after 0s

- /changes diffs the last turn's file snapshot (added/modified/deleted), reusing undo infra via SnapshotStack.peek()
- system prompt memoized behind version counters (notebook/memory/skills/plugins/tools/workspace); hit-rate in /cost, foundation for provider caching
- web_search: DuckDuckGo Lite, keyless, 5 results, SSRF-filtered, in the net set with ask permission
- /search <query>: full-text grep over saved sessions incl. tool-input JSON
- workspace file list re-walks at a turn boundary after writes
- maxSpendPerTurn: per-turn cap stops a runaway step with a notice
- /fork: branch the session at the last turn boundary, original untouched

821 tests pass, typecheck clean, build green
This commit is contained in:
asepharyana committed 2026-09-09 18:06:31 +07:00
1 parent 0bdf642672
commit e709737df1
24 files changed
+720 -41

No files matched your search

+35 -1
View File
@@ -33,7 +33,7 @@ import {
type SubagentView,
} from './Panels';
import { CommandMenu, InstallConfirm, Picker } from './Pickers';
import { contextPanel, costPanel, todosPanel, toolsPanel } from './panel-bodies';
import { contextPanel, costPanel, todosPanel, toolsPanel, changesPanel } from './panel-bodies';
import { PromptInput } from './PromptInput';
import { accent, glyph } from './theme';
import { nextKey, resultSummary, toolDetail, withResult, type Line, type NewLine } from './transcript';
@@ -55,6 +55,10 @@ export type AppHooks = {
applyProvider: (result: OnboardResult) => Promise<string>;
listModels: () => Promise<{ models: string[]; warning?: string }>;
listSessions: () => Promise<string>;
/** Full-text search over saved sessions; returns a formatted panel body or ''. */
searchSessions: (query: string) => Promise<string>;
/** Fork the current session at the last turn boundary; returns a resume hint. */
forkSession: () => Promise<string>;
listSkills: () => string;
listPlugins: () => string;
listMemory: () => Promise<string>;
@@ -705,6 +709,36 @@ export function App({
setWorking(false);
return;
}
case 'changes': {
push({ kind: 'user', text: chosen.trim() });
setPanel(changesPanel(session));
return;
}
case 'search': {
push({ kind: 'user', text: chosen.trim() });
setWorking(true);
try {
const results = await hooks.searchSessions(action.query);
if (results === '') {
push({ kind: 'info', text: 'no sessions match that phrase' });
} else {
setPanel({ title: `sessions: ${action.query}`, body: results });
}
} catch (e) {
push({ kind: 'error', text: e instanceof Error ? e.message : String(e) });
}
setWorking(false);
return;
}
case 'fork': {
push({ kind: 'user', text: chosen.trim() });
try {
push({ kind: 'info', text: await hooks.forkSession() });
} catch (e) {
push({ kind: 'error', text: e instanceof Error ? e.message : String(e) });
}
return;
}
case 'provider':
push({ kind: 'user', text: chosen.trim() });
setOnboarding(true);