@code-fixer-23/pi-session-manager 1.0.4 → 1.0.5

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 1.0.5 (2026-07-08)
2
+
3
+ ### 🩹 Fixes
4
+
5
+ - prompt parsing and session-series continuation ([#6](https://github.com/louiss0/pi-packages/pull/6))
6
+
7
+ ### ❤️ Thank You
8
+
9
+ - louiss0 @louiss0
10
+
1
11
  ## 1.0.4 (2026-07-04)
2
12
 
3
13
  ### 🩹 Fixes
@@ -11,6 +11,7 @@ import {
11
11
  handleSessionCleanOlderThan,
12
12
  handleSessionDeleteLast,
13
13
  handleSessionSeries,
14
+ getSessionEntryWithSeries,
14
15
  getSessionSeriesDataTempPath,
15
16
  persistSessionSeriesData,
16
17
  consumePersistedSessionSeriesData,
@@ -254,6 +255,7 @@ describe("persisted session series data", () => {
254
255
  entry: {
255
256
  customType: sessionSeriesEntrySchema.entries.customType.literal,
256
257
  series: "Implement Auth",
258
+ sessionTitle: "Create JWT Token",
257
259
  createdAt: new Date().toISOString(),
258
260
  },
259
261
  };
@@ -279,6 +281,7 @@ describe("persisted session series data", () => {
279
281
  expect(pi.setSessionName).toHaveBeenCalledWith(sessionData.sessionName);
280
282
  expect(pi.appendEntry).toHaveBeenCalledWith(sessionData.entry.customType, {
281
283
  series: sessionData.entry.series,
284
+ sessionTitle: sessionData.entry.sessionTitle,
282
285
  createdAt: sessionData.entry.createdAt,
283
286
  });
284
287
  expect(ctx.ui.notify).toHaveBeenCalledWith(
@@ -288,6 +291,82 @@ describe("persisted session series data", () => {
288
291
  });
289
292
  });
290
293
 
294
+ describe("getSessionEntryWithSeries", () => {
295
+ it("only returns the series entry that matches the current session name", () => {
296
+ const createdAt = new Date().toISOString();
297
+ const lspCoverageEntry = {
298
+ type: "custom",
299
+ customType: sessionSeriesEntrySchema.entries.customType.literal,
300
+ data: {
301
+ series: "LSP Coverage",
302
+ sessionTitle: "Add diagnostics",
303
+ createdAt,
304
+ },
305
+ } as SessionSeriesEntry;
306
+ const authEntry = {
307
+ type: "custom",
308
+ customType: sessionSeriesEntrySchema.entries.customType.literal,
309
+ data: {
310
+ series: "Auth Cleanup",
311
+ sessionTitle: "Fix token refresh",
312
+ createdAt,
313
+ },
314
+ } as SessionSeriesEntry;
315
+
316
+ expect(
317
+ getSessionEntryWithSeries(
318
+ [lspCoverageEntry, authEntry],
319
+ `Auth Cleanup${SESION_TITLE_SEPARATOR}Fix token refresh`,
320
+ ),
321
+ ).toBe(authEntry);
322
+ });
323
+
324
+ it("does not return another session's series entry", () => {
325
+ const createdAt = new Date().toISOString();
326
+ const lspCoverageEntry = {
327
+ type: "custom",
328
+ customType: sessionSeriesEntrySchema.entries.customType.literal,
329
+ data: {
330
+ series: "LSP Coverage",
331
+ sessionTitle: "Add diagnostics",
332
+ createdAt,
333
+ },
334
+ } as SessionSeriesEntry;
335
+
336
+ expect(
337
+ getSessionEntryWithSeries(
338
+ [lspCoverageEntry],
339
+ `Auth Cleanup${SESION_TITLE_SEPARATOR}Fix token refresh`,
340
+ ),
341
+ ).toBeUndefined();
342
+ });
343
+
344
+ it("falls back to the session name when legacy series entries are missing sessionTitle", () => {
345
+ const createdAt = new Date().toISOString();
346
+ const legacyEntry = {
347
+ type: "custom",
348
+ customType: sessionSeriesEntrySchema.entries.customType.literal,
349
+ data: {
350
+ series: "Auth Cleanup",
351
+ createdAt,
352
+ },
353
+ } as unknown as SessionSeriesEntry;
354
+
355
+ expect(
356
+ getSessionEntryWithSeries(
357
+ [legacyEntry],
358
+ `Auth Cleanup${SESION_TITLE_SEPARATOR}Fix token refresh`,
359
+ ),
360
+ ).toEqual({
361
+ ...legacyEntry,
362
+ data: {
363
+ ...legacyEntry.data,
364
+ sessionTitle: "Fix token refresh",
365
+ },
366
+ });
367
+ });
368
+ });
369
+
291
370
  describe("handleSessionCleanInactive", () => {
292
371
  test("gets rid of all sessions that haven't been modified in the last three days", ({
293
372
  sessions,
@@ -507,6 +586,40 @@ describe("handleSessionSeries", () => {
507
586
  );
508
587
  });
509
588
 
589
+ it("stops creating a session series when the series prompt is cancelled", async () => {
590
+ const context = {
591
+ cwd: "/pi-packages",
592
+ newSession: vi.fn<ExtensionCommandContext["newSession"]>(),
593
+ ui: {
594
+ notify: vi.fn<ExtensionUIContext["notify"]>(),
595
+ input: vi
596
+ .fn<ExtensionUIContext["input"]>()
597
+ .mockResolvedValue(undefined),
598
+ },
599
+ } satisfies MockExtenstionCommandContext;
600
+
601
+ await handleSessionSeries(
602
+ "create",
603
+ {
604
+ sessionManagerConfigurator: new SessionManagerConfiguratorMock(),
605
+ sessionFilter: new MockSessionFilter(
606
+ [],
607
+ new MockPastTimestampCalculator(),
608
+ ),
609
+ getSessionEntryWithSeries() {
610
+ return undefined;
611
+ },
612
+ removeSessionFiles() {
613
+ return;
614
+ },
615
+ },
616
+ castToExtensionContext(context),
617
+ );
618
+
619
+ expect(context.ui.input).toHaveBeenCalledTimes(1);
620
+ expect(context.newSession).not.toHaveBeenCalled();
621
+ });
622
+
510
623
  const seriesInput = "Implement Auth";
511
624
  it("keeps asking for a unique trimmed session series when creating", async () => {
512
625
  const sessionCtx = {
@@ -834,6 +947,50 @@ describe("handleSessionSeries", () => {
834
947
  );
835
948
  });
836
949
 
950
+ it("stops creating a new session in a series when the title prompt is cancelled", async () => {
951
+ const selectedSeries = "refactor-auth-middleware";
952
+ const context = {
953
+ cwd: "/user/work/cancel-new-title",
954
+ newSession: vi.fn<ExtensionCommandContext["newSession"]>(),
955
+ ui: {
956
+ notify: vi.fn<ExtensionUIContext["notify"]>(),
957
+ input: vi
958
+ .fn<ExtensionUIContext["input"]>()
959
+ .mockResolvedValue(undefined),
960
+ select: vi
961
+ .fn<ExtensionUIContext["select"]>()
962
+ .mockResolvedValue(selectedSeries),
963
+ },
964
+ } satisfies MockExtenstionCommandContext;
965
+
966
+ await handleSessionSeries(
967
+ "new",
968
+ {
969
+ sessionManagerConfigurator: new SessionManagerConfiguratorMock({
970
+ seriesRecord: {
971
+ [context.cwd]: {
972
+ [selectedSeries]: [],
973
+ },
974
+ },
975
+ }),
976
+ sessionFilter: new MockSessionFilter(
977
+ [],
978
+ new MockPastTimestampCalculator(),
979
+ ),
980
+ getSessionEntryWithSeries() {
981
+ return undefined;
982
+ },
983
+ removeSessionFiles() {
984
+ return;
985
+ },
986
+ },
987
+ castToExtensionContext(context),
988
+ );
989
+
990
+ expect(context.ui.input).toHaveBeenCalledTimes(1);
991
+ expect(context.newSession).not.toHaveBeenCalled();
992
+ });
993
+
837
994
  it("keeps asking for a unique trimmed title when creating a new session in a series", async () => {
838
995
  const selectedSeries = "refactor-auth-middleware";
839
996
 
@@ -922,6 +1079,55 @@ describe("handleSessionSeries", () => {
922
1079
  );
923
1080
  });
924
1081
 
1082
+ it("stops continuing a session in a series when the title prompt is cancelled", async () => {
1083
+ const context = {
1084
+ cwd: "/user/work/cancel-continue-title",
1085
+ sessionManager: {
1086
+ getEntries:
1087
+ vi.fn<ExtensionCommandContext["sessionManager"]["getEntries"]>(),
1088
+ getSessionName: vi
1089
+ .fn<ExtensionCommandContext["sessionManager"]["getSessionName"]>()
1090
+ .mockReturnValue("refactor-auth-middleware--current-task"),
1091
+ },
1092
+ newSession: vi.fn<ExtensionCommandContext["newSession"]>(),
1093
+ ui: {
1094
+ notify: vi.fn<ExtensionUIContext["notify"]>(),
1095
+ input: vi
1096
+ .fn<ExtensionUIContext["input"]>()
1097
+ .mockResolvedValue(undefined),
1098
+ },
1099
+ } satisfies MockExtenstionCommandContext;
1100
+
1101
+ await handleSessionSeries(
1102
+ "continue",
1103
+ {
1104
+ sessionFilter: new MockSessionFilter(
1105
+ [],
1106
+ new MockPastTimestampCalculator(),
1107
+ ),
1108
+ getSessionEntryWithSeries() {
1109
+ return {
1110
+ type: "custom",
1111
+ customType: sessionSeriesEntrySchema.entries.customType.literal,
1112
+ data: {
1113
+ series: "refactor-auth-middleware",
1114
+ sessionTitle: "current-task",
1115
+ createdAt: new Date().toISOString(),
1116
+ },
1117
+ } as SessionSeriesEntry;
1118
+ },
1119
+ sessionManagerConfigurator: new SessionManagerConfiguratorMock(),
1120
+ removeSessionFiles() {
1121
+ return;
1122
+ },
1123
+ },
1124
+ castToExtensionContext(context),
1125
+ );
1126
+
1127
+ expect(context.ui.input).toHaveBeenCalledTimes(1);
1128
+ expect(context.newSession).not.toHaveBeenCalled();
1129
+ });
1130
+
925
1131
  it("continues a session in a series when continue is passed", async () => {
926
1132
  const sessionCtx = {
927
1133
  cwd: "/session/continue",
@@ -935,6 +1141,9 @@ describe("handleSessionSeries", () => {
935
1141
  sessionManager: {
936
1142
  getEntries:
937
1143
  vi.fn<ExtensionCommandContext["sessionManager"]["getEntries"]>(),
1144
+ getSessionName: vi
1145
+ .fn<ExtensionCommandContext["sessionManager"]["getSessionName"]>()
1146
+ .mockReturnValue("refactor-auth-middleware--current-task"),
938
1147
  },
939
1148
  newSession: vi.fn<ExtensionCommandContext["newSession"]>(
940
1149
  async (options) => {
@@ -957,6 +1166,7 @@ describe("handleSessionSeries", () => {
957
1166
  customType: sessionSeriesEntrySchema.entries.customType.literal,
958
1167
  data: {
959
1168
  series: "refactor-auth-middleware",
1169
+ sessionTitle: "current-task",
960
1170
  createdAt: new Date().toISOString(),
961
1171
  },
962
1172
  } as SessionSeriesEntry;
@@ -1010,6 +1220,7 @@ describe("handleSessionSeries", () => {
1010
1220
 
1011
1221
  expect(getSessionEntryWithSeries).toHaveBeenCalledWith(
1012
1222
  context.sessionManager.getEntries.mock.results[0]?.value,
1223
+ context.sessionManager.getSessionName(),
1013
1224
  );
1014
1225
 
1015
1226
  const entry = getSessionEntryWithSeries.mock.results[0]