@gkorepanov/ccodex 0.4.15 → 0.4.17

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.
@@ -101,7 +101,7 @@ function commandLane(command) {
101
101
  return "control";
102
102
  if (["providerEventStarted", "providerEventFinished", "providerBoundary", "providerRetract",
103
103
  "conversationReset", "modelFallback", "fastModeStatus", "systemNotice", "runtimeNotification", "mainStream",
104
- "accountUsage", "accountCost", "publishUsage", "lifecycle", "compactBoundary", "compactFailed",
104
+ "accountUsage", "accountCost", "publishUsage", "lifecycle", "autoCompactStarted", "compactBoundary", "compactFailed",
105
105
  "postCompact",
106
106
  ].includes(command.type))
107
107
  return "provider";
@@ -135,6 +135,7 @@ export class ClaudeSession {
135
135
  scopes = new Map();
136
136
  tasks = new Map();
137
137
  compaction;
138
+ automaticCompaction;
138
139
  compactionActions = [];
139
140
  lastPublishedUsage;
140
141
  lifecycle;
@@ -1342,6 +1343,13 @@ export class ClaudeSession {
1342
1343
  if (status === "requesting") {
1343
1344
  await this.providerSubmitLifecycle(projection, runtimeGeneration, { type: "request", messageStarted: false });
1344
1345
  }
1346
+ else if (status === "compacting") {
1347
+ await this.submitProviderProjection(runtimeGeneration, {
1348
+ type: "autoCompactStarted",
1349
+ runtimeGeneration,
1350
+ source: this.providerFactSource(projection),
1351
+ });
1352
+ }
1345
1353
  return "stateOnly";
1346
1354
  }
1347
1355
  if (message.type === "system" && message.subtype === "session_state_changed") {
@@ -4499,10 +4507,15 @@ export class ClaudeSession {
4499
4507
  if (command.runtimeGeneration !== this.runtimeGeneration)
4500
4508
  return { admitted: false, hidden: false };
4501
4509
  return {
4502
- admitted: command.trigger === "auto" ? !this.compaction && Boolean(this.activeNormalTurn())
4510
+ admitted: command.trigger === "auto"
4511
+ ? !this.compaction && Boolean(this.automaticCompaction || this.activeNormalTurn())
4503
4512
  : Boolean(this.compaction && !this.compaction.cancellation),
4504
4513
  hidden: Boolean(this.compaction?.hidden),
4505
4514
  };
4515
+ case "autoCompactStarted":
4516
+ if (command.runtimeGeneration !== this.runtimeGeneration)
4517
+ return undefined;
4518
+ return this.startAutomaticCompaction(command.runtimeGeneration, command.source);
4506
4519
  case "compactBoundary":
4507
4520
  if (command.runtimeGeneration !== this.runtimeGeneration)
4508
4521
  return undefined;
@@ -4528,8 +4541,10 @@ export class ClaudeSession {
4528
4541
  : this.compactionProjection();
4529
4542
  }
4530
4543
  case "compactFailed":
4531
- if (command.runtimeGeneration !== this.runtimeGeneration || !this.compaction)
4544
+ if (command.runtimeGeneration !== this.runtimeGeneration)
4532
4545
  return undefined;
4546
+ if (!this.compaction)
4547
+ return this.completeAutomaticCompaction(command.source);
4533
4548
  if (this.compaction.cancellation)
4534
4549
  return this.compactionProjection();
4535
4550
  return this.completeCompaction("failed", command.message, command.codexErrorInfo, command.source);
@@ -4869,21 +4884,77 @@ export class ClaudeSession {
4869
4884
  if (this.compaction)
4870
4885
  return this.compactionProjection();
4871
4886
  const record = this.requireRecord(true);
4872
- const turn = this.activeNormalTurn(record);
4887
+ const automatic = this.automaticCompaction;
4888
+ const turn = automatic
4889
+ ? this.repository.readTurn(this.threadId, automatic.turnId)
4890
+ : this.activeNormalTurn(record);
4873
4891
  if (!turn)
4874
4892
  return undefined;
4893
+ const item = automatic
4894
+ ? turn.items.find((candidate) => candidate.id === automatic.itemId)
4895
+ : undefined;
4875
4896
  const updated = { ...record, lastClaudeMessageUuid: boundary };
4876
- this.commitState(updated, [{
4897
+ this.commitState(updated, [
4898
+ ...(item?.type === "contextCompaction" ? [{
4899
+ turnId: turn.id,
4900
+ method: "item/completed",
4901
+ params: { item, threadId: this.threadId, turnId: turn.id, completedAtMs: Date.now() },
4902
+ providerEventId: source.providerEventId,
4903
+ providerEventType: source.providerEventType,
4904
+ }] : []),
4905
+ {
4877
4906
  turnId: turn.id,
4878
4907
  method: "thread/compacted",
4879
4908
  params: { threadId: this.threadId, turnId: turn.id },
4880
4909
  providerEventId: source.providerEventId,
4881
4910
  providerEventType: source.providerEventType,
4882
- }], turn, false, {
4911
+ },
4912
+ ], turn, false, {
4883
4913
  ownerThreadId: this.threadId,
4884
4914
  turnId: turn.id,
4885
4915
  messageUuid: boundary,
4886
4916
  });
4917
+ if (automatic)
4918
+ this.automaticCompaction = undefined;
4919
+ return { turnId: turn.id, terminal: false };
4920
+ }
4921
+ startAutomaticCompaction(runtimeGeneration, source) {
4922
+ if (this.compaction)
4923
+ return this.compactionProjection();
4924
+ const turn = this.activeNormalTurn();
4925
+ if (!turn)
4926
+ return undefined;
4927
+ if (this.automaticCompaction?.turnId === turn.id) {
4928
+ return { turnId: turn.id, terminal: false };
4929
+ }
4930
+ const item = {
4931
+ type: "contextCompaction",
4932
+ id: uuidv7(),
4933
+ };
4934
+ turn.items.push(item);
4935
+ this.publishTurn(turn, "item/started", {
4936
+ item, threadId: this.threadId, turnId: turn.id, startedAtMs: Date.now(),
4937
+ }, source);
4938
+ this.automaticCompaction = { turnId: turn.id, itemId: item.id, runtimeGeneration };
4939
+ return { turnId: turn.id, terminal: false };
4940
+ }
4941
+ completeAutomaticCompaction(source) {
4942
+ const automatic = this.automaticCompaction;
4943
+ if (!automatic)
4944
+ return undefined;
4945
+ const record = this.requireRecord(false);
4946
+ const turn = this.repository.readTurn(this.threadId, automatic.turnId);
4947
+ const item = turn?.items.find((candidate) => candidate.id === automatic.itemId);
4948
+ if (!turn || item?.type !== "contextCompaction")
4949
+ return undefined;
4950
+ this.commitState(record, [{
4951
+ turnId: turn.id,
4952
+ method: "item/completed",
4953
+ params: { item, threadId: this.threadId, turnId: turn.id, completedAtMs: Date.now() },
4954
+ providerEventId: source.providerEventId,
4955
+ providerEventType: source.providerEventType,
4956
+ }], turn);
4957
+ this.automaticCompaction = undefined;
4887
4958
  return { turnId: turn.id, terminal: false };
4888
4959
  }
4889
4960
  completeCompaction(status, errorMessage, codexErrorInfo, source, boundary) {
@@ -4933,7 +5004,7 @@ export class ClaudeSession {
4933
5004
  }
4934
5005
  activeNormalTurn(record = this.requireRecord(true)) {
4935
5006
  return record.thread.turns.findLast((turn) => turn.status === "inProgress"
4936
- && !turn.items.some((item) => item.type === "contextCompaction"));
5007
+ && turn.items.some((item) => item.type !== "contextCompaction"));
4937
5008
  }
4938
5009
  startTurn(items, threadPatch = {}, id = uuidv7(), emitEvents = true) {
4939
5010
  const record = this.requireRecord(false);
@@ -5103,7 +5174,21 @@ export class ClaudeSession {
5103
5174
  updatedAt: turn.completedAt, recencyAt: turn.completedAt,
5104
5175
  },
5105
5176
  };
5106
- const events = [...terminalEvents.map((event) => ({
5177
+ const automatic = this.automaticCompaction?.turnId === turn.id
5178
+ ? this.automaticCompaction
5179
+ : undefined;
5180
+ const automaticItem = automatic
5181
+ ? turn.items.find((item) => item.id === automatic.itemId)
5182
+ : undefined;
5183
+ const events = [
5184
+ ...(automaticItem?.type === "contextCompaction" ? [{
5185
+ turnId: turn.id,
5186
+ method: "item/completed",
5187
+ params: { item: automaticItem, threadId: this.threadId, turnId: turn.id, completedAtMs: Date.now() },
5188
+ providerEventId: source.providerEventId,
5189
+ providerEventType: source.providerEventType,
5190
+ }] : []),
5191
+ ...terminalEvents.map((event) => ({
5107
5192
  ...event,
5108
5193
  providerEventId: event.providerEventId ?? source.providerEventId,
5109
5194
  providerEventType: event.providerEventType ?? source.providerEventType,
@@ -5113,7 +5198,8 @@ export class ClaudeSession {
5113
5198
  params: { threadId: this.threadId, status: updated.thread.status },
5114
5199
  providerEventId: source.providerEventId,
5115
5200
  providerEventType: source.providerEventType,
5116
- }];
5201
+ }
5202
+ ];
5117
5203
  if (turn.error && emitError)
5118
5204
  events.push({
5119
5205
  turnId: turn.id,
@@ -5132,6 +5218,8 @@ export class ClaudeSession {
5132
5218
  providerEventType: source.providerEventType,
5133
5219
  });
5134
5220
  this.commitState(updated, events, turn, false, providerBoundary, emitEvents);
5221
+ if (automatic)
5222
+ this.automaticCompaction = undefined;
5135
5223
  return { record: updated, turn };
5136
5224
  }
5137
5225
  goalContext() {