Skip to content

Commit 8f56e5a

Browse files
committed
feat: let session destroy target latest session
1 parent 82ec726 commit 8f56e5a

4 files changed

Lines changed: 64 additions & 7 deletions

File tree

docs/cli-reference.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ List persisted sessions from `.agentpowershell/sessions.json`. Text mode include
5959

6060
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.
6161

62-
### `session destroy <session-id>`
62+
### `session destroy [session-id]`
6363

64-
Remove a session from the session store. Missing sessions return `status: not-found`, `removed: false`, and a non-zero exit code.
64+
Remove a session from the session store. If `session-id` is omitted, the command removes the most recently created session. Missing sessions return `status: not-found`, `removed: false`, and a non-zero exit code.
6565

6666
### `policy validate <path>`
6767

docs/getting-started.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ Show the most recent session:
5151
dotnet run --project src/AgentPowerShell.Cli -- session show --output json
5252
```
5353

54+
Destroy the most recent session:
55+
56+
```powershell
57+
dotnet run --project src/AgentPowerShell.Cli -- session destroy --output json
58+
```
59+
5460
Execute an explicit inline PowerShell command through the current runtime path:
5561

5662
```powershell

src/AgentPowerShell.Cli/CliApp.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,14 +250,19 @@ private static Command BuildSessionCommand(Option<string> outputOption)
250250
}, showSessionId, outputOption);
251251

252252
var destroy = new Command("destroy", "Destroy session");
253-
var sessionId = new Argument<string>("session-id");
253+
var sessionId = new Argument<string?>("session-id", () => null);
254254
destroy.AddArgument(sessionId);
255-
destroy.SetHandler(async (string id, string output) =>
255+
destroy.SetHandler(async (string? id, string output) =>
256256
{
257-
var store = new SessionStore(Path.Combine(Environment.CurrentDirectory, ".agentpowershell", "sessions.json"));
257+
using var store = new SessionStore(GetSessionsPath());
258258
await store.LoadAsync(CancellationToken.None).ConfigureAwait(false);
259-
var removed = await store.RemoveAsync(id, CancellationToken.None).ConfigureAwait(false);
260-
Emit(output, new { command = "session destroy", sessionId = id, removed, status = removed ? "removed" : "not-found" });
259+
var sessions = await store.ListAsync(CancellationToken.None).ConfigureAwait(false);
260+
var resolvedId = string.IsNullOrWhiteSpace(id)
261+
? sessions.Count == 0 ? null : sessions[^1].SessionId
262+
: id;
263+
var removed = !string.IsNullOrWhiteSpace(resolvedId)
264+
&& await store.RemoveAsync(resolvedId, CancellationToken.None).ConfigureAwait(false);
265+
Emit(output, new { command = "session destroy", sessionId = resolvedId ?? id, removed, status = removed ? "removed" : "not-found" });
261266
if (!removed)
262267
{
263268
Environment.ExitCode = 1;

tests/AgentPowerShell.Tests/ExecutionPolicyTests.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,52 @@ public void DaemonLaunchResolver_Falls_Back_To_Source_Project_When_Repo_Is_Avail
16711671
}
16721672
}
16731673

1674+
[Fact]
1675+
public async Task CliApp_SessionDestroy_Uses_Latest_Session_By_Default()
1676+
{
1677+
var root = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid():N}-cli-session-destroy-latest");
1678+
Directory.CreateDirectory(root);
1679+
var originalDirectory = Environment.CurrentDirectory;
1680+
var originalOut = Console.Out;
1681+
1682+
try
1683+
{
1684+
Environment.CurrentDirectory = root;
1685+
1686+
using (var store = new SessionStore(Path.Combine(root, ".agentpowershell", "sessions.json")))
1687+
{
1688+
await store.LoadAsync(CancellationToken.None);
1689+
await store.GetOrCreateAsync("session-a", root, new AgentPowerShellConfig().Sessions, CancellationToken.None);
1690+
await Task.Delay(10);
1691+
await store.GetOrCreateAsync("session-b", root, new AgentPowerShellConfig().Sessions, CancellationToken.None);
1692+
}
1693+
1694+
using var writer = new StringWriter();
1695+
Console.SetOut(writer);
1696+
1697+
Assert.Equal(0, CliApp.Run(["session", "destroy", "--output", "json"]));
1698+
var payload = writer.ToString();
1699+
Assert.Contains("\"command\":\"session destroy\"", payload, StringComparison.Ordinal);
1700+
Assert.Contains("\"sessionId\":\"session-b\"", payload, StringComparison.Ordinal);
1701+
Assert.Contains("\"removed\":true", payload, StringComparison.Ordinal);
1702+
1703+
using var verifyStore = new SessionStore(Path.Combine(root, ".agentpowershell", "sessions.json"));
1704+
await verifyStore.LoadAsync(CancellationToken.None);
1705+
var sessions = await verifyStore.ListAsync(CancellationToken.None);
1706+
Assert.DoesNotContain(sessions, session => session.SessionId == "session-b");
1707+
Assert.Contains(sessions, session => session.SessionId == "session-a");
1708+
}
1709+
finally
1710+
{
1711+
Console.SetOut(originalOut);
1712+
Environment.CurrentDirectory = originalDirectory;
1713+
if (Directory.Exists(root))
1714+
{
1715+
Directory.Delete(root, recursive: true);
1716+
}
1717+
}
1718+
}
1719+
16741720
[Fact]
16751721
public async Task SessionReportGenerator_Builds_Markdown_And_Findings()
16761722
{

0 commit comments

Comments
 (0)