Skip to content

Commit 7a0ea7a

Browse files
committed
feat: add session show command
1 parent b9c17e2 commit 7a0ea7a

4 files changed

Lines changed: 117 additions & 0 deletions

File tree

docs/cli-reference.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ Create a new session identifier.
5555

5656
List persisted sessions from `.agentpowershell/sessions.json`. Text mode includes the active flag, working directory, created/last/expires timestamps, and policy path. JSON mode emits a stable summary shape.
5757

58+
### `session show [session-id]`
59+
60+
Show one persisted session from `.agentpowershell/sessions.json`. If `session-id` is omitted, the command returns the most recently created session. Missing sessions return `status: not-found` and a non-zero exit code.
61+
5862
### `session destroy <session-id>`
5963

6064
Remove a session from the session store.

docs/getting-started.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ List sessions:
4545
dotnet run --project src/AgentPowerShell.Cli -- session list
4646
```
4747

48+
Show the most recent session:
49+
50+
```powershell
51+
dotnet run --project src/AgentPowerShell.Cli -- session show --output json
52+
```
53+
4854
Execute an explicit inline PowerShell command through the current runtime path:
4955

5056
```powershell

src/AgentPowerShell.Cli/CliApp.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,41 @@ private static Command BuildSessionCommand(Option<string> outputOption)
214214
}
215215
}, outputOption);
216216

217+
var show = new Command("show", "Show one session");
218+
var showSessionId = new Argument<string?>("session-id", () => null);
219+
show.AddArgument(showSessionId);
220+
show.SetHandler(async (string? id, string output) =>
221+
{
222+
using var store = new SessionStore(GetSessionsPath());
223+
await store.LoadAsync(CancellationToken.None).ConfigureAwait(false);
224+
var sessions = await store.ListAsync(CancellationToken.None).ConfigureAwait(false);
225+
226+
var session = string.IsNullOrWhiteSpace(id)
227+
? sessions.Count == 0 ? null : sessions[^1]
228+
: await store.GetAsync(id, CancellationToken.None).ConfigureAwait(false);
229+
230+
if (session is null)
231+
{
232+
Emit(output, new
233+
{
234+
command = "session show",
235+
sessionId = id,
236+
status = "not-found"
237+
});
238+
Environment.ExitCode = 1;
239+
return;
240+
}
241+
242+
var summary = ToSessionSummary(session);
243+
if (string.Equals(output, "json", StringComparison.OrdinalIgnoreCase))
244+
{
245+
Emit(output, new { command = "session show", sessionId = summary.Id, session = summary });
246+
return;
247+
}
248+
249+
Console.WriteLine($"{summary.Id} | active={summary.IsActive} | cwd={summary.WorkingDirectory} | created={summary.CreatedAt:O} | last={summary.LastActivityAt:O} | expires={summary.ExpiresAt:O} | policy={summary.PolicyPath}");
250+
}, showSessionId, outputOption);
251+
217252
var destroy = new Command("destroy", "Destroy session");
218253
var sessionId = new Argument<string>("session-id");
219254
destroy.AddArgument(sessionId);
@@ -227,6 +262,7 @@ private static Command BuildSessionCommand(Option<string> outputOption)
227262

228263
command.AddCommand(create);
229264
command.AddCommand(list);
265+
command.AddCommand(show);
230266
command.AddCommand(destroy);
231267
return command;
232268
}

tests/AgentPowerShell.Tests/ExecutionPolicyTests.cs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,6 +1510,77 @@ public async Task CliApp_SessionList_Text_Mode_Includes_Usable_Metadata()
15101510
}
15111511
}
15121512

1513+
[Fact]
1514+
public async Task CliApp_SessionShow_Json_Mode_Returns_Latest_Session_By_Default()
1515+
{
1516+
var root = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid():N}-cli-session-show-json");
1517+
Directory.CreateDirectory(root);
1518+
var originalDirectory = Environment.CurrentDirectory;
1519+
var originalOut = Console.Out;
1520+
1521+
try
1522+
{
1523+
Environment.CurrentDirectory = root;
1524+
1525+
using (var store = new SessionStore(Path.Combine(root, ".agentpowershell", "sessions.json")))
1526+
{
1527+
await store.LoadAsync(CancellationToken.None);
1528+
await store.GetOrCreateAsync("session-a", root, new AgentPowerShellConfig().Sessions, CancellationToken.None);
1529+
await Task.Delay(10);
1530+
await store.GetOrCreateAsync("session-b", root, new AgentPowerShellConfig().Sessions, CancellationToken.None);
1531+
}
1532+
1533+
using var writer = new StringWriter();
1534+
Console.SetOut(writer);
1535+
1536+
Assert.Equal(0, CliApp.Run(["session", "show", "--output", "json"]));
1537+
var payload = writer.ToString();
1538+
Assert.Contains("\"command\":\"session show\"", payload, StringComparison.Ordinal);
1539+
Assert.Contains("\"sessionId\":\"session-b\"", payload, StringComparison.Ordinal);
1540+
Assert.Contains("\"id\":\"session-b\"", payload, StringComparison.Ordinal);
1541+
}
1542+
finally
1543+
{
1544+
Console.SetOut(originalOut);
1545+
Environment.CurrentDirectory = originalDirectory;
1546+
if (Directory.Exists(root))
1547+
{
1548+
Directory.Delete(root, recursive: true);
1549+
}
1550+
}
1551+
}
1552+
1553+
[Fact]
1554+
public void CliApp_SessionShow_Returns_NotFound_For_Missing_Session()
1555+
{
1556+
var root = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid():N}-cli-session-show-missing");
1557+
Directory.CreateDirectory(root);
1558+
var originalDirectory = Environment.CurrentDirectory;
1559+
var originalOut = Console.Out;
1560+
1561+
try
1562+
{
1563+
Environment.CurrentDirectory = root;
1564+
using var writer = new StringWriter();
1565+
Console.SetOut(writer);
1566+
1567+
Assert.Equal(1, CliApp.Run(["session", "show", "missing-session", "--output", "json"]));
1568+
var payload = writer.ToString();
1569+
Assert.Contains("\"command\":\"session show\"", payload, StringComparison.Ordinal);
1570+
Assert.Contains("\"status\":\"not-found\"", payload, StringComparison.Ordinal);
1571+
Assert.Contains("\"sessionId\":\"missing-session\"", payload, StringComparison.Ordinal);
1572+
}
1573+
finally
1574+
{
1575+
Console.SetOut(originalOut);
1576+
Environment.CurrentDirectory = originalDirectory;
1577+
if (Directory.Exists(root))
1578+
{
1579+
Directory.Delete(root, recursive: true);
1580+
}
1581+
}
1582+
}
1583+
15131584
[Fact]
15141585
public void DaemonLaunchResolver_Uses_Explicit_Dll_Path_When_Configured()
15151586
{

0 commit comments

Comments
 (0)