@@ -20,6 +20,7 @@ typedef ClientCmdHandler =
2020 BuildContext context,
2121 WidgetRef ref, {
2222 required String sessionId,
23+ required String arg,
2324 });
2425
2526class ClientCommand {
@@ -48,9 +49,10 @@ Future<bool> handleClientCommand(
4849 if (! raw.startsWith ('/' )) return false ;
4950 final firstSpace = raw.indexOf (RegExp (r'\s' ));
5051 final name = firstSpace < 0 ? raw.substring (1 ) : raw.substring (1 , firstSpace);
52+ final arg = firstSpace < 0 ? '' : raw.substring (firstSpace + 1 ).trim ();
5153 for (final c in clientCommands) {
5254 if (c.name == name) {
53- await c.handler (context, ref, sessionId: sessionId);
55+ await c.handler (context, ref, sessionId: sessionId, arg : arg );
5456 return true ;
5557 }
5658 }
@@ -61,7 +63,7 @@ final List<ClientCommand> clientCommands = <ClientCommand>[
6163 ClientCommand (
6264 name: 'new' ,
6365 description: 'Start a fresh agent session in the same project' ,
64- handler: (context, ref, {required sessionId}) async {
66+ handler: (context, ref, {required sessionId, required arg }) async {
6567 final session = ref.read (sessionsProvider).byId (sessionId);
6668 if (session == null ) return ;
6769 final messenger = ScaffoldMessenger .of (context);
@@ -81,7 +83,7 @@ final List<ClientCommand> clientCommands = <ClientCommand>[
8183 ClientCommand (
8284 name: 'cancel' ,
8385 description: 'Cancel the current agent turn' ,
84- handler: (context, ref, {required sessionId}) async {
86+ handler: (context, ref, {required sessionId, required arg }) async {
8587 try {
8688 await ref.read (connectionControllerProvider.notifier).request (
8789 MsgType .cmd,
@@ -95,7 +97,7 @@ final List<ClientCommand> clientCommands = <ClientCommand>[
9597 ClientCommand (
9698 name: 'unpair' ,
9799 description: 'Forget the paired desktop server and return to pairing' ,
98- handler: (context, ref, {required sessionId}) async {
100+ handler: (context, ref, {required sessionId, required arg }) async {
99101 await ref.read (connectionControllerProvider.notifier).unpair ();
100102 if (! context.mounted) return ;
101103 context.go ('/pair' );
@@ -104,7 +106,7 @@ final List<ClientCommand> clientCommands = <ClientCommand>[
104106 ClientCommand (
105107 name: 'help' ,
106108 description: 'Show available commands' ,
107- handler: (context, ref, {required sessionId}) async {
109+ handler: (context, ref, {required sessionId, required arg }) async {
108110 final agentCmds = ref.read (commandsProvider (sessionId));
109111 final lines = [
110112 for (final c in clientCommands) '/${c .name } — ${c .description }' ,
@@ -138,7 +140,7 @@ final List<ClientCommand> clientCommands = <ClientCommand>[
138140 name: 'ask' ,
139141 description:
140142 'Debug: ask the server to ask you a question (round-trip test)' ,
141- handler: (context, ref, {required sessionId}) async {
143+ handler: (context, ref, {required sessionId, required arg }) async {
142144 try {
143145 await ref.read (connectionControllerProvider.notifier).request (
144146 MsgType .cmd,
@@ -152,7 +154,7 @@ final List<ClientCommand> clientCommands = <ClientCommand>[
152154 ClientCommand (
153155 name: 'compact' ,
154156 description: 'Compact the conversation to free up context' ,
155- handler: (context, ref, {required sessionId}) async {
157+ handler: (context, ref, {required sessionId, required arg }) async {
156158 final meta = ref.read (sessionMetaProvider (sessionId));
157159 if (meta == null ) {
158160 ScaffoldMessenger .of (context).showSnackBar (
@@ -171,7 +173,7 @@ final List<ClientCommand> clientCommands = <ClientCommand>[
171173 ClientCommand (
172174 name: 'thinking' ,
173175 description: 'Set the agent thinking level' ,
174- handler: (context, ref, {required sessionId}) async {
176+ handler: (context, ref, {required sessionId, required arg }) async {
175177 final level = await _pickThinkingLevel (context);
176178 if (level == null || ! context.mounted) return ;
177179 ref
@@ -185,7 +187,7 @@ final List<ClientCommand> clientCommands = <ClientCommand>[
185187 ClientCommand (
186188 name: 'model' ,
187189 description: 'Switch the agent model' ,
188- handler: (context, ref, {required sessionId}) async {
190+ handler: (context, ref, {required sessionId, required arg }) async {
189191 final meta = ref.read (sessionMetaProvider (sessionId));
190192 final models = meta? .models ?? const [];
191193 if (models.isEmpty) {
@@ -216,8 +218,53 @@ final List<ClientCommand> clientCommands = <ClientCommand>[
216218 ).showSnackBar (SnackBar (content: Text ('Switching to ${picked .name }…' )));
217219 },
218220 ),
221+ ClientCommand (
222+ name: 'name' ,
223+ description: 'Rename this session (shown in the session list)' ,
224+ handler: (context, ref, {required sessionId, required arg}) async {
225+ final title = arg.isNotEmpty ? arg : await _promptSessionName (context);
226+ if (title == null || title.isEmpty || ! context.mounted) return ;
227+ ref
228+ .read (storeControllerProvider.notifier)
229+ .sendSessionAction (sessionId, 'name' , args: {'name' : title});
230+ ScaffoldMessenger .of (
231+ context,
232+ ).showSnackBar (SnackBar (content: Text ('Renamed to “$title ”' )));
233+ },
234+ ),
219235];
220236
237+ /// Prompt for a session name via a simple text dialog. Resolves with the
238+ /// trimmed name, or null if dismissed/empty.
239+ Future <String ?> _promptSessionName (BuildContext context) async {
240+ final controller = TextEditingController ();
241+ final result = await showDialog <String >(
242+ context: context,
243+ builder: (ctx) => AlertDialog (
244+ title: const Text ('Rename session' ),
245+ content: TextField (
246+ controller: controller,
247+ autofocus: true ,
248+ textInputAction: TextInputAction .done,
249+ decoration: const InputDecoration (hintText: 'Session name' ),
250+ onSubmitted: (v) => Navigator .pop (ctx, v.trim ()),
251+ ),
252+ actions: [
253+ TextButton (
254+ onPressed: () => Navigator .pop (ctx),
255+ child: const Text ('Cancel' ),
256+ ),
257+ TextButton (
258+ onPressed: () => Navigator .pop (ctx, controller.text.trim ()),
259+ child: const Text ('Rename' ),
260+ ),
261+ ],
262+ ),
263+ );
264+ controller.dispose ();
265+ return result;
266+ }
267+
221268/// pi's thinking levels, low → high. `off` disables reasoning.
222269const _thinkingLevels = ['off' , 'minimal' , 'low' , 'medium' , 'high' , 'xhigh' ];
223270
0 commit comments