mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-17 08:00:59 +00:00
Rename /clear to /new, update hook events to before_new/new
Closes #305 - took direct rename approach instead of alias system Thanks @mitsuhiko for the nudge!
This commit is contained in:
parent
0427445242
commit
454ea1d36a
11 changed files with 56 additions and 35 deletions
|
|
@ -2,6 +2,20 @@
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
- **Renamed `/clear` to `/new`**: The command to start a fresh session is now `/new`. Hook event reasons `before_clear`/`clear` are now `before_new`/`new`. Merry Christmas [@mitsuhiko](https://github.com/mitsuhiko)! ([#305](https://github.com/badlogic/pi-mono/pull/305))
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Auto-space before pasted file paths**: When pasting a file path (starting with `/`, `~`, or `.`) after a word character, a space is automatically prepended. ([#307](https://github.com/badlogic/pi-mono/pull/307) by [@mitsuhiko](https://github.com/mitsuhiko))
|
||||||
|
- **Word navigation in input fields**: Added Ctrl+Left/Right and Alt+Left/Right for word-by-word cursor movement. ([#306](https://github.com/badlogic/pi-mono/pull/306) by [@kim0](https://github.com/kim0))
|
||||||
|
- **Full Unicode input**: Input fields now accept Unicode characters beyond ASCII. ([#306](https://github.com/badlogic/pi-mono/pull/306) by [@kim0](https://github.com/kim0))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Readline-style Ctrl+W**: Now skips trailing whitespace before deleting the preceding word, matching standard readline behavior. ([#306](https://github.com/badlogic/pi-mono/pull/306) by [@kim0](https://github.com/kim0))
|
||||||
|
|
||||||
## [0.28.0] - 2025-12-25
|
## [0.28.0] - 2025-12-25
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
||||||
|
|
@ -197,7 +197,7 @@ The agent reads, writes, and edits files, and executes commands via bash.
|
||||||
| `/resume` | Switch to a different session (interactive selector) |
|
| `/resume` | Switch to a different session (interactive selector) |
|
||||||
| `/login` | OAuth login for subscription-based models |
|
| `/login` | OAuth login for subscription-based models |
|
||||||
| `/logout` | Clear OAuth tokens |
|
| `/logout` | Clear OAuth tokens |
|
||||||
| `/clear` | Clear context and start fresh session |
|
| `/new` | Start a new session |
|
||||||
| `/copy` | Copy last agent message to clipboard |
|
| `/copy` | Copy last agent message to clipboard |
|
||||||
| `/compact [instructions]` | Manually compact conversation context |
|
| `/compact [instructions]` | Manually compact conversation context |
|
||||||
| `/autocompact` | Toggle automatic context compaction |
|
| `/autocompact` | Toggle automatic context compaction |
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ interface ToolSessionEvent {
|
||||||
entries: SessionEntry[]; // All session entries
|
entries: SessionEntry[]; // All session entries
|
||||||
sessionFile: string | null; // Current session file
|
sessionFile: string | null; // Current session file
|
||||||
previousSessionFile: string | null; // Previous session file
|
previousSessionFile: string | null; // Previous session file
|
||||||
reason: "start" | "switch" | "branch" | "clear";
|
reason: "start" | "switch" | "branch" | "new";
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -194,7 +194,7 @@ interface ToolSessionEvent {
|
||||||
- `start`: Initial session load on startup
|
- `start`: Initial session load on startup
|
||||||
- `switch`: User switched to a different session (`/resume`)
|
- `switch`: User switched to a different session (`/resume`)
|
||||||
- `branch`: User branched from a previous message (`/branch`)
|
- `branch`: User branched from a previous message (`/branch`)
|
||||||
- `clear`: User cleared the session (`/clear`)
|
- `new`: User started a new session (`/new`)
|
||||||
|
|
||||||
### State Management Pattern
|
### State Management Pattern
|
||||||
|
|
||||||
|
|
@ -250,7 +250,7 @@ const factory: CustomToolFactory = (pi) => {
|
||||||
This pattern ensures:
|
This pattern ensures:
|
||||||
- When user branches, state is correct for that point in history
|
- When user branches, state is correct for that point in history
|
||||||
- When user switches sessions, state matches that session
|
- When user switches sessions, state matches that session
|
||||||
- When user clears, state resets
|
- When user starts a new session, state resets
|
||||||
|
|
||||||
## Custom Rendering
|
## Custom Rendering
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -125,10 +125,10 @@ user switches session (/resume)
|
||||||
├─► session (reason: "before_switch", can cancel)
|
├─► session (reason: "before_switch", can cancel)
|
||||||
└─► session (reason: "switch", AFTER switch)
|
└─► session (reason: "switch", AFTER switch)
|
||||||
|
|
||||||
user clears session (/clear)
|
user starts new session (/new)
|
||||||
│
|
│
|
||||||
├─► session (reason: "before_clear", can cancel)
|
├─► session (reason: "before_new", can cancel)
|
||||||
└─► session (reason: "clear", AFTER clear)
|
└─► session (reason: "new", AFTER new session starts)
|
||||||
|
|
||||||
context compaction (auto or /compact)
|
context compaction (auto or /compact)
|
||||||
│
|
│
|
||||||
|
|
@ -151,12 +151,12 @@ pi.on("session", async (event, ctx) => {
|
||||||
// event.entries: SessionEntry[] - all session entries
|
// event.entries: SessionEntry[] - all session entries
|
||||||
// event.sessionFile: string | null - current session file (null with --no-session)
|
// event.sessionFile: string | null - current session file (null with --no-session)
|
||||||
// event.previousSessionFile: string | null - previous session file
|
// event.previousSessionFile: string | null - previous session file
|
||||||
// event.reason: "start" | "before_switch" | "switch" | "before_clear" | "clear" |
|
// event.reason: "start" | "before_switch" | "switch" | "before_new" | "new" |
|
||||||
// "before_branch" | "branch" | "before_compact" | "compact" | "shutdown"
|
// "before_branch" | "branch" | "before_compact" | "compact" | "shutdown"
|
||||||
// event.targetTurnIndex: number - only for "before_branch" and "branch"
|
// event.targetTurnIndex: number - only for "before_branch" and "branch"
|
||||||
|
|
||||||
// Cancel a before_* action:
|
// Cancel a before_* action:
|
||||||
if (event.reason === "before_clear") {
|
if (event.reason === "before_new") {
|
||||||
return { cancel: true };
|
return { cancel: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,7 +171,7 @@ pi.on("session", async (event, ctx) => {
|
||||||
**Reasons:**
|
**Reasons:**
|
||||||
- `start`: Initial session load on startup
|
- `start`: Initial session load on startup
|
||||||
- `before_switch` / `switch`: User switched sessions (`/resume`)
|
- `before_switch` / `switch`: User switched sessions (`/resume`)
|
||||||
- `before_clear` / `clear`: User cleared the session (`/clear`)
|
- `before_new` / `new`: User started a new session (`/new`)
|
||||||
- `before_branch` / `branch`: User branched the session (`/branch`)
|
- `before_branch` / `branch`: User branched the session (`/branch`)
|
||||||
- `before_compact` / `compact`: Context compaction (auto or `/compact`)
|
- `before_compact` / `compact`: Context compaction (auto or `/compact`)
|
||||||
- `shutdown`: Process is exiting (double Ctrl+C, Ctrl+D, or SIGTERM)
|
- `shutdown`: Process is exiting (double Ctrl+C, Ctrl+D, or SIGTERM)
|
||||||
|
|
@ -848,9 +848,9 @@ Session switch:
|
||||||
|
|
||||||
Clear:
|
Clear:
|
||||||
-> AgentSession.reset()
|
-> AgentSession.reset()
|
||||||
-> hookRunner.emit({ type: "session", reason: "before_clear", ... }) # can cancel
|
-> hookRunner.emit({ type: "session", reason: "before_new", ... }) # can cancel
|
||||||
-> [if not cancelled: clear happens]
|
-> [if not cancelled: new session starts]
|
||||||
-> hookRunner.emit({ type: "session", reason: "clear", ... })
|
-> hookRunner.emit({ type: "session", reason: "new", ... })
|
||||||
|
|
||||||
Shutdown (interactive mode):
|
Shutdown (interactive mode):
|
||||||
-> handleCtrlC() or handleCtrlD()
|
-> handleCtrlC() or handleCtrlD()
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import type { HookAPI } from "@mariozechner/pi-coding-agent/hooks";
|
||||||
export default function (pi: HookAPI) {
|
export default function (pi: HookAPI) {
|
||||||
pi.on("session", async (event, ctx) => {
|
pi.on("session", async (event, ctx) => {
|
||||||
// Only handle before_* events (the ones that can be cancelled)
|
// Only handle before_* events (the ones that can be cancelled)
|
||||||
if (event.reason === "before_clear") {
|
if (event.reason === "before_new") {
|
||||||
if (!ctx.hasUI) return;
|
if (!ctx.hasUI) return;
|
||||||
|
|
||||||
const confirmed = await ctx.ui.confirm(
|
const confirmed = await ctx.ui.confirm(
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import type { HookAPI } from "@mariozechner/pi-coding-agent/hooks";
|
||||||
export default function (pi: HookAPI) {
|
export default function (pi: HookAPI) {
|
||||||
pi.on("session", async (event, ctx) => {
|
pi.on("session", async (event, ctx) => {
|
||||||
// Only guard destructive actions
|
// Only guard destructive actions
|
||||||
if (event.reason !== "before_clear" && event.reason !== "before_switch" && event.reason !== "before_branch") {
|
if (event.reason !== "before_new" && event.reason !== "before_switch" && event.reason !== "before_branch") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,11 +36,7 @@ export default function (pi: HookAPI) {
|
||||||
const changedFiles = stdout.trim().split("\n").filter(Boolean).length;
|
const changedFiles = stdout.trim().split("\n").filter(Boolean).length;
|
||||||
|
|
||||||
const action =
|
const action =
|
||||||
event.reason === "before_clear"
|
event.reason === "before_new" ? "new session" : event.reason === "before_switch" ? "switch session" : "branch";
|
||||||
? "clear session"
|
|
||||||
: event.reason === "before_switch"
|
|
||||||
? "switch session"
|
|
||||||
: "branch";
|
|
||||||
|
|
||||||
const choice = await ctx.ui.select(`You have ${changedFiles} uncommitted file(s). ${action} anyway?`, [
|
const choice = await ctx.ui.select(`You have ${changedFiles} uncommitted file(s). ${action} anyway?`, [
|
||||||
"Yes, proceed anyway",
|
"Yes, proceed anyway",
|
||||||
|
|
|
||||||
|
|
@ -517,14 +517,14 @@ export class AgentSession {
|
||||||
const previousSessionFile = this.sessionFile;
|
const previousSessionFile = this.sessionFile;
|
||||||
const entries = this.sessionManager.getEntries();
|
const entries = this.sessionManager.getEntries();
|
||||||
|
|
||||||
// Emit before_clear event (can be cancelled)
|
// Emit before_new event (can be cancelled)
|
||||||
if (this._hookRunner?.hasHandlers("session")) {
|
if (this._hookRunner?.hasHandlers("session")) {
|
||||||
const result = (await this._hookRunner.emit({
|
const result = (await this._hookRunner.emit({
|
||||||
type: "session",
|
type: "session",
|
||||||
entries,
|
entries,
|
||||||
sessionFile: this.sessionFile,
|
sessionFile: this.sessionFile,
|
||||||
previousSessionFile: null,
|
previousSessionFile: null,
|
||||||
reason: "before_clear",
|
reason: "before_new",
|
||||||
})) as SessionEventResult | undefined;
|
})) as SessionEventResult | undefined;
|
||||||
|
|
||||||
if (result?.cancel) {
|
if (result?.cancel) {
|
||||||
|
|
@ -539,7 +539,7 @@ export class AgentSession {
|
||||||
this._queuedMessages = [];
|
this._queuedMessages = [];
|
||||||
this._reconnectToAgent();
|
this._reconnectToAgent();
|
||||||
|
|
||||||
// Emit session event with reason "clear" to hooks
|
// Emit session event with reason "new" to hooks
|
||||||
if (this._hookRunner) {
|
if (this._hookRunner) {
|
||||||
this._hookRunner.setSessionFile(this.sessionFile);
|
this._hookRunner.setSessionFile(this.sessionFile);
|
||||||
await this._hookRunner.emit({
|
await this._hookRunner.emit({
|
||||||
|
|
@ -547,12 +547,12 @@ export class AgentSession {
|
||||||
entries: [],
|
entries: [],
|
||||||
sessionFile: this.sessionFile,
|
sessionFile: this.sessionFile,
|
||||||
previousSessionFile,
|
previousSessionFile,
|
||||||
reason: "clear",
|
reason: "new",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit session event to custom tools
|
// Emit session event to custom tools
|
||||||
await this._emitToolSessionEvent("clear", previousSessionFile);
|
await this._emitToolSessionEvent("new", previousSessionFile);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,10 +51,10 @@ export interface SessionEvent {
|
||||||
entries: SessionEntry[];
|
entries: SessionEntry[];
|
||||||
/** Current session file path, or null in --no-session mode */
|
/** Current session file path, or null in --no-session mode */
|
||||||
sessionFile: string | null;
|
sessionFile: string | null;
|
||||||
/** Previous session file path, or null for "start" and "clear" */
|
/** Previous session file path, or null for "start" and "new" */
|
||||||
previousSessionFile: string | null;
|
previousSessionFile: string | null;
|
||||||
/** Reason for the session event */
|
/** Reason for the session event */
|
||||||
reason: "start" | "switch" | "branch" | "clear";
|
reason: "start" | "switch" | "branch" | "new";
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Rendering options passed to renderResult */
|
/** Rendering options passed to renderResult */
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ interface SessionEventBase {
|
||||||
entries: SessionEntry[];
|
entries: SessionEntry[];
|
||||||
/** Current session file path, or null in --no-session mode */
|
/** Current session file path, or null in --no-session mode */
|
||||||
sessionFile: string | null;
|
sessionFile: string | null;
|
||||||
/** Previous session file path, or null for "start" and "clear" */
|
/** Previous session file path, or null for "start" and "new" */
|
||||||
previousSessionFile: string | null;
|
previousSessionFile: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,7 +110,7 @@ interface SessionEventBase {
|
||||||
* Lifecycle:
|
* Lifecycle:
|
||||||
* - start: Initial session load
|
* - start: Initial session load
|
||||||
* - before_switch / switch: Session switch (e.g., /resume command)
|
* - before_switch / switch: Session switch (e.g., /resume command)
|
||||||
* - before_clear / clear: Session clear (e.g., /clear command)
|
* - before_new / new: New session (e.g., /new command)
|
||||||
* - before_branch / branch: Session branch (e.g., /branch command)
|
* - before_branch / branch: Session branch (e.g., /branch command)
|
||||||
* - before_compact / compact: Before/after context compaction
|
* - before_compact / compact: Before/after context compaction
|
||||||
* - shutdown: Process exit (SIGINT/SIGTERM)
|
* - shutdown: Process exit (SIGINT/SIGTERM)
|
||||||
|
|
@ -120,7 +120,7 @@ interface SessionEventBase {
|
||||||
*/
|
*/
|
||||||
export type SessionEvent =
|
export type SessionEvent =
|
||||||
| (SessionEventBase & {
|
| (SessionEventBase & {
|
||||||
reason: "start" | "switch" | "clear" | "before_switch" | "before_clear" | "shutdown";
|
reason: "start" | "switch" | "new" | "before_switch" | "before_new" | "shutdown";
|
||||||
})
|
})
|
||||||
| (SessionEventBase & {
|
| (SessionEventBase & {
|
||||||
reason: "branch" | "before_branch";
|
reason: "branch" | "before_branch";
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ export class InteractiveMode {
|
||||||
{ name: "logout", description: "Logout from OAuth provider" },
|
{ name: "logout", description: "Logout from OAuth provider" },
|
||||||
{ name: "queue", description: "Select message queue mode (opens selector UI)" },
|
{ name: "queue", description: "Select message queue mode (opens selector UI)" },
|
||||||
{ name: "theme", description: "Select color theme (opens selector UI)" },
|
{ name: "theme", description: "Select color theme (opens selector UI)" },
|
||||||
{ name: "clear", description: "Clear context and start a fresh session" },
|
{ name: "new", description: "Start a new session" },
|
||||||
{ name: "compact", description: "Manually compact the session context" },
|
{ name: "compact", description: "Manually compact the session context" },
|
||||||
{ name: "autocompact", description: "Toggle automatic context compaction" },
|
{ name: "autocompact", description: "Toggle automatic context compaction" },
|
||||||
{ name: "resume", description: "Resume a different session" },
|
{ name: "resume", description: "Resume a different session" },
|
||||||
|
|
@ -672,7 +672,7 @@ export class InteractiveMode {
|
||||||
this.editor.setText("");
|
this.editor.setText("");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (text === "/clear") {
|
if (text === "/new") {
|
||||||
this.editor.setText("");
|
this.editor.setText("");
|
||||||
await this.handleClearCommand();
|
await this.handleClearCommand();
|
||||||
return;
|
return;
|
||||||
|
|
@ -1843,9 +1843,7 @@ export class InteractiveMode {
|
||||||
this.isFirstUserMessage = true;
|
this.isFirstUserMessage = true;
|
||||||
|
|
||||||
this.chatContainer.addChild(new Spacer(1));
|
this.chatContainer.addChild(new Spacer(1));
|
||||||
this.chatContainer.addChild(
|
this.chatContainer.addChild(new Text(`${theme.fg("accent", "✓ New session started")}`, 1, 1));
|
||||||
new Text(`${theme.fg("accent", "✓ Context cleared")}\n${theme.fg("muted", "Started fresh session")}`, 1, 1),
|
|
||||||
);
|
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
13
packages/tui/CHANGELOG.md
Normal file
13
packages/tui/CHANGELOG.md
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Auto-space before pasted file paths**: When pasting a file path (starting with `/`, `~`, or `.`) and the cursor is after a word character, a space is automatically prepended for better readability. Useful when dragging screenshots from macOS. ([#307](https://github.com/badlogic/pi-mono/pull/307) by [@mitsuhiko](https://github.com/mitsuhiko))
|
||||||
|
- **Word navigation for Input component**: Added Ctrl+Left/Right and Alt+Left/Right support for word-by-word cursor movement. ([#306](https://github.com/badlogic/pi-mono/pull/306) by [@kim0](https://github.com/kim0))
|
||||||
|
- **Full Unicode input**: Input component now accepts Unicode characters beyond ASCII. ([#306](https://github.com/badlogic/pi-mono/pull/306) by [@kim0](https://github.com/kim0))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Readline-style Ctrl+W**: Now skips trailing whitespace before deleting the preceding word, matching standard readline behavior. ([#306](https://github.com/badlogic/pi-mono/pull/306) by [@kim0](https://github.com/kim0))
|
||||||
Loading…
Add table
Add a link
Reference in a new issue