@oh-my-pi/pi-coding-agent 13.12.8 → 13.12.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -150,6 +150,13 @@ export interface TtsrInjectionEntry extends SessionEntryBase {
150
150
  injectedRules: string[];
151
151
  }
152
152
 
153
+ /** Persisted MCP discovery selection state for a session branch. */
154
+ export interface MCPToolSelectionEntry extends SessionEntryBase {
155
+ type: "mcp_tool_selection";
156
+ /** MCP tool names selected for visibility in discovery mode. */
157
+ selectedToolNames: string[];
158
+ }
159
+
153
160
  /** Session init entry - captures initial context for subagent sessions (debugging/replay). */
154
161
  export interface SessionInitEntry extends SessionEntryBase {
155
162
  type: "session_init";
@@ -206,6 +213,7 @@ export type SessionEntry =
206
213
  | CustomMessageEntry
207
214
  | LabelEntry
208
215
  | TtsrInjectionEntry
216
+ | MCPToolSelectionEntry
209
217
  | SessionInitEntry
210
218
  | ModeChangeEntry;
211
219
 
@@ -228,6 +236,10 @@ export interface SessionContext {
228
236
  models: Record<string, string>;
229
237
  /** Names of TTSR rules that have been injected this session */
230
238
  injectedTtsrRules: string[];
239
+ /** MCP tool names selected through discovery for this session branch. */
240
+ selectedMCPToolNames: string[];
241
+ /** Whether this branch contains an explicit persisted MCP selection entry. */
242
+ hasPersistedMCPToolSelection: boolean;
231
243
  /** Active mode (e.g. "plan") or "none" if no special mode is active */
232
244
  mode: string;
233
245
  /** Mode-specific data from the last mode_change entry */
@@ -499,6 +511,8 @@ export function buildSessionContext(
499
511
  serviceTier: undefined,
500
512
  models: {},
501
513
  injectedTtsrRules: [],
514
+ selectedMCPToolNames: [],
515
+ hasPersistedMCPToolSelection: false,
502
516
  mode: "none",
503
517
  };
504
518
  }
@@ -517,6 +531,8 @@ export function buildSessionContext(
517
531
  serviceTier: undefined,
518
532
  models: {},
519
533
  injectedTtsrRules: [],
534
+ selectedMCPToolNames: [],
535
+ hasPersistedMCPToolSelection: false,
520
536
  mode: "none",
521
537
  };
522
538
  }
@@ -535,6 +551,8 @@ export function buildSessionContext(
535
551
  const models: Record<string, string> = {};
536
552
  let compaction: CompactionEntry | null = null;
537
553
  const injectedTtsrRulesSet = new Set<string>();
554
+ let selectedMCPToolNames: string[] = [];
555
+ let hasPersistedMCPToolSelection = false;
538
556
  let mode = "none";
539
557
  let modeData: Record<string, unknown> | undefined;
540
558
 
@@ -559,6 +577,9 @@ export function buildSessionContext(
559
577
  for (const ruleName of entry.injectedRules) {
560
578
  injectedTtsrRulesSet.add(ruleName);
561
579
  }
580
+ } else if (entry.type === "mcp_tool_selection") {
581
+ selectedMCPToolNames = [...entry.selectedToolNames];
582
+ hasPersistedMCPToolSelection = true;
562
583
  } else if (entry.type === "mode_change") {
563
584
  mode = entry.mode;
564
585
  modeData = entry.data;
@@ -648,7 +669,17 @@ export function buildSessionContext(
648
669
  }
649
670
  }
650
671
 
651
- return { messages, thinkingLevel, serviceTier, models, injectedTtsrRules, mode, modeData };
672
+ return {
673
+ messages,
674
+ thinkingLevel,
675
+ serviceTier,
676
+ models,
677
+ injectedTtsrRules,
678
+ selectedMCPToolNames,
679
+ hasPersistedMCPToolSelection,
680
+ mode,
681
+ modeData,
682
+ };
652
683
  }
653
684
 
654
685
  /**
@@ -2116,6 +2147,23 @@ export class SessionManager {
2116
2147
  // TTSR (Time Traveling Stream Rules)
2117
2148
  // =========================================================================
2118
2149
 
2150
+ /**
2151
+ * Append an MCP tool selection entry recording the discovery-selected MCP tools.
2152
+ * @param selectedToolNames MCP tool names selected for this branch
2153
+ * @returns Entry id
2154
+ */
2155
+ appendMCPToolSelection(selectedToolNames: string[]): string {
2156
+ const entry: MCPToolSelectionEntry = {
2157
+ type: "mcp_tool_selection",
2158
+ id: generateId(this.#byId),
2159
+ parentId: this.#leafId,
2160
+ timestamp: new Date().toISOString(),
2161
+ selectedToolNames: [...selectedToolNames],
2162
+ };
2163
+ this.#appendEntry(entry);
2164
+ return entry.id;
2165
+ }
2166
+
2119
2167
  /**
2120
2168
  * Append a TTSR injection entry recording which rules were injected.
2121
2169
  * @param ruleNames Names of rules that were injected
@@ -1,4 +1,5 @@
1
1
  import * as fs from "node:fs";
2
+ import * as fsp from "node:fs/promises";
2
3
  import * as path from "node:path";
3
4
  import { isEnoent, toError } from "@oh-my-pi/pi-utils";
4
5
 
@@ -184,6 +185,32 @@ export class FileSessionStorage implements SessionStorage {
184
185
  openWriter(path: string, options?: { flags?: "a" | "w"; onError?: (err: Error) => void }): SessionStorageWriter {
185
186
  return new FileSessionStorageWriter(path, options);
186
187
  }
188
+
189
+ /**
190
+ * Delete a session file and its artifacts directory.
191
+ * Artifacts are stored in a sibling directory with the same name minus .jsonl extension.
192
+ */
193
+ async deleteSessionWithArtifacts(sessionPath: string): Promise<void> {
194
+ // Delete the session file itself
195
+ await this.unlink(sessionPath);
196
+
197
+ // Compute artifacts directory: /path/to/session.jsonl -> /path/to/session
198
+ const artifactsDir = sessionPath.slice(0, -6);
199
+
200
+ // Delete artifacts directory if it exists. Missing directories are fine, but
201
+ // surface real cleanup failures because the session file is already gone.
202
+ try {
203
+ await fsp.rm(artifactsDir, { recursive: true, force: true });
204
+ } catch (err) {
205
+ const error = toError(err);
206
+ throw new Error(
207
+ `Session file deleted but failed to remove artifacts directory ${artifactsDir}: ${error.message}`,
208
+ {
209
+ cause: error,
210
+ },
211
+ );
212
+ }
213
+ }
187
214
  }
188
215
 
189
216
  function matchesPattern(name: string, pattern: string): boolean {
@@ -229,8 +229,20 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
229
229
  },
230
230
  {
231
231
  name: "session",
232
- description: "Show session info and stats",
233
- handle: async (_command, runtime) => {
232
+ description: "Session management commands",
233
+ subcommands: [
234
+ { name: "info", description: "Show session info and stats" },
235
+ { name: "delete", description: "Delete current session and return to selector" },
236
+ ],
237
+ allowArgs: true,
238
+ handle: async (command, runtime) => {
239
+ const sub = command.args.trim().toLowerCase() || "info";
240
+ if (sub === "delete") {
241
+ runtime.ctx.editor.setText("");
242
+ await runtime.ctx.handleSessionDeleteCommand();
243
+ return;
244
+ }
245
+ // Default: show session info
234
246
  await runtime.ctx.handleSessionCommand();
235
247
  runtime.ctx.editor.setText("");
236
248
  },