wendkeep 0.68.1 → 0.68.6

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.
@@ -1,5 +1,5 @@
1
1
  import {
2
- isBootstrapPrompt,
2
+ isSyntheticTranscriptText,
3
3
  redactSecrets,
4
4
  sanitizeAssistantMessage,
5
5
  } from './prompt-content.mjs';
@@ -20,14 +20,8 @@ function extractContentText(content) {
20
20
  .trim();
21
21
  }
22
22
 
23
- const SYNTHETIC_EVENT_TAG = /^<\/?(?:task-notification|system-reminder|local-command-stdout|local-command-stderr|command-message|command-name|command-args|user-prompt-submit-hook|ide_selection|ide_opened_file|environment_context)\b/i;
24
-
25
23
  function shouldIgnoreUserText(text) {
26
- const trimmed = String(text || '').trim();
27
- return SYNTHETIC_EVENT_TAG.test(trimmed)
28
- || isBootstrapPrompt(trimmed)
29
- || /^Generate a concise( UI)? title/i.test(trimmed)
30
- || /^You are a helpful assistant\. You will be presented with a user prompt/i.test(trimmed);
24
+ return isSyntheticTranscriptText(text);
31
25
  }
32
26
 
33
27
  function addUnique(list, value) {
@@ -180,6 +174,16 @@ export function completedCodexTurnIdsContent(content = '') {
180
174
  return completed;
181
175
  }
182
176
 
177
+ export function abortedCodexTurnIdsContent(content = '') {
178
+ const aborted = new Set();
179
+ for (const event of jsonLines(content)) {
180
+ if (event.type !== 'event_msg' || event.payload?.type !== 'turn_aborted') continue;
181
+ const turnId = String(event.payload?.turn_id || event.turn_id || '').trim();
182
+ if (turnId) aborted.add(turnId);
183
+ }
184
+ return aborted;
185
+ }
186
+
183
187
  export function parseCodexTranscriptContent(content, options = {}) {
184
188
  const result = createResult('codex');
185
189
  const eventUserPrompts = [];
@@ -208,6 +212,11 @@ export function parseCodexTranscriptContent(content, options = {}) {
208
212
  ensureTurn(result.latestTurnId, event.timestamp);
209
213
  continue;
210
214
  }
215
+ if (event.type === 'event_msg' && event.payload?.type === 'turn_aborted') {
216
+ const turn = ensureTurn(event.payload.turn_id || event.turn_id || result.latestTurnId, event.timestamp);
217
+ turn.status = 'aborted';
218
+ continue;
219
+ }
211
220
  if (event.type === 'turn_context') {
212
221
  result.latestTurnId = event.payload?.turn_id || result.latestTurnId;
213
222
  result.model = event.payload?.model || result.model;
@@ -280,6 +289,26 @@ export function parseCodexTranscriptContent(content, options = {}) {
280
289
  }
281
290
  }
282
291
  }
292
+ if (payload.type === 'custom_tool_call') {
293
+ const name = payload.name || payload.tool_name || payload.tool || 'custom_tool_call';
294
+ const turn = ensureTurn(payload.turn_id || event.turn_id || result.latestTurnId, event.timestamp);
295
+ addUnique(result.tools, name);
296
+ addUnique(turn.tools, name);
297
+ const parsed = parseToolArguments(payload.arguments ?? payload.input ?? payload.parameters);
298
+ const combined = typeof parsed.raw === 'string' ? parsed.raw : toolArgumentText(parsed);
299
+ for (const path of extractPaths(combined, paths)) {
300
+ addUnique(result.consultedFiles, path);
301
+ addUnique(turn.consultedFiles, path);
302
+ }
303
+ for (const path of extractPatchFiles(combined)) {
304
+ addUnique(result.changedFiles, path);
305
+ addUnique(turn.changedFiles, path);
306
+ }
307
+ }
308
+ if (payload.type === 'custom_tool_call_output') {
309
+ // A custom tool output closes an existing call; it is deliberately not a second tool.
310
+ ensureTurn(payload.turn_id || event.turn_id || result.latestTurnId, event.timestamp);
311
+ }
283
312
  if (payload.type === 'tool_search_call') {
284
313
  const turn = ensureTurn(payload.turn_id || event.turn_id || result.latestTurnId, event.timestamp);
285
314
  addUnique(result.tools, 'tool_search');
@@ -446,6 +446,27 @@ function currentEventFromRecord(record) {
446
446
  return { ...record.source, value: record.value, revision: record.revision };
447
447
  }
448
448
 
449
+ function supersededTransitively(superseded, sourceEventId, finalEventId) {
450
+ if (!sourceEventId || !finalEventId || sourceEventId === finalEventId) return false;
451
+ const edges = new Map();
452
+ for (const item of superseded) {
453
+ if (!edges.has(item.event_id)) edges.set(item.event_id, []);
454
+ edges.get(item.event_id).push(item.by_event_id);
455
+ }
456
+ const pending = [sourceEventId];
457
+ const visited = new Set();
458
+ while (pending.length) {
459
+ const current = pending.shift();
460
+ if (visited.has(current)) continue;
461
+ visited.add(current);
462
+ for (const next of edges.get(current) || []) {
463
+ if (next === finalEventId) return true;
464
+ if (!visited.has(next)) pending.push(next);
465
+ }
466
+ }
467
+ return false;
468
+ }
469
+
449
470
  function isCausallyOlder(event, current) {
450
471
  if (!current) return false;
451
472
  if (sameCausalActivation(event, current)) {
@@ -636,6 +657,24 @@ export function reduceMemoryEvents(inputEvents = [], {
636
657
  }
637
658
  records.set(item.memory_key, { value: item.value, revision: current.revision + 1, source: item });
638
659
  tombstones.delete(item.memory_key);
660
+ const explicitlySupersededIds = new Set(
661
+ Array.isArray(item.supersedes)
662
+ ? item.supersedes
663
+ : (item.supersedes_event_id ? [item.supersedes_event_id] : []),
664
+ );
665
+ if (item.candidate_decision?.action === 'promote' && explicitlySupersededIds.size) {
666
+ for (const candidate of candidates) {
667
+ if (candidate.reason !== 'conflict' || !candidate.event_ids?.length) continue;
668
+ if (candidate.event_ids.every((eventId) => explicitlySupersededIds.has(eventId))) {
669
+ resolvedCandidateIds.add(candidate.candidate_id);
670
+ }
671
+ }
672
+ for (const pending of pendingAssertConflicts) {
673
+ if (explicitlySupersededIds.has(pending.event.event_id)) {
674
+ resolvedCandidateIds.add(pending.candidate.candidate_id);
675
+ }
676
+ }
677
+ }
639
678
  revision += 1;
640
679
  appliedEventIds.push(item.event_id);
641
680
  }
@@ -680,13 +719,36 @@ export function reduceMemoryEvents(inputEvents = [], {
680
719
  }
681
720
  }
682
721
 
722
+ const pendingByCandidateId = new Map(
723
+ pendingAssertConflicts.map((pending) => [pending.candidate.candidate_id, pending]),
724
+ );
725
+ const reanchoredCandidates = candidates
726
+ .map((candidate) => {
727
+ const pending = pendingByCandidateId.get(candidate.candidate_id);
728
+ if (!pending) return candidate;
729
+ const finalSource = currentEventFromRecord(records.get(candidate.memory_key));
730
+ const previousSource = candidate.events?.find(
731
+ (event) => event.event_id !== pending.event.event_id,
732
+ );
733
+ if (!finalSource || !previousSource || finalSource.event_id === previousSource.event_id) {
734
+ return candidate;
735
+ }
736
+ if (!sameCompleteCausalLineage(previousSource, finalSource)
737
+ || !supersededTransitively(superseded, previousSource.event_id, finalSource.event_id)) {
738
+ return candidate;
739
+ }
740
+ if (hashMemoryValue(finalSource.value) === hashMemoryValue(pending.event.value)) return null;
741
+ return conflictCandidate(candidate.memory_key, [finalSource, pending.event], finalSource);
742
+ })
743
+ .filter(Boolean);
744
+
683
745
  const stateEntries = [...records].map(([key, record]) => [key, record.value]);
684
746
  const recordEntries = [...records].map(([key, record]) => [key, record]);
685
747
  const tombstoneEntries = [...tombstones];
686
748
  const state = sortedObject(stateEntries);
687
749
  const recordObject = sortedObject(recordEntries);
688
750
  const tombstoneObject = sortedObject(tombstoneEntries);
689
- const unresolvedCandidates = candidates
751
+ const unresolvedCandidates = reanchoredCandidates
690
752
  .filter((item) => !candidateDecisions.has(item.candidate_id)
691
753
  && !resolvedCandidateIds.has(item.candidate_id));
692
754
  unresolvedCandidates.sort((left, right) => left.candidate_id.localeCompare(right.candidate_id));
package/src/init.mjs CHANGED
@@ -220,6 +220,7 @@ export function mergeCodexHooks(existing, { force = false } = {}) {
220
220
  const owning = groups.find((g) => (g.hooks || []).some(owns));
221
221
  if (owning) {
222
222
  const hk = owning.hooks.find(owns);
223
+ const matcher = CODEX_MATCHER_EVENTS.has(h.event) ? h.matcher : null;
223
224
  // `timeout` is the pre-0.46 key: Codex never read it. Migrate it even without --force,
224
225
  // otherwise the hook keeps running at the 600s default forever.
225
226
  const legacyTimeout = 'timeout' in hk;
@@ -233,6 +234,8 @@ export function mergeCodexHooks(existing, { force = false } = {}) {
233
234
  if (entry.statusMessage) hk.statusMessage = entry.statusMessage;
234
235
  }
235
236
  }
237
+ if (force && matcher) owning.matcher = matcher;
238
+ if (force && !matcher) delete owning.matcher;
236
239
  file.hooks[h.event] = groups;
237
240
  continue;
238
241
  }
package/src/memory.mjs CHANGED
@@ -387,9 +387,16 @@ function promotedSupersedes(vault, candidate, selected) {
387
387
  const memberIds = new Set(Array.isArray(candidate.event_ids) ? candidate.event_ids : []);
388
388
  const ledger = readMemoryLedger(vault);
389
389
  if (ledger.status !== 'ok') throw new Error('Ledger de memória inválido durante a promoção.');
390
- const current = deriveMemoryProjection(vault, ledger.events)
391
- .records?.[candidate.memory_key]?.source;
392
- if (!current?.event_id || memberIds.has(current.event_id)) return [...memberIds].sort();
390
+ const projection = deriveMemoryProjection(vault, ledger.events);
391
+ const current = projection.records?.[candidate.memory_key]?.source;
392
+ if (!current?.event_id) return [...memberIds].sort();
393
+ if (memberIds.has(current.event_id)) {
394
+ projection.superseded
395
+ .filter((item) => item.by_event_id === current.event_id)
396
+ .map((item) => item.event_id)
397
+ .forEach((eventId) => memberIds.add(eventId));
398
+ return [...memberIds].sort();
399
+ }
393
400
 
394
401
  const currentSelectedId = current.candidate_decision?.selected_event_id;
395
402
  const currentSelected = currentSelectedId