Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 32 additions & 32 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"test:watch": "vitest"
},
"dependencies": {
"@github/copilot-sdk": "^0.1.24",
"@github/copilot-sdk": "^0.1.26",
"ink": "^5.1.0",
"ink-select-input": "^6.0.0",
"ink-spinner": "^5.0.0",
Expand Down
6 changes: 4 additions & 2 deletions src/components/status-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@ interface StatusBarProps {
screen: string;
hint?: string;
model?: string;
extra?: string;
}

export default function StatusBar({ screen, hint, model }: StatusBarProps): React.ReactElement {
export default function StatusBar({ screen, hint, model, extra }: StatusBarProps): React.ReactElement {
const displayModel = model || getModelLabel();
const { stdout } = useStdout();
// Parent App uses padding={1} → 2 cols consumed; border chars │…│ take 2 more
const innerWidth = (stdout?.columns ?? 80) - 4;

// Build right-side content: "model hint q: quit"
// Build right-side content: "model extra hint q: quit"
const rightParts: string[] = [displayModel];
if (extra) rightParts.push(extra);
if (hint) rightParts.push(hint);
rightParts.push('q: quit');
const rightText = rightParts.join(' ');
Expand Down
21 changes: 21 additions & 0 deletions src/screens/clarify.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default function ClarifyScreen({ onScopeConfirmed, onBack }: ClarifyScree
const [codebaseContext, setCodebaseContext] = useState('');
const [inspecting, setInspecting] = useState(false);
const [inspectDone, setInspectDone] = useState(false);
const [compactionMsg, setCompactionMsg] = useState('');

useEffect(() => {
loadHistory().then(setHistory);
Expand Down Expand Up @@ -108,6 +109,19 @@ export default function ClarifyScreen({ onScopeConfirmed, onBack }: ClarifyScree
]);
setStreaming(false);
},
onSessionEvent: (event) => {
if (event.type === 'session.compaction_start') {
setCompactionMsg('⟳ Compacting session history…');
} else if (event.type === 'session.compaction_complete') {
if (event.data.success) {
const removed = event.data.messagesRemoved ?? 0;
setCompactionMsg(`✓ Session history compacted (${removed} messages removed)`);
} else {
setCompactionMsg(`⚠ Compaction failed: ${event.data.error ?? 'unknown error'}`);
}
setTimeout(() => setCompactionMsg(''), 5000);
}
},
}, codebaseContext || undefined).catch((error: Error) => {
setMessages((prev) => [
...prev,
Expand Down Expand Up @@ -232,6 +246,13 @@ export default function ClarifyScreen({ onScopeConfirmed, onBack }: ClarifyScree
</Box>
)}

{/* Compaction notification */}
{compactionMsg !== '' && (
<Box marginBottom={1}>
<Text color="magenta">{compactionMsg}</Text>
</Box>
)}

<StatusBar
screen="Clarify"
hint={
Expand Down
24 changes: 24 additions & 0 deletions src/screens/execute.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ export default function ExecuteScreen({
const [summarized, setSummarized] = useState('');
const [sessionEvents, setSessionEvents] = useState<SessionEventWithTask[]>([]);
const [taskContexts, setTaskContexts] = useState<Record<string, { cwd?: string; repository?: string; branch?: string }>>({});
const [tokenUsage, setTokenUsage] = useState<{ tokenLimit: number; currentTokens: number } | null>(null);
const [compactionMsg, setCompactionMsg] = useState('');

const { batches } = computeBatches(plan.tasks);
// Total display batches: init batch (index 0) + real batches
Expand Down Expand Up @@ -211,6 +213,20 @@ export default function ExecuteScreen({
...prev,
[taskId]: { cwd, repository, branch },
}));
} else if (event.type === 'session.usage_info') {
setTokenUsage({ tokenLimit: event.data.tokenLimit, currentTokens: event.data.currentTokens });
} else if (event.type === 'session.compaction_start') {
setCompactionMsg('⟳ Compacting session history…');
} else if (event.type === 'session.compaction_complete') {
if (event.data.success) {
const removed = event.data.messagesRemoved ?? 0;
const pre = event.data.preCompactionTokens ?? 0;
const post = event.data.postCompactionTokens ?? 0;
setCompactionMsg(`✓ Compacted: ${removed} messages removed (${pre}→${post} tokens)`);
} else {
setCompactionMsg(`⚠ Compaction failed: ${event.data.error ?? 'unknown error'}`);
}
setTimeout(() => setCompactionMsg(''), 5000);
}
},
}, execOptions);
Expand Down Expand Up @@ -456,6 +472,13 @@ export default function ExecuteScreen({
</Box>
)}

{/* Compaction notification */}
{compactionMsg !== '' && (
<Box marginBottom={1}>
<Text color="magenta">{compactionMsg}</Text>
</Box>
)}

<StatusBar
screen="Execute"
hint={
Expand All @@ -469,6 +492,7 @@ export default function ExecuteScreen({
? '←→: switch batch ↑↓: select task z: summarize esc: back'
: 'x: start esc: back'
}
extra={tokenUsage ? `ctx: ${Math.round((tokenUsage.currentTokens / tokenUsage.tokenLimit) * 100)}%` : undefined}
/>
</Box>
);
Expand Down
22 changes: 21 additions & 1 deletion src/screens/refine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export default function RefineScreen({
const [viewMode, setViewMode] = useState<ViewMode>('tree');
const [editingTask, setEditingTask] = useState<Task | null>(null);
const [commandMode, setCommandMode] = useState(false);
const [compactionMsg, setCompactionMsg] = useState('');

const toggleSkill = useCallback(
(skillName: string) => {
Expand Down Expand Up @@ -164,7 +165,19 @@ export default function RefineScreen({
.then((skillOptions) =>
refineWBS(currentPlan.tasks, value, (_delta, fullText) => {
setStreamText(fullText);
}, skillOptions)
}, skillOptions, (event) => {
if (event.type === 'session.compaction_start') {
setCompactionMsg('⟳ Compacting session history…');
} else if (event.type === 'session.compaction_complete') {
if (event.data.success) {
const removed = event.data.messagesRemoved ?? 0;
setCompactionMsg(`✓ Session history compacted (${removed} messages removed)`);
} else {
setCompactionMsg(`⚠ Compaction failed: ${event.data.error ?? 'unknown error'}`);
}
setTimeout(() => setCompactionMsg(''), 5000);
}
})
)
.then((tasks) => {
const updated = { ...currentPlan, tasks, updatedAt: new Date().toISOString() };
Expand Down Expand Up @@ -301,6 +314,13 @@ export default function RefineScreen({

{saved && <Text color="green">✓ Plan saved</Text>}

{/* Compaction notification */}
{compactionMsg !== '' && (
<Box marginBottom={1}>
<Text color="magenta">{compactionMsg}</Text>
</Box>
)}

<StatusBar
screen="Refine"
hint={viewMode === 'skills'
Expand Down
5 changes: 5 additions & 0 deletions src/services/copilot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ export async function stopClient(): Promise<void> {
}
}

/** Default context utilization threshold (0.0–1.0) at which background compaction starts. */
export const COMPACTION_THRESHOLD = 0.8;

export interface StreamCallbacks {
onDelta: (text: string) => void;
onDone: (fullText: string) => void;
Expand Down Expand Up @@ -205,11 +208,13 @@ export async function sendPrompt(
streaming: boolean;
skillDirectories?: string[];
disabledSkills?: string[];
infiniteSessions?: { backgroundCompactionThreshold?: number };
}

const sessionConfig: SessionConfigWithSkills = {
model: currentModel,
streaming: true,
infiniteSessions: { backgroundCompactionThreshold: COMPACTION_THRESHOLD },
};

if (skillOptions?.skillDirectories && skillOptions.skillDirectories.length > 0) {
Expand Down
Loading