dsh-mnemon 0.5.37 → 0.5.39

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.
@@ -614,6 +614,89 @@ function encodeFrames(text) {
614
614
  return Buffer.concat([text.slice(0, end), text.slice(end)].filter(Boolean).map(part => zlib.zstdCompressSync(part, options)))
615
615
  }
616
616
 
617
+ async function writeRepairCopy(input, output, result) {
618
+ if (resolve(input) === resolve(output)) throw new Error('Output must be a new copy; the input cannot be overwritten.')
619
+ const temporary = await mkdtemp(join(dirname(resolve(output)), '.mnemon-repair-'))
620
+ try {
621
+ const path = join(temporary, 'session')
622
+ const file = await open(path, 'wx', 0o600)
623
+ try { await file.writeFile(result); await file.sync() } finally { await file.close() }
624
+ // Publish exclusively, including when output is a symlink or hard link.
625
+ await link(path, output)
626
+ } finally { await rm(temporary, { recursive: true, force: true }) }
627
+ }
628
+
629
+ /** Preserve the complete audit payload and all offsets; never truncate history. */
630
+ async function repairIdleProbeSession(entries, original, compressed, input, output) {
631
+ const header = entries[0].row
632
+ assertUniqueJson(entries[0].line, header)
633
+ if (header.type !== 'session' || header.version !== 4 || header.isSeeded !== false || header.delegationDepth !== 0 ||
634
+ header.parentSession !== undefined || header.origin !== undefined) throw new Error('Idle probe recovery requires an unseeded v4 root Session.')
635
+ const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u
636
+ const recovered = new Set()
637
+ const pending = new Map()
638
+ const roots = new Set()
639
+ let openTurn
640
+ let completed = false
641
+ const refuse = () => { throw new Error('Unrecognized or incomplete out-of-turn PTC audit; no output written.') }
642
+ for (const entry of entries.slice(1)) {
643
+ const row = entry.row
644
+ if (row.type === 'turn/start' || row.type === 'turn/end') {
645
+ assertUniqueJson(entry.line, row)
646
+ if (pending.size || !count(row.data?.turn)) refuse()
647
+ if (row.type === 'turn/start') {
648
+ if (openTurn !== undefined) refuse()
649
+ openTurn = row.data.turn
650
+ } else {
651
+ if (openTurn !== row.data.turn) refuse()
652
+ openTurn = undefined
653
+ completed = true
654
+ }
655
+ }
656
+ if (!['tool/ptc-dispatch-start', 'tool/ptc-dispatch'].includes(row.type) || openTurn !== undefined) continue
657
+ assertUniqueJson(entry.line, row)
658
+ const data = row.data
659
+ const start = row.type === 'tool/ptc-dispatch-start'
660
+ if (!completed || !exactKeys(row, ['type', 'seq', 'time', 'data']) || !count(row.seq) || !integer(row.time) ||
661
+ !exactKeys(data, ['rootCallId', 'parentCallId', 'subCallId', 'name', 'arguments', ...(start ? [] : ['isError', 'content'])], start ? [] : ['error', 'meta']) ||
662
+ !uuid.test(data.rootCallId) || data.parentCallId !== data.rootCallId || data.subCallId !== `${data.rootCallId}:ptc:1` ||
663
+ data.name !== 'mnemon_subagent_result' || !exactKeys(data.arguments, ['requestId', 'result']) ||
664
+ !uuid.test(data.arguments.requestId) || !exactKeys(data.arguments.result, [])) refuse()
665
+ if (start) {
666
+ if (roots.has(data.rootCallId)) refuse()
667
+ roots.add(data.rootCallId)
668
+ pending.set(data.rootCallId, entry)
669
+ } else {
670
+ const previous = pending.get(data.rootCallId)
671
+ if (!previous || !isDeepStrictEqual(previous.row.data.arguments, data.arguments) || previous.row.seq >= row.seq ||
672
+ typeof data.isError !== 'boolean' || !Array.isArray(data.content) ||
673
+ !data.isError && !isDeepStrictEqual(data.content, [{ type: 'text', text: 'Mnemon subagent result recorded.' }])) refuse()
674
+ pending.delete(data.rootCallId)
675
+ recovered.add(previous)
676
+ recovered.add(entry)
677
+ }
678
+ }
679
+ if (pending.size) refuse()
680
+ const changedSeqs = new Set([...recovered].map(entry => entry.row.seq))
681
+ for (const { row } of entries.slice(1)) {
682
+ for (const range of row.sourceEventSeqs ?? []) {
683
+ if (typeof range === 'number' ? changedSeqs.has(range) : Array.isArray(range) && [...changedSeqs].some(seq => seq >= range[0] && seq <= range[1])) refuse()
684
+ }
685
+ }
686
+ const text = entries.map(entry => recovered.has(entry)
687
+ ? JSON.stringify({ type: 'dsh-mnemon/recovered-idle-probe', seq: entry.row.seq, time: entry.row.time, ignorable: true,
688
+ data: { originalType: entry.row.type, originalData: entry.row.data } }) + '\n'
689
+ : entry.line).join('')
690
+ const plain = Buffer.from(text)
691
+ if (plain.length > maximumBytes) throw new Error('Repaired Session exceeds the 128 MiB repair limit; no output written.')
692
+ const result = recovered.size === 0 ? original : compressed ? encodeFrames(text) : plain
693
+ if (result.length > maximumBytes) throw new Error('Repaired Session exceeds the 128 MiB repair limit; no output written.')
694
+ if (output !== undefined) await writeRepairCopy(input, output, result)
695
+ return { mode: output === undefined ? 'preview' : 'copy', format: 4, encoding: compressed ? 'zstd' : 'jsonl',
696
+ recoveredIdleProbeEvents: recovered.size, inputSha256: sha256(original), outputSha256: sha256(result),
697
+ originalPreserved: true, migrationValidated: false, blockers: [] }
698
+ }
699
+
617
700
  export async function repairLegacySession(input, output) {
618
701
  const original = await readBounded(input)
619
702
  const compressed = original.subarray(0, 4).equals(Buffer.from([0x28, 0xb5, 0x2f, 0xfd]))
@@ -627,6 +710,7 @@ export async function repairLegacySession(input, output) {
627
710
  const entries = lines.map((line, index) => {
628
711
  try { return { line, index, row: JSON.parse(line) } } catch { throw new Error(`Invalid JSON at line ${index + 1}; no output written.`) }
629
712
  })
713
+ if (entries[0]?.row?.version === 4) return repairIdleProbeSession(entries, original, compressed, input, output)
630
714
  const recovery = recoverRecordedToolIdentities(entries)
631
715
  let changes = 0
632
716
  let descriptors = 0
@@ -681,15 +765,7 @@ export async function repairLegacySession(input, output) {
681
765
  if (result.length > maximumBytes) throw new Error('Repaired Session exceeds the 128 MiB repair limit; no output written.')
682
766
  const blockers = diagnostics.report()
683
767
  if (output !== undefined && blockers.length === 0) {
684
- if (resolve(input) === resolve(output)) throw new Error('Output must be a new copy; the input cannot be overwritten.')
685
- const temporary = await mkdtemp(join(dirname(resolve(output)), '.mnemon-repair-'))
686
- try {
687
- const path = join(temporary, 'session')
688
- const file = await open(path, 'wx', 0o600)
689
- try { await file.writeFile(result); await file.sync() } finally { await file.close() }
690
- // Publish exclusively, including when output is a symlink or hard link.
691
- await link(path, output)
692
- } finally { await rm(temporary, { recursive: true, force: true }) }
768
+ await writeRepairCopy(input, output, result)
693
769
  }
694
770
  return {
695
771
  mode: output === undefined ? 'preview' : blockers.length === 0 ? 'copy' : 'refused',
@@ -712,7 +788,7 @@ export async function repairLegacySession(input, output) {
712
788
  }
713
789
 
714
790
  async function main(args) {
715
- const usage = 'Usage: dsh-mnemon-repair-session --input FILE [--output NEW_FILE]\nWithout --output, preview the three known Mnemon v0 summary repairs, exact compatible v2 subagent descriptors, packed deltas with empty IDs/names, property-preserving null-to-empty delta names and proven DeepSeek chains with a previously recorded provider ID. Unsupported descriptor/tool shapes are reported with exit status 1 and prevent output. DSH must still validate the repaired copy. Stop DSH and work on a backup copy. The input and existing output files are never overwritten.'
791
+ const usage = 'Usage: dsh-mnemon-repair-session --input FILE [--output NEW_FILE]\nWithout --output, preview recognized v4 idle-review probe audit recovery or the three known Mnemon v0 summary repairs, exact compatible v2 subagent descriptors, packed deltas with empty IDs/names, property-preserving null-to-empty delta names and proven DeepSeek chains with a previously recorded provider ID. Unsupported descriptor/tool shapes are reported with exit status 1 and prevent output. DSH must still validate the repaired copy. Stop DSH and work on a backup copy. The input and existing output files are never overwritten.'
716
792
  if (args.length === 1 && args[0] === '--help') { console.log(usage); return }
717
793
  const options = new Map()
718
794
  for (let index = 0; index < args.length; index += 2) {
package/lib/bundle.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as prepareStarterResolution } from "./starter-resolution-DYeYvfwr.js";
1
+ import { t as prepareStarterResolution } from "./starter-resolution-C3yJawlA.js";
2
2
  //#region src/bundle.ts
3
3
  const groupKey = Symbol.for("cordis.group");
4
4
  const init = Symbol.for("cordis.init");