@leanandmean/coding-agent 0.74.1-scramjet.25 → 0.74.1-scramjet.27

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.
Files changed (32) hide show
  1. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  2. package/dist/core/agent-session-runtime.js +2 -10
  3. package/dist/core/agent-session-runtime.js.map +1 -1
  4. package/dist/core/agent-session.d.ts +1 -1
  5. package/dist/core/agent-session.d.ts.map +1 -1
  6. package/dist/core/agent-session.js +58 -24
  7. package/dist/core/agent-session.js.map +1 -1
  8. package/dist/core/extensions/index.d.ts +1 -1
  9. package/dist/core/extensions/index.d.ts.map +1 -1
  10. package/dist/core/extensions/index.js.map +1 -1
  11. package/dist/core/extensions/runner.d.ts.map +1 -1
  12. package/dist/core/extensions/runner.js +30 -4
  13. package/dist/core/extensions/runner.js.map +1 -1
  14. package/dist/core/extensions/types.d.ts +12 -0
  15. package/dist/core/extensions/types.d.ts.map +1 -1
  16. package/dist/core/extensions/types.js.map +1 -1
  17. package/dist/core/scramjet-command-parser.d.ts +4 -0
  18. package/dist/core/scramjet-command-parser.d.ts.map +1 -1
  19. package/dist/core/scramjet-command-parser.js +72 -1
  20. package/dist/core/scramjet-command-parser.js.map +1 -1
  21. package/dist/core/session-manager.d.ts +10 -3
  22. package/dist/core/session-manager.d.ts.map +1 -1
  23. package/dist/core/session-manager.js +36 -11
  24. package/dist/core/session-manager.js.map +1 -1
  25. package/dist/index.d.ts +1 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  29. package/dist/modes/interactive/interactive-mode.js +15 -5
  30. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  31. package/docs/models.md +1 -1
  32. package/package.json +3 -3
@@ -30,6 +30,7 @@ import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
30
30
  import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
31
31
  import { emitSessionShutdownEvent, spliceContributedSections } from "./extensions/runner.js";
32
32
  import { expandPromptTemplate } from "./prompt-templates.js";
33
+ import { indexScramjetCommandStarts, restoreScramjetCommandInvocation } from "./scramjet-command-parser.js";
33
34
  import { CURRENT_SESSION_VERSION, getLatestCompactionEntry } from "./session-manager.js";
34
35
  import { createSyntheticSourceInfo } from "./source-info.js";
35
36
  import { buildSystemPromptSections } from "./system-prompt.js";
@@ -76,6 +77,7 @@ export class AgentSession {
76
77
  _followUpMessages = [];
77
78
  /** Messages queued to be included with the next user prompt as context ("asides"). */
78
79
  _pendingNextTurnMessages = [];
80
+ _inputSessionEntries = new WeakMap();
79
81
  // Compaction state
80
82
  _compactionAbortController = undefined;
81
83
  _autoCompactionAbortController = undefined;
@@ -386,7 +388,31 @@ export class AgentSession {
386
388
  event.message.role === "assistant" ||
387
389
  event.message.role === "toolResult") {
388
390
  // Regular LLM message - persist as SessionMessageEntry
389
- this.sessionManager.appendMessage(event.message);
391
+ const messageEntryId = this.sessionManager.appendMessage(event.message);
392
+ if (event.message.role === "user") {
393
+ const sessionEntries = this._inputSessionEntries.get(event.message);
394
+ this._inputSessionEntries.delete(event.message);
395
+ // This try/catch observes only failures thrown synchronously by
396
+ // appendCustomEntry. On the buffered first-turn path (before any
397
+ // assistant message) _persist stores the entry in memory with no I/O,
398
+ // so only metadata *serialization* failures surface here; the deferred
399
+ // disk write happens later in the unguarded appendMessage(assistant)
400
+ // flush, whose throw is swallowed by the _agentEventQueue.catch on the
401
+ // event-handler chain and degrades exact restoration silently.
402
+ for (const entry of sessionEntries ?? []) {
403
+ try {
404
+ this.sessionManager.appendCustomEntry(entry.customType, entry.data, messageEntryId);
405
+ }
406
+ catch (err) {
407
+ this._extensionRunner.emitError({
408
+ extensionPath: `session-entry:${entry.customType}`,
409
+ event: "session_entry_persistence",
410
+ error: `Failed to persist attached input metadata after its user message; exact input restoration may be unavailable: ${err instanceof Error ? err.message : String(err)}`,
411
+ stack: err instanceof Error ? err.stack : undefined,
412
+ });
413
+ }
414
+ }
415
+ }
390
416
  }
391
417
  // Other message types (bashExecution, compactionSummary, branchSummary) are persisted elsewhere
392
418
  // Track assistant message for auto-compaction (checked on agent_end)
@@ -889,6 +915,8 @@ export class AgentSession {
889
915
  const expandPromptTemplates = options?.expandPromptTemplates ?? true;
890
916
  const preflightResult = options?.preflightResult;
891
917
  let messages;
918
+ let inputSessionEntries;
919
+ let acceptInput;
892
920
  try {
893
921
  // Handle extension commands first (execute immediately, even during streaming)
894
922
  // Extension commands manage their own LLM interaction via pi.sendMessage()
@@ -912,6 +940,8 @@ export class AgentSession {
912
940
  if (inputResult.action === "transform") {
913
941
  currentText = inputResult.text;
914
942
  currentImages = inputResult.images ?? currentImages;
943
+ inputSessionEntries = inputResult.sessionEntries;
944
+ acceptInput = inputResult.onAccepted;
915
945
  }
916
946
  }
917
947
  // Expand skill commands (/skill:name args) and prompt templates (/template args)
@@ -927,11 +957,12 @@ export class AgentSession {
927
957
  "deliverAs when calling dispatchUserInput() or sendUserMessage() — to queue the message.");
928
958
  }
929
959
  if (options.streamingBehavior === "followUp") {
930
- await this._queueFollowUp(expandedText, currentImages);
960
+ await this._queueFollowUp(expandedText, currentImages, inputSessionEntries);
931
961
  }
932
962
  else {
933
- await this._queueSteer(expandedText, currentImages);
963
+ await this._queueSteer(expandedText, currentImages, inputSessionEntries);
934
964
  }
965
+ acceptInput?.();
935
966
  preflightResult?.(true);
936
967
  return;
937
968
  }
@@ -962,11 +993,15 @@ export class AgentSession {
962
993
  if (currentImages) {
963
994
  userContent.push(...currentImages);
964
995
  }
965
- messages.push({
996
+ const userMessage = {
966
997
  role: "user",
967
998
  content: userContent,
968
999
  timestamp: Date.now(),
969
- });
1000
+ };
1001
+ messages.push(userMessage);
1002
+ if (inputSessionEntries?.length) {
1003
+ this._inputSessionEntries.set(userMessage, inputSessionEntries);
1004
+ }
970
1005
  // Inject any pending "nextTurn" messages as context alongside the user message
971
1006
  for (const msg of this._pendingNextTurnMessages) {
972
1007
  messages.push(msg);
@@ -1008,6 +1043,7 @@ export class AgentSession {
1008
1043
  if (!messages) {
1009
1044
  return;
1010
1045
  }
1046
+ acceptInput?.();
1011
1047
  preflightResult?.(true);
1012
1048
  this._runRetryCount = 0;
1013
1049
  await this.agent.prompt(messages);
@@ -1108,34 +1144,42 @@ export class AgentSession {
1108
1144
  /**
1109
1145
  * Internal: Queue a steering message (already expanded, no extension command check).
1110
1146
  */
1111
- async _queueSteer(text, images) {
1147
+ async _queueSteer(text, images, sessionEntries) {
1112
1148
  this._steeringMessages.push(text);
1113
1149
  this._emitQueueUpdate();
1114
1150
  const content = [{ type: "text", text }];
1115
1151
  if (images) {
1116
1152
  content.push(...images);
1117
1153
  }
1118
- this.agent.steer({
1154
+ const message = {
1119
1155
  role: "user",
1120
1156
  content,
1121
1157
  timestamp: Date.now(),
1122
- });
1158
+ };
1159
+ if (sessionEntries?.length) {
1160
+ this._inputSessionEntries.set(message, sessionEntries);
1161
+ }
1162
+ this.agent.steer(message);
1123
1163
  }
1124
1164
  /**
1125
1165
  * Internal: Queue a follow-up message (already expanded, no extension command check).
1126
1166
  */
1127
- async _queueFollowUp(text, images) {
1167
+ async _queueFollowUp(text, images, sessionEntries) {
1128
1168
  this._followUpMessages.push(text);
1129
1169
  this._emitQueueUpdate();
1130
1170
  const content = [{ type: "text", text }];
1131
1171
  if (images) {
1132
1172
  content.push(...images);
1133
1173
  }
1134
- this.agent.followUp({
1174
+ const message = {
1135
1175
  role: "user",
1136
1176
  content,
1137
1177
  timestamp: Date.now(),
1138
- });
1178
+ };
1179
+ if (sessionEntries?.length) {
1180
+ this._inputSessionEntries.set(message, sessionEntries);
1181
+ }
1182
+ this.agent.followUp(message);
1139
1183
  }
1140
1184
  /**
1141
1185
  * Throw an error if the text is an extension command.
@@ -2493,7 +2537,7 @@ export class AgentSession {
2493
2537
  if (targetEntry.type === "message" && targetEntry.message.role === "user") {
2494
2538
  // User message: leaf = parent (null if root), text goes to editor
2495
2539
  newLeafId = targetEntry.parentId;
2496
- editorText = this._extractUserMessageText(targetEntry.message.content);
2540
+ editorText = restoreScramjetCommandInvocation(targetEntry, this.sessionManager.getEntries());
2497
2541
  }
2498
2542
  else if (targetEntry.type === "custom_message") {
2499
2543
  // Custom message: leaf = parent (null if root), text goes to editor
@@ -2557,30 +2601,20 @@ export class AgentSession {
2557
2601
  */
2558
2602
  getUserMessagesForForking() {
2559
2603
  const entries = this.sessionManager.getEntries();
2604
+ const commandStarts = indexScramjetCommandStarts(entries);
2560
2605
  const result = [];
2561
2606
  for (const entry of entries) {
2562
2607
  if (entry.type !== "message")
2563
2608
  continue;
2564
2609
  if (entry.message.role !== "user")
2565
2610
  continue;
2566
- const text = this._extractUserMessageText(entry.message.content);
2611
+ const text = restoreScramjetCommandInvocation(entry, commandStarts);
2567
2612
  if (text) {
2568
2613
  result.push({ entryId: entry.id, text });
2569
2614
  }
2570
2615
  }
2571
2616
  return result;
2572
2617
  }
2573
- _extractUserMessageText(content) {
2574
- if (typeof content === "string")
2575
- return content;
2576
- if (Array.isArray(content)) {
2577
- return content
2578
- .filter((c) => c.type === "text")
2579
- .map((c) => c.text)
2580
- .join("");
2581
- }
2582
- return "";
2583
- }
2584
2618
  /**
2585
2619
  * Get session statistics.
2586
2620
  */