@hoilab/ada-cli 0.84.18 → 0.84.19

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.
@@ -380,6 +380,25 @@ export class AgentSession {
380
380
  // =========================================================================
381
381
  // Automatic project memory (claude-mem style)
382
382
  // =========================================================================
383
+ /**
384
+ * Replace vault-expanded secrets with the redacted form for UI events and
385
+ * persistence (the LLM still receives the expanded values via agent state).
386
+ */
387
+ _applyVaultRedaction(event) {
388
+ if (event.message.role !== "user")
389
+ return;
390
+ const id = event.message.id;
391
+ if (!id)
392
+ return;
393
+ const redactedText = this._vaultRedactions.get(id);
394
+ if (redactedText === undefined)
395
+ return;
396
+ this._vaultRedactions.delete(id);
397
+ event.message = {
398
+ ...event.message,
399
+ content: [{ type: "text", text: redactedText }],
400
+ };
401
+ }
383
402
  /** Live-index a message for the Memory Engine session search (layer 3c). */
384
403
  _indexMessageForMemory(message) {
385
404
  const memoryEngine = this._resourceLoader.getMemoryEngine();
@@ -469,8 +488,11 @@ Task: given the CURRENT MEMORY and the LATEST CONVERSATION TURN, produce the COM
469
488
  // Track last assistant message for auto-compaction check
470
489
  _lastAssistantMessage = undefined;
471
490
  _lastAutoMemorizeAt = 0;
472
- /** Redacted user-message content pending persistence (vault expansion). */
473
- _pendingUserRedactions = [];
491
+ /** Vault expansion redactions by user-message id (frontend + persistence). */
492
+ _vaultRedactions = new Map();
493
+ _userMessageSeq = 0;
494
+ /** Pending expansion for the user message built right after (prompt flow). */
495
+ _pendingVaultExpansion = null;
474
496
  /** Internal handler for agent events - shared by subscribe and reconnect */
475
497
  _handleAgentEvent = async (event) => {
476
498
  // When a user message starts, check if it's from either queue and remove it BEFORE emitting
@@ -530,15 +552,9 @@ Task: given the CURRENT MEMORY and the LATEST CONVERSATION TURN, produce the COM
530
552
  else if (event.message.role === "user" ||
531
553
  event.message.role === "assistant" ||
532
554
  event.message.role === "toolResult") {
533
- // Regular LLM message - persist as SessionMessageEntry.
534
- // Vault expansion: persist the REDACTED form so secrets expanded
535
- // from the vault never land in the session file.
536
- let toPersist = event.message;
537
- if (event.message.role === "user" && this._pendingUserRedactions.length > 0) {
538
- const redactedText = this._pendingUserRedactions.shift();
539
- toPersist = { ...event.message, content: [{ type: "text", text: redactedText }] };
540
- }
541
- this.sessionManager.appendMessage(toPersist);
555
+ // Regular LLM message - persist as SessionMessageEntry. Vault
556
+ // expansions are already redacted by _applyVaultRedaction above.
557
+ this.sessionManager.appendMessage(event.message);
542
558
  }
543
559
  // Other message types (bashExecution, compactionSummary, branchSummary) are persisted elsewhere
544
560
  // Track assistant message for auto-compaction (checked on agent_end)
@@ -627,6 +643,7 @@ Task: given the CURRENT MEMORY and the LATEST CONVERSATION TURN, produce the COM
627
643
  this._turnIndex++;
628
644
  }
629
645
  else if (event.type === "message_start") {
646
+ this._applyVaultRedaction(event);
630
647
  const extensionEvent = {
631
648
  type: "message_start",
632
649
  message: event.message,
@@ -642,6 +659,7 @@ Task: given the CURRENT MEMORY and the LATEST CONVERSATION TURN, produce the COM
642
659
  await this._extensionRunner.emit(extensionEvent);
643
660
  }
644
661
  else if (event.type === "message_end") {
662
+ this._applyVaultRedaction(event);
645
663
  const extensionEvent = {
646
664
  type: "message_end",
647
665
  message: event.message,
@@ -1027,7 +1045,10 @@ Task: given the CURRENT MEMORY and the LATEST CONVERSATION TURN, produce the COM
1027
1045
  if (vaultManager) {
1028
1046
  const expansion = expandVaultRefs(expandedText, vaultManager);
1029
1047
  if (expansion.expanded.length > 0) {
1030
- this._pendingUserRedactions.push(expandedText);
1048
+ this._pendingVaultExpansion = {
1049
+ id: `usr-vault-${++this._userMessageSeq}`,
1050
+ redactedText: expandedText,
1051
+ };
1031
1052
  expandedText = expansion.text;
1032
1053
  }
1033
1054
  }
@@ -1075,11 +1096,18 @@ Task: given the CURRENT MEMORY and the LATEST CONVERSATION TURN, produce the COM
1075
1096
  if (currentImages) {
1076
1097
  userContent.push(...currentImages);
1077
1098
  }
1078
- messages.push({
1099
+ const vaultExpansion = this._pendingVaultExpansion;
1100
+ this._pendingVaultExpansion = null;
1101
+ const userMessage = {
1102
+ ...(vaultExpansion ? { id: vaultExpansion.id } : {}),
1079
1103
  role: "user",
1080
1104
  content: userContent,
1081
1105
  timestamp: Date.now(),
1082
- });
1106
+ };
1107
+ if (vaultExpansion) {
1108
+ this._vaultRedactions.set(vaultExpansion.id, vaultExpansion.redactedText);
1109
+ }
1110
+ messages.push(userMessage);
1083
1111
  // Inject any pending "nextTurn" messages as context alongside the user message
1084
1112
  for (const msg of this._pendingNextTurnMessages) {
1085
1113
  messages.push(msg);
@@ -1224,11 +1252,18 @@ Task: given the CURRENT MEMORY and the LATEST CONVERSATION TURN, produce the COM
1224
1252
  if (images) {
1225
1253
  content.push(...images);
1226
1254
  }
1227
- this.agent.steer({
1255
+ const vaultExpansion = this._pendingVaultExpansion;
1256
+ this._pendingVaultExpansion = null;
1257
+ const message = {
1258
+ ...(vaultExpansion ? { id: vaultExpansion.id } : {}),
1228
1259
  role: "user",
1229
1260
  content,
1230
1261
  timestamp: Date.now(),
1231
- });
1262
+ };
1263
+ if (vaultExpansion) {
1264
+ this._vaultRedactions.set(vaultExpansion.id, vaultExpansion.redactedText);
1265
+ }
1266
+ this.agent.steer(message);
1232
1267
  }
1233
1268
  /**
1234
1269
  * Internal: Queue a follow-up message (already expanded, no extension command check).
@@ -1240,11 +1275,19 @@ Task: given the CURRENT MEMORY and the LATEST CONVERSATION TURN, produce the COM
1240
1275
  if (images) {
1241
1276
  content.push(...images);
1242
1277
  }
1243
- this.agent.followUp({
1278
+ const vaultExpansion = this._pendingVaultExpansion;
1279
+ this._pendingVaultExpansion = null;
1280
+ const message = {
1281
+ ...(vaultExpansion ? { id: vaultExpansion.id } : {}),
1244
1282
  role: "user",
1245
1283
  content,
1246
1284
  timestamp: Date.now(),
1247
- });
1285
+ };
1286
+ if (vaultExpansion) {
1287
+ this._vaultRedactions.set(vaultExpansion.id, vaultExpansion.redactedText);
1288
+ }
1289
+ this.agent.followUp(message);
1290
+ return;
1248
1291
  }
1249
1292
  /**
1250
1293
  * Throw an error if the text is an extension command.