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.
- package/bin/repair-legacy-session.mjs +86 -10
- package/lib/bundle.js +1 -1
- package/lib/client.js +485 -116
- package/lib/core.js +1 -1
- package/lib/index.js +1177 -551
- package/lib/{runtime-zuuBe8x1.js → runtime-0u6dOiF9.js} +33 -1
- package/lib/{starter-resolution-DYeYvfwr.js → starter-resolution-C3yJawlA.js} +5 -5
- package/lib/starter.js +1 -1
- package/lib/testing.js +1 -1
- package/lib/types/src/client/locales.d.ts +15 -0
- package/lib/types/src/client/page-client.d.ts +3 -1
- package/lib/types/src/client/source-contracts.d.ts +6 -1
- package/lib/types/src/host/protocol.d.ts +13 -2
- package/package.json +39 -39
|
@@ -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
|
-
|
|
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-
|
|
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");
|