@@ -1838,6 +1838,113 @@ impl Session {
18381838 . await
18391839 . map_err ( |e| napi:: Error :: from_reason ( format ! ( "Task join error: {e}" ) ) )
18401840 }
1841+
1842+ // ========================================================================
1843+ // Slash Command & Scheduler API
1844+ // ========================================================================
1845+
1846+ /// List all registered slash commands.
1847+ ///
1848+ /// Returns each command's name, description, and optional usage hint.
1849+ /// Slash commands can be invoked via `session.send("/command args")`.
1850+ ///
1851+ /// @returns Array of CommandInfo objects sorted by name
1852+ #[ napi]
1853+ pub fn list_commands ( & self ) -> Vec < CommandInfo > {
1854+ self . inner
1855+ . command_registry ( )
1856+ . list_full ( )
1857+ . into_iter ( )
1858+ . map ( |( name, description, usage) | CommandInfo {
1859+ name,
1860+ description,
1861+ usage,
1862+ } )
1863+ . collect ( )
1864+ }
1865+
1866+ /// Schedule a recurring prompt to fire at a given interval.
1867+ ///
1868+ /// This is the programmatic equivalent of `/loop <interval>s <prompt>`.
1869+ /// The scheduled prompt runs automatically after each `send()` call when it is due.
1870+ ///
1871+ /// @param prompt - The prompt to send at each interval
1872+ /// @param intervalSecs - Interval in seconds (minimum: 1)
1873+ /// @returns 8-char hex task ID (use with `cancelScheduledTask`)
1874+ #[ napi]
1875+ pub fn schedule_task ( & self , prompt : String , interval_secs : u32 ) -> napi:: Result < String > {
1876+ self . inner
1877+ . cron_scheduler ( )
1878+ . create_task (
1879+ prompt,
1880+ std:: time:: Duration :: from_secs ( interval_secs as u64 ) ,
1881+ true ,
1882+ )
1883+ . map_err ( napi:: Error :: from_reason)
1884+ }
1885+
1886+ /// List all active scheduled tasks for this session.
1887+ ///
1888+ /// @returns Array of ScheduledTaskInfo objects sorted by task ID
1889+ #[ napi]
1890+ pub fn list_scheduled_tasks ( & self ) -> Vec < ScheduledTaskInfo > {
1891+ self . inner
1892+ . cron_scheduler ( )
1893+ . list_tasks ( )
1894+ . into_iter ( )
1895+ . map ( |t| ScheduledTaskInfo {
1896+ id : t. id ,
1897+ prompt : t. prompt ,
1898+ interval_secs : t. interval_secs as i64 ,
1899+ recurring : t. recurring ,
1900+ fire_count : t. fire_count as i64 ,
1901+ next_fire_in_secs : t. next_fire_in_secs as i64 ,
1902+ } )
1903+ . collect ( )
1904+ }
1905+
1906+ /// Cancel a scheduled task by ID.
1907+ ///
1908+ /// @param id - Task ID returned by `scheduleTask` or listed by `listScheduledTasks`
1909+ /// @returns `true` if the task was found and cancelled
1910+ #[ napi]
1911+ pub fn cancel_scheduled_task ( & self , id : String ) -> bool {
1912+ self . inner . cron_scheduler ( ) . cancel_task ( & id)
1913+ }
1914+ }
1915+
1916+ // ============================================================================
1917+ // Slash Command Types
1918+ // ============================================================================
1919+
1920+ /// Metadata about a registered slash command.
1921+ #[ napi( object) ]
1922+ #[ derive( Clone ) ]
1923+ pub struct CommandInfo {
1924+ /// Command name without the leading `/` (e.g., `"loop"`, `"help"`)
1925+ pub name : String ,
1926+ /// Short description shown in `/help`
1927+ pub description : String ,
1928+ /// Optional usage hint (e.g., `"/loop [interval] <prompt> [every <interval>]"`)
1929+ pub usage : Option < String > ,
1930+ }
1931+
1932+ /// Info about an active scheduled task.
1933+ #[ napi( object) ]
1934+ #[ derive( Clone ) ]
1935+ pub struct ScheduledTaskInfo {
1936+ /// 8-char hex task ID
1937+ pub id : String ,
1938+ /// The prompt sent at each interval
1939+ pub prompt : String ,
1940+ /// Interval between fires in seconds
1941+ pub interval_secs : i64 ,
1942+ /// Whether the task repeats (always `true` for tasks created via `/loop`)
1943+ pub recurring : bool ,
1944+ /// Number of times this task has fired so far
1945+ pub fire_count : i64 ,
1946+ /// Seconds until the next fire (0 if overdue)
1947+ pub next_fire_in_secs : i64 ,
18411948}
18421949
18431950// ============================================================================
0 commit comments