dsh-mnemon 0.5.41 → 0.5.42

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/lib/bundle.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as prepareStarterResolution } from "./starter-resolution-xVjONc6g.js";
1
+ import { t as prepareStarterResolution } from "./starter-resolution-B5mdKlvf.js";
2
2
  //#region src/bundle.ts
3
3
  const groupKey = Symbol.for("cordis.group");
4
4
  const init = Symbol.for("cordis.init");
package/lib/client.js CHANGED
@@ -1288,6 +1288,12 @@ window.__ModuleLoader__.load({
1288
1288
  "documents.selectText": "在左侧查看活跃项目知识或沿 Mnemon 引用打开归档原文。",
1289
1289
  "documents.coldArchive": "归档原文",
1290
1290
  "documents.edit": "编辑",
1291
+ "documents.delete": "删除",
1292
+ "documents.deleteConfirm": "永久删除这份档案?",
1293
+ "documents.deleteDescription": "将永久移除档案记录和托管副本,无法撤销。不会建立记忆空间冷索引,也不会修改已有记忆空间条目或项目源文件。",
1294
+ "documents.deleteNow": "永久删除",
1295
+ "documents.deleting": "删除中…",
1296
+ "documents.deleted": "档案已永久删除。",
1291
1297
  "documents.path": "托管路径",
1292
1298
  "documents.revision": "修订",
1293
1299
  "documents.hash": "内容哈希",
@@ -1351,6 +1357,12 @@ window.__ModuleLoader__.load({
1351
1357
  "documents.selectText": "Read active project knowledge or follow a Mnemon reference to an archived original.",
1352
1358
  "documents.coldArchive": "Archived original",
1353
1359
  "documents.edit": "Edit",
1360
+ "documents.delete": "Delete",
1361
+ "documents.deleteConfirm": "Permanently delete this document?",
1362
+ "documents.deleteDescription": "This permanently removes the document record and managed copy and cannot be undone. No Memory Space index is created. Existing Memory Space entries and original project files remain unchanged.",
1363
+ "documents.deleteNow": "Delete permanently",
1364
+ "documents.deleting": "Deleting…",
1365
+ "documents.deleted": "Document permanently deleted.",
1354
1366
  "documents.path": "Managed path",
1355
1367
  "documents.revision": "Revision",
1356
1368
  "documents.hash": "Content hash",
@@ -2786,6 +2798,7 @@ window.__ModuleLoader__.load({
2786
2798
  "board.relationNeeds": "需要“{component}”",
2787
2799
  "board.relationNeededBy": "“{component}”依赖它",
2788
2800
  "options.aria": "“{component}”的选项",
2801
+ "options.emptySourcesConfirm": "当前未选择任何记忆源。保存后 Agent 的热记忆、档案和记忆空间读写将不可用。若想恢复自动选择,请取消并点击恢复默认。确定保存空列表吗?",
2789
2802
  "options.apply": "应用",
2790
2803
  "options.fix": "先修正标出的选项",
2791
2804
  "options.applying": "正在应用…",
@@ -3610,6 +3623,7 @@ window.__ModuleLoader__.load({
3610
3623
  "board.relationNeeds": "Needs “{component}”",
3611
3624
  "board.relationNeededBy": "“{component}” depends on it",
3612
3625
  "options.aria": "Options of “{component}”",
3626
+ "options.emptySourcesConfirm": "No memory sources are selected. Saving disables Agent access to runtime memory, documents and memory spaces. To restore automatic selection, cancel and reset this option to default. Save an empty selection?",
3613
3627
  "options.apply": "Apply",
3614
3628
  "options.fix": "Fix the marked options first",
3615
3629
  "options.applying": "Applying…",
@@ -4588,7 +4602,7 @@ window.__ModuleLoader__.load({
4588
4602
  };
4589
4603
  //#endregion
4590
4604
  //#region \0dsh-mnemon-css:/home/runner/work/dsh-mnemon/dsh-mnemon/plugins/dsh-mnemon-source-documents/presentation/page.module.css.mjs
4591
- const css$10 = ".IIa07q_documentSummary{grid-template-columns:.7fr .7fr 1.6fr;gap:12px;margin-bottom:12px;display:grid}.IIa07q_documentSummary article{border:.5px solid var(--mn-card-line);border-radius:var(--dsw-radius-lg);min-width:0;min-height:92px;padding:14px 16px}.IIa07q_documentSummary article>span{color:var(--mn-faint);font-size:12px;line-height:18px;display:block}.IIa07q_documentSummary article>strong{font-variant-numeric:tabular-nums;margin:4px 0 2px;font-size:20px;font-weight:500;line-height:28px;display:block}.IIa07q_documentSummary article>small{color:var(--mn-faint);font-size:12px;line-height:18px}.IIa07q_documentCapacity>div{background:var(--mn-fill);border-radius:999px;height:4px;margin:8px 0 6px;overflow:hidden}.IIa07q_documentCapacity>div i{border-radius:inherit;background:var(--dsw-alias-brand-primary);height:100%;transition:width .3s;display:block}.IIa07q_documentToolbar{border:.5px solid var(--mn-card-line);border-radius:var(--dsw-radius-lg);align-items:center;gap:8px;margin-bottom:12px;padding:8px;display:flex}.IIa07q_documentToolbar form{flex:1;align-items:center;gap:8px;min-width:260px;display:flex}.IIa07q_documentSearch{flex:1}.IIa07q_documentEditor input,.IIa07q_documentEditor textarea{border:.5px solid var(--mn-field-line);border-radius:var(--dsw-radius-md);width:100%;color:var(--mn-text);background:var(--mn-input);outline:0;padding:6px 10px;font-size:13px;line-height:20px}.IIa07q_documentEditor input:focus,.IIa07q_documentEditor textarea:focus{border-color:var(--mn-accent)}.IIa07q_documentToolbar>div{border-radius:var(--dsw-radius-md);background:var(--mn-hover);align-items:center;gap:2px;padding:3px;display:flex}.IIa07q_documentToolbar>div button{border-radius:var(--dsw-radius-sm);min-height:28px;color:var(--mn-muted);cursor:pointer;background:0 0;border:0;padding:0 12px;font-size:13px;font-weight:500;line-height:20px}.IIa07q_documentToolbar>div button:hover{color:var(--mn-text)}.IIa07q_documentToolbar>div button[data-active]{color:var(--mn-text);background:var(--mn-layer-1);box-shadow:var(--dsw-elevation-soft)}.IIa07q_documentToolbar>div b{color:var(--mn-faint);font-variant-numeric:tabular-nums;margin-left:6px;font-size:12px;font-weight:400}.IIa07q_documentWorkspace{grid-template-columns:minmax(250px,310px) minmax(0,1fr);gap:12px;min-height:590px;display:grid}.IIa07q_documentList,.IIa07q_documentReader{border:.5px solid var(--mn-card-line);border-radius:var(--dsw-radius-lg);min-width:0;overflow:hidden}.IIa07q_documentList{align-self:stretch}.IIa07q_documentList>header{border-bottom:.5px solid var(--mn-line);min-height:44px;color:var(--mn-faint);justify-content:space-between;align-items:center;padding:0 14px;font-size:12px;line-height:18px;display:flex}.IIa07q_documentList>header code{color:var(--mn-muted)}.IIa07q_documentList>button{--mn-provider-color:var(--mn-faint);border-radius:var(--dsw-radius-md);width:calc(100% - 12px);color:var(--mn-text);text-align:left;cursor:pointer;background:0 0;border:0;margin:6px 6px 0;padding:10px 12px;transition:background-color .15s;display:block}.IIa07q_documentList>button:hover{background:var(--mn-hover)}.IIa07q_documentList>button[data-selected]{background:var(--mn-fill)}.IIa07q_documentList>button>div{justify-content:space-between;align-items:baseline;gap:12px;display:flex}.IIa07q_documentList>button strong{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:500;line-height:20px;overflow:hidden}.IIa07q_documentList>button time{color:var(--mn-faint);font-variant-numeric:tabular-nums;flex:none;font-size:11px}.IIa07q_documentList>button p{color:var(--mn-faint);-webkit-line-clamp:2;-webkit-box-orient:vertical;margin:4px 0 6px;font-size:12px;line-height:18px;display:-webkit-box;overflow:hidden}.IIa07q_documentList>button footer{color:var(--mn-faint);align-items:center;gap:8px;font-size:11px;line-height:16px;display:flex}.IIa07q_documentList>button footer code{margin-left:auto}.IIa07q_documentList>button footer em{color:var(--mn-danger);font-style:normal}.IIa07q_documentListEmpty{min-height:230px;color:var(--mn-muted);text-align:center;align-content:center;place-items:center;gap:4px;padding:24px;display:grid}.IIa07q_documentListEmpty>span{color:var(--mn-faint);margin-bottom:6px;font-size:24px;line-height:1}.IIa07q_documentListEmpty p{color:var(--mn-faint);margin:0;font-size:12px;line-height:18px}.IIa07q_documentReader{padding:clamp(16px,2vw,24px)}.IIa07q_documentReader>.IIa07q_emptyState{background:0 0;border:0;height:100%}.IIa07q_documentDetail>header{border-bottom:.5px solid var(--mn-line);justify-content:space-between;align-items:flex-start;gap:16px;padding-bottom:14px;display:flex}.IIa07q_documentDetail>header span{color:var(--mn-faint);font-size:12px;line-height:18px}.IIa07q_documentDetail>header h3{margin:2px 0;font-size:16px;font-weight:500;line-height:24px}.IIa07q_documentDetail>header p{color:var(--mn-faint);margin:0;font-size:12px;line-height:18px}.IIa07q_documentDetail>dl{border:.5px solid var(--mn-line);border-radius:var(--dsw-radius-md);grid-template-columns:2fr .45fr .8fr .55fr;margin:12px 0;display:grid;overflow:hidden}.IIa07q_documentDetail>dl>div{min-width:0;padding:8px 10px}.IIa07q_documentDetail>dl>div+div{border-left:.5px solid var(--mn-line)}.IIa07q_documentDetail dt{color:var(--mn-faint);margin-bottom:2px;font-size:11px;line-height:16px}.IIa07q_documentDetail dd{text-overflow:ellipsis;white-space:nowrap;margin:0;font-size:12px;line-height:18px;overflow:hidden}.IIa07q_documentSources{flex-wrap:wrap;align-items:center;gap:6px;margin:12px 0;display:flex}.IIa07q_documentSources>span{color:var(--mn-faint);margin-right:4px;font-size:12px}.IIa07q_documentSources code,.IIa07q_documentArchiveReceipt code{color:var(--mn-muted);background:var(--mn-fill);border-radius:999px;padding:1px 8px;font-size:11px;line-height:17px}.IIa07q_markdownBody{overflow-wrap:anywhere;border:.5px solid var(--mn-line);border-radius:var(--dsw-radius-md);min-height:310px;color:var(--mn-text);margin:16px 0 0;padding:clamp(16px,2.5vw,28px);font-size:14px;line-height:1.75}.IIa07q_markdownBody>:first-child{margin-top:0}.IIa07q_markdownBody>:last-child{margin-bottom:0}.IIa07q_markdownBody h1,.IIa07q_markdownBody h2,.IIa07q_markdownBody h3,.IIa07q_markdownBody h4{color:var(--mn-text);margin:1.5em 0 .6em;font-weight:500;line-height:1.35}.IIa07q_markdownBody h1{border-bottom:.5px solid var(--mn-line);padding-bottom:.35em;font-size:1.6em}.IIa07q_markdownBody h2{border-bottom:.5px solid var(--mn-line);padding-bottom:.3em;font-size:1.35em}.IIa07q_markdownBody h3{font-size:1.15em}.IIa07q_markdownBody p,.IIa07q_markdownBody ul,.IIa07q_markdownBody ol,.IIa07q_markdownBody blockquote,.IIa07q_markdownBody table,.IIa07q_markdownBody pre{margin:.85em 0}.IIa07q_markdownBody ul,.IIa07q_markdownBody ol{padding-left:1.6em}.IIa07q_markdownBody li+li{margin-top:.3em}.IIa07q_markdownBody blockquote{border-left:2px solid var(--mn-line-strong);color:var(--mn-muted);margin-inline:0;padding:.1em 1em}.IIa07q_markdownBody code{border-radius:var(--dsw-radius-xs);color:var(--mn-text);background:var(--dsw-alias-markdown-inline-code,var(--mn-fill));font:.88em/1.55 var(--mn-code);padding:.15em .4em}.IIa07q_markdownBody pre{border-radius:var(--dsw-radius-md);background:var(--dsw-alias-markdown-code-block,var(--mn-fill));max-width:100%;padding:12px 16px;overflow:auto}.IIa07q_markdownBody pre code{background:0 0;padding:0;font-size:12px}.IIa07q_markdownBody a{color:var(--dsw-alias-link,var(--mn-accent));text-underline-offset:3px;text-decoration-thickness:1px}.IIa07q_markdownBody hr{border:0;border-top:.5px solid var(--mn-line);margin:1.8em 0}.IIa07q_markdownBody table{border-collapse:collapse;max-width:100%;display:block;overflow-x:auto}.IIa07q_markdownBody th,.IIa07q_markdownBody td{border:.5px solid var(--mn-line);text-align:left;vertical-align:top;padding:8px 10px}.IIa07q_markdownBody th{background:var(--mn-fill);font-weight:500}.IIa07q_markdownBody img{border-radius:var(--dsw-radius-sm);max-width:100%;height:auto}.IIa07q_documentArchiveReceipt{border-radius:var(--dsw-radius-md);background:color-mix(in srgb, var(--mn-success) 8%, transparent);margin:12px 0;padding:10px 12px}.IIa07q_documentArchiveReceipt p{color:var(--mn-muted);margin:2px 0 8px;font-size:12px;line-height:18px}.IIa07q_documentArchiveReceipt div{flex-wrap:wrap;gap:6px;display:flex}.IIa07q_documentDanger{border-top:.5px solid var(--mn-line);justify-content:flex-end;align-items:center;gap:8px;min-height:56px;margin-top:12px;padding-top:12px;display:flex}.IIa07q_documentDanger>div{margin-right:auto}.IIa07q_documentDanger strong{font-size:13px;font-weight:500;line-height:20px;display:block}.IIa07q_documentDanger p{color:var(--mn-faint);margin:2px 0 0;font-size:12px;line-height:18px}.IIa07q_documentDanger>span{color:var(--mn-danger);margin-right:auto;font-size:12px}.IIa07q_documentEditor{border:.5px solid var(--mn-card-line);border-radius:var(--dsw-radius-lg);margin-bottom:12px;padding:16px}.IIa07q_documentReader>.IIa07q_documentEditor{background:0 0;border:0;margin:0;padding:0}.IIa07q_documentEditor>header{justify-content:space-between;align-items:flex-start;gap:16px;margin-bottom:12px;display:flex}.IIa07q_documentEditor h3{margin:0;font-size:14px;font-weight:500;line-height:22px}.IIa07q_documentEditor header p{color:var(--mn-faint);margin:2px 0 0;font-size:12px;line-height:18px}.IIa07q_documentEditor header>span,.IIa07q_documentEditor header>code{color:var(--mn-muted);background:var(--mn-fill);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.IIa07q_documentEditor label{color:var(--mn-muted);gap:6px;margin-top:12px;font-size:12px;font-weight:500;line-height:18px;display:grid}.IIa07q_documentEditor textarea{resize:vertical;line-height:1.65}.IIa07q_documentEditorMeta{grid-template-columns:.8fr 1.2fr;gap:12px;display:grid}.IIa07q_documentEditorMeta label{margin:0}.IIa07q_documentEditor footer{justify-content:flex-end;gap:8px;margin-top:12px;display:flex}@media (width<=1000px){.IIa07q_documentWorkspace{grid-template-columns:minmax(220px,270px) minmax(0,1fr)}.IIa07q_documentDetail>dl{grid-template-columns:repeat(2,minmax(0,1fr))}.IIa07q_documentDetail>dl>div+div{border-left:0}.IIa07q_documentDetail>dl>div:nth-child(2n){border-left:.5px solid var(--mn-line)}.IIa07q_documentDetail>dl>div:nth-child(n+3){border-top:.5px solid var(--mn-line)}}@media (width<=760px){.IIa07q_documentSummary{grid-template-columns:repeat(2,minmax(0,1fr))}.IIa07q_documentCapacity{grid-column:1/-1}.IIa07q_documentToolbar{flex-direction:column;align-items:stretch}.IIa07q_documentToolbar form{min-width:0}.IIa07q_documentToolbar>div,.IIa07q_documentToolbar>button{width:100%}.IIa07q_documentToolbar>div button{flex:1}.IIa07q_documentWorkspace{grid-template-columns:1fr;min-height:0}.IIa07q_documentList{-webkit-overflow-scrolling:touch;max-height:330px;overflow:auto}.IIa07q_documentReader{min-height:430px}.IIa07q_documentEditorMeta{grid-template-columns:1fr}}@media (width<=520px){.IIa07q_documentDetail>header,.IIa07q_documentDanger{flex-direction:column;align-items:flex-start}.IIa07q_documentDetail>header>div:last-child,.IIa07q_documentDetail>header button{width:100%}.IIa07q_documentDanger>div,.IIa07q_documentDanger>span{margin-right:0}.IIa07q_documentDanger>button{width:100%}.IIa07q_documentDetail>dl{grid-template-columns:1fr}.IIa07q_documentDetail>dl>div:nth-child(2n){border-left:0}.IIa07q_documentDetail>dl>div+div{border-top:.5px solid var(--mn-line)}.IIa07q_markdownBody{padding:16px;font-size:13px}}";
4605
+ const css$10 = ".IIa07q_documentSummary{grid-template-columns:.7fr .7fr 1.6fr;gap:12px;margin-bottom:12px;display:grid}.IIa07q_documentSummary article{border:.5px solid var(--mn-card-line);border-radius:var(--dsw-radius-lg);min-width:0;min-height:92px;padding:14px 16px}.IIa07q_documentSummary article>span{color:var(--mn-faint);font-size:12px;line-height:18px;display:block}.IIa07q_documentSummary article>strong{font-variant-numeric:tabular-nums;margin:4px 0 2px;font-size:20px;font-weight:500;line-height:28px;display:block}.IIa07q_documentSummary article>small{color:var(--mn-faint);font-size:12px;line-height:18px}.IIa07q_documentCapacity>div{background:var(--mn-fill);border-radius:999px;height:4px;margin:8px 0 6px;overflow:hidden}.IIa07q_documentCapacity>div i{border-radius:inherit;background:var(--dsw-alias-brand-primary);height:100%;transition:width .3s;display:block}.IIa07q_documentToolbar{border:.5px solid var(--mn-card-line);border-radius:var(--dsw-radius-lg);align-items:center;gap:8px;margin-bottom:12px;padding:8px;display:flex}.IIa07q_documentToolbar form{flex:1;align-items:center;gap:8px;min-width:260px;display:flex}.IIa07q_documentSearch{flex:1}.IIa07q_documentEditor input,.IIa07q_documentEditor textarea{border:.5px solid var(--mn-field-line);border-radius:var(--dsw-radius-md);width:100%;color:var(--mn-text);background:var(--mn-input);outline:0;padding:6px 10px;font-size:13px;line-height:20px}.IIa07q_documentEditor input:focus,.IIa07q_documentEditor textarea:focus{border-color:var(--mn-accent)}.IIa07q_documentToolbar>div{border-radius:var(--dsw-radius-md);background:var(--mn-hover);align-items:center;gap:2px;padding:3px;display:flex}.IIa07q_documentToolbar>div button{border-radius:var(--dsw-radius-sm);min-height:28px;color:var(--mn-muted);cursor:pointer;background:0 0;border:0;padding:0 12px;font-size:13px;font-weight:500;line-height:20px}.IIa07q_documentToolbar>div button:hover{color:var(--mn-text)}.IIa07q_documentToolbar>div button[data-active]{color:var(--mn-text);background:var(--mn-layer-1);box-shadow:var(--dsw-elevation-soft)}.IIa07q_documentToolbar>div b{color:var(--mn-faint);font-variant-numeric:tabular-nums;margin-left:6px;font-size:12px;font-weight:400}.IIa07q_documentWorkspace{grid-template-columns:minmax(250px,310px) minmax(0,1fr);gap:12px;min-height:590px;display:grid}.IIa07q_documentList,.IIa07q_documentReader{border:.5px solid var(--mn-card-line);border-radius:var(--dsw-radius-lg);min-width:0;overflow:hidden}.IIa07q_documentList{align-self:stretch}.IIa07q_documentList>header{border-bottom:.5px solid var(--mn-line);min-height:44px;color:var(--mn-faint);justify-content:space-between;align-items:center;padding:0 14px;font-size:12px;line-height:18px;display:flex}.IIa07q_documentList>header code{color:var(--mn-muted)}.IIa07q_documentList>button{--mn-provider-color:var(--mn-faint);border-radius:var(--dsw-radius-md);width:calc(100% - 12px);color:var(--mn-text);text-align:left;cursor:pointer;background:0 0;border:0;margin:6px 6px 0;padding:10px 12px;transition:background-color .15s;display:block}.IIa07q_documentList>button:hover{background:var(--mn-hover)}.IIa07q_documentList>button[data-selected]{background:var(--mn-fill)}.IIa07q_documentList>button>div{justify-content:space-between;align-items:baseline;gap:12px;display:flex}.IIa07q_documentList>button strong{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:500;line-height:20px;overflow:hidden}.IIa07q_documentList>button time{color:var(--mn-faint);font-variant-numeric:tabular-nums;flex:none;font-size:11px}.IIa07q_documentList>button p{color:var(--mn-faint);-webkit-line-clamp:2;-webkit-box-orient:vertical;margin:4px 0 6px;font-size:12px;line-height:18px;display:-webkit-box;overflow:hidden}.IIa07q_documentList>button footer{color:var(--mn-faint);align-items:center;gap:8px;font-size:11px;line-height:16px;display:flex}.IIa07q_documentList>button footer code{margin-left:auto}.IIa07q_documentList>button footer em{color:var(--mn-danger);font-style:normal}.IIa07q_documentListEmpty{min-height:230px;color:var(--mn-muted);text-align:center;align-content:center;place-items:center;gap:4px;padding:24px;display:grid}.IIa07q_documentListEmpty>span{color:var(--mn-faint);margin-bottom:6px;font-size:24px;line-height:1}.IIa07q_documentListEmpty p{color:var(--mn-faint);margin:0;font-size:12px;line-height:18px}.IIa07q_documentReader{padding:clamp(16px,2vw,24px)}.IIa07q_documentReader>.IIa07q_emptyState{background:0 0;border:0;height:100%}.IIa07q_documentDetail>header{border-bottom:.5px solid var(--mn-line);justify-content:space-between;align-items:flex-start;gap:16px;padding-bottom:14px;display:flex}.IIa07q_documentDetail>header span{color:var(--mn-faint);font-size:12px;line-height:18px}.IIa07q_documentDetail>header h3{margin:2px 0;font-size:16px;font-weight:500;line-height:24px}.IIa07q_documentDetail>header p{color:var(--mn-faint);margin:0;font-size:12px;line-height:18px}.IIa07q_documentActions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.IIa07q_documentDetail>dl{border:.5px solid var(--mn-line);border-radius:var(--dsw-radius-md);grid-template-columns:2fr .45fr .8fr .55fr;margin:12px 0;display:grid;overflow:hidden}.IIa07q_documentDetail>dl>div{min-width:0;padding:8px 10px}.IIa07q_documentDetail>dl>div+div{border-left:.5px solid var(--mn-line)}.IIa07q_documentDetail dt{color:var(--mn-faint);margin-bottom:2px;font-size:11px;line-height:16px}.IIa07q_documentDetail dd{text-overflow:ellipsis;white-space:nowrap;margin:0;font-size:12px;line-height:18px;overflow:hidden}.IIa07q_documentSources{flex-wrap:wrap;align-items:center;gap:6px;margin:12px 0;display:flex}.IIa07q_documentSources>span{color:var(--mn-faint);margin-right:4px;font-size:12px}.IIa07q_documentSources code,.IIa07q_documentArchiveReceipt code{color:var(--mn-muted);background:var(--mn-fill);border-radius:999px;padding:1px 8px;font-size:11px;line-height:17px}.IIa07q_markdownBody{overflow-wrap:anywhere;border:.5px solid var(--mn-line);border-radius:var(--dsw-radius-md);min-height:310px;color:var(--mn-text);margin:16px 0 0;padding:clamp(16px,2.5vw,28px);font-size:14px;line-height:1.75}.IIa07q_markdownBody>:first-child{margin-top:0}.IIa07q_markdownBody>:last-child{margin-bottom:0}.IIa07q_markdownBody h1,.IIa07q_markdownBody h2,.IIa07q_markdownBody h3,.IIa07q_markdownBody h4{color:var(--mn-text);margin:1.5em 0 .6em;font-weight:500;line-height:1.35}.IIa07q_markdownBody h1{border-bottom:.5px solid var(--mn-line);padding-bottom:.35em;font-size:1.6em}.IIa07q_markdownBody h2{border-bottom:.5px solid var(--mn-line);padding-bottom:.3em;font-size:1.35em}.IIa07q_markdownBody h3{font-size:1.15em}.IIa07q_markdownBody p,.IIa07q_markdownBody ul,.IIa07q_markdownBody ol,.IIa07q_markdownBody blockquote,.IIa07q_markdownBody table,.IIa07q_markdownBody pre{margin:.85em 0}.IIa07q_markdownBody ul,.IIa07q_markdownBody ol{padding-left:1.6em}.IIa07q_markdownBody li+li{margin-top:.3em}.IIa07q_markdownBody blockquote{border-left:2px solid var(--mn-line-strong);color:var(--mn-muted);margin-inline:0;padding:.1em 1em}.IIa07q_markdownBody code{border-radius:var(--dsw-radius-xs);color:var(--mn-text);background:var(--dsw-alias-markdown-inline-code,var(--mn-fill));font:.88em/1.55 var(--mn-code);padding:.15em .4em}.IIa07q_markdownBody pre{border-radius:var(--dsw-radius-md);background:var(--dsw-alias-markdown-code-block,var(--mn-fill));max-width:100%;padding:12px 16px;overflow:auto}.IIa07q_markdownBody pre code{background:0 0;padding:0;font-size:12px}.IIa07q_markdownBody a{color:var(--dsw-alias-link,var(--mn-accent));text-underline-offset:3px;text-decoration-thickness:1px}.IIa07q_markdownBody hr{border:0;border-top:.5px solid var(--mn-line);margin:1.8em 0}.IIa07q_markdownBody table{border-collapse:collapse;max-width:100%;display:block;overflow-x:auto}.IIa07q_markdownBody th,.IIa07q_markdownBody td{border:.5px solid var(--mn-line);text-align:left;vertical-align:top;padding:8px 10px}.IIa07q_markdownBody th{background:var(--mn-fill);font-weight:500}.IIa07q_markdownBody img{border-radius:var(--dsw-radius-sm);max-width:100%;height:auto}.IIa07q_documentArchiveReceipt{border-radius:var(--dsw-radius-md);background:color-mix(in srgb, var(--mn-success) 8%, transparent);margin:12px 0;padding:10px 12px}.IIa07q_documentArchiveReceipt p{color:var(--mn-muted);margin:2px 0 8px;font-size:12px;line-height:18px}.IIa07q_documentArchiveReceipt div{flex-wrap:wrap;gap:6px;display:flex}.IIa07q_documentDanger{border-top:.5px solid var(--mn-line);justify-content:flex-end;align-items:center;gap:8px;min-height:56px;margin-top:12px;padding-top:12px;display:flex}.IIa07q_documentDanger>div{margin-right:auto}.IIa07q_documentDanger strong{font-size:13px;font-weight:500;line-height:20px;display:block}.IIa07q_documentDanger p{color:var(--mn-faint);margin:2px 0 0;font-size:12px;line-height:18px}.IIa07q_documentDanger>span{color:var(--mn-danger);margin-right:auto;font-size:12px}.IIa07q_documentEditor{border:.5px solid var(--mn-card-line);border-radius:var(--dsw-radius-lg);margin-bottom:12px;padding:16px}.IIa07q_documentReader>.IIa07q_documentEditor{background:0 0;border:0;margin:0;padding:0}.IIa07q_documentEditor>header{justify-content:space-between;align-items:flex-start;gap:16px;margin-bottom:12px;display:flex}.IIa07q_documentEditor h3{margin:0;font-size:14px;font-weight:500;line-height:22px}.IIa07q_documentEditor header p{color:var(--mn-faint);margin:2px 0 0;font-size:12px;line-height:18px}.IIa07q_documentEditor header>span,.IIa07q_documentEditor header>code{color:var(--mn-muted);background:var(--mn-fill);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.IIa07q_documentEditor label{color:var(--mn-muted);gap:6px;margin-top:12px;font-size:12px;font-weight:500;line-height:18px;display:grid}.IIa07q_documentEditor textarea{resize:vertical;line-height:1.65}.IIa07q_documentEditorMeta{grid-template-columns:.8fr 1.2fr;gap:12px;display:grid}.IIa07q_documentEditorMeta label{margin:0}.IIa07q_documentEditor footer{justify-content:flex-end;gap:8px;margin-top:12px;display:flex}@media (width<=1000px){.IIa07q_documentWorkspace{grid-template-columns:minmax(220px,270px) minmax(0,1fr)}.IIa07q_documentDetail>dl{grid-template-columns:repeat(2,minmax(0,1fr))}.IIa07q_documentDetail>dl>div+div{border-left:0}.IIa07q_documentDetail>dl>div:nth-child(2n){border-left:.5px solid var(--mn-line)}.IIa07q_documentDetail>dl>div:nth-child(n+3){border-top:.5px solid var(--mn-line)}}@media (width<=760px){.IIa07q_documentSummary{grid-template-columns:repeat(2,minmax(0,1fr))}.IIa07q_documentCapacity{grid-column:1/-1}.IIa07q_documentToolbar{flex-direction:column;align-items:stretch}.IIa07q_documentToolbar form{min-width:0}.IIa07q_documentToolbar>div,.IIa07q_documentToolbar>button{width:100%}.IIa07q_documentToolbar>div button{flex:1}.IIa07q_documentWorkspace{grid-template-columns:1fr;min-height:0}.IIa07q_documentList{-webkit-overflow-scrolling:touch;max-height:330px;overflow:auto}.IIa07q_documentReader{min-height:430px}.IIa07q_documentEditorMeta{grid-template-columns:1fr}}@media (width<=520px){.IIa07q_documentDetail>header,.IIa07q_documentDanger{flex-direction:column;align-items:flex-start}.IIa07q_documentDetail>header>div:last-child,.IIa07q_documentDetail>header button{width:100%}.IIa07q_documentDanger>div,.IIa07q_documentDanger>span{margin-right:0}.IIa07q_documentDanger>button{width:100%}.IIa07q_documentDetail>dl{grid-template-columns:1fr}.IIa07q_documentDetail>dl>div:nth-child(2n){border-left:0}.IIa07q_documentDetail>dl>div+div{border-top:.5px solid var(--mn-line)}.IIa07q_markdownBody{padding:16px;font-size:13px}}";
4592
4606
  const tagId$9 = "dsh-mnemon-source-documents/presentation/page.module.css";
4593
4607
  if (typeof document !== "undefined") {
4594
4608
  let tag = document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$9) + "]");
@@ -4600,6 +4614,7 @@ window.__ModuleLoader__.load({
4600
4614
  if (tag.textContent !== css$10) tag.textContent = css$10;
4601
4615
  }
4602
4616
  var page_module_css_default$1 = {
4617
+ "documentActions": "IIa07q_documentActions",
4603
4618
  "documentArchiveReceipt": "IIa07q_documentArchiveReceipt",
4604
4619
  "documentCapacity": "IIa07q_documentCapacity",
4605
4620
  "documentDanger": "IIa07q_documentDanger",
@@ -5177,6 +5192,7 @@ window.__ModuleLoader__.load({
5177
5192
  field.input === "source-list" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SourceChoice, {
5178
5193
  field,
5179
5194
  value,
5195
+ defaultAll: entry.typeId === "scoped" && field.key === "sourceKeys",
5180
5196
  sources: props.dashboard.sources,
5181
5197
  name: sourceName,
5182
5198
  labelledBy: `${control}-label`,
@@ -5221,6 +5237,7 @@ window.__ModuleLoader__.load({
5221
5237
  t,
5222
5238
  onDiscard: () => setDraft(initial(entry)),
5223
5239
  onApply: () => {
5240
+ if (entry.typeId === "scoped" && Array.isArray(config.sourceKeys) && config.sourceKeys.length === 0 && !window.confirm(t("options.emptySourcesConfirm"))) return;
5224
5241
  props.onApply(config);
5225
5242
  }
5226
5243
  })]
@@ -5230,9 +5247,15 @@ window.__ModuleLoader__.load({
5230
5247
  function SourceChoice(props) {
5231
5248
  const { field, value, t } = props;
5232
5249
  const eligible = props.sources.filter((source) => field.sourceRoles === void 0 || field.sourceRoles.length === 0 || field.sourceRoles.includes(source.role));
5233
- const missing = value.sources.filter((key) => !eligible.some((source) => source.sourceInstanceKey === key));
5250
+ const defaultRoles = [
5251
+ "working-context",
5252
+ "narrative",
5253
+ "durable-evidence"
5254
+ ];
5255
+ const selected = !value.own && props.defaultAll ? eligible.filter((source) => defaultRoles.includes(source.role)).sort((a, b) => defaultRoles.indexOf(a.role) - defaultRoles.indexOf(b.role) || a.sourceInstanceKey.localeCompare(b.sourceInstanceKey)).map((source) => source.sourceInstanceKey) : value.sources;
5256
+ const missing = selected.filter((key) => !eligible.some((source) => source.sourceInstanceKey === key));
5234
5257
  const several = (sourceTypeId) => eligible.filter((source) => source.sourceTypeId === sourceTypeId).length > 1;
5235
- const toggle = (key, on) => props.onChange(on ? [...value.sources, key] : value.sources.filter((item) => item !== key));
5258
+ const toggle = (key, on) => props.onChange(on ? [...selected, key] : selected.filter((item) => item !== key));
5236
5259
  if (eligible.length === 0 && missing.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5237
5260
  className: MnemonSettingsCard_module_css_default.optionEmpty,
5238
5261
  children: t("options.noSources")
@@ -5244,7 +5267,7 @@ window.__ModuleLoader__.load({
5244
5267
  children: [eligible.map((source) => {
5245
5268
  const label = props.name(source.sourceTypeId, source.label);
5246
5269
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Checkbox, {
5247
- checked: value.sources.includes(source.sourceInstanceKey),
5270
+ checked: selected.includes(source.sourceInstanceKey),
5248
5271
  disabled: props.disabled,
5249
5272
  label: several(source.sourceTypeId) ? `${label} · ${source.sourceInstanceKey}` : label,
5250
5273
  onChange: (on) => toggle(source.sourceInstanceKey, on)
package/lib/index.js CHANGED
@@ -419,7 +419,7 @@ const schema = z.object({
419
419
  const legacySchema = z.object({ sources: z.dict(z.object({ enabled: z.boolean() })).default({}) });
420
420
  const ENTRY_ID$1 = /^[a-zA-Z0-9][a-zA-Z0-9._:/-]{0,299}$/u;
421
421
  const clone$2 = (value) => JSON.parse(JSON.stringify(value));
422
- function record$10(value) {
422
+ function record$11(value) {
423
423
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("Plugin configuration must be an object");
424
424
  const json = JSON.stringify(value);
425
425
  if (json.length > 65536) throw new Error("Plugin configuration exceeds 64 KiB");
@@ -433,13 +433,13 @@ function record$10(value) {
433
433
  }
434
434
  function preferences(value) {
435
435
  if (value.strategyTypeId !== void 0 && !/^[a-z][a-z0-9-]{0,127}$/u.test(value.strategyTypeId)) throw new Error("Invalid Strategy type id");
436
- const entries = record$10(value.entries ?? {});
436
+ const entries = record$11(value.entries ?? {});
437
437
  if (Object.keys(entries).length > 64) throw new Error("At most 64 memory plugin Entries can be configured");
438
438
  for (const [entryId, item] of Object.entries(entries)) {
439
439
  if (!ENTRY_ID$1.test(entryId)) throw new Error("Invalid memory plugin Entry id");
440
- const candidate = record$10(item);
440
+ const candidate = record$11(item);
441
441
  if (candidate.enabled !== void 0 && typeof candidate.enabled !== "boolean") throw new Error("Plugin enabled must be boolean");
442
- record$10(candidate.config);
442
+ record$11(candidate.config);
443
443
  }
444
444
  return clone$2(value);
445
445
  }
@@ -1003,7 +1003,7 @@ function createStorageRoot(config, workspaceRoot) {
1003
1003
  const MNEMON_MACHINE_DIRECTORY = "state";
1004
1004
  const MNEMON_MACHINE_FILE = "machine.json";
1005
1005
  const MNEMON_MACHINE_VERSION = 1;
1006
- function record$9(value) {
1006
+ function record$10(value) {
1007
1007
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
1008
1008
  }
1009
1009
  /** The name a fresh identity carries: the host name, or a neutral fallback. */
@@ -1085,7 +1085,7 @@ var MnemonMachineStore = class {
1085
1085
  } catch {
1086
1086
  return;
1087
1087
  }
1088
- const parsed = record$9(value);
1088
+ const parsed = record$10(value);
1089
1089
  if (parsed?.version !== MNEMON_MACHINE_VERSION) return void 0;
1090
1090
  if (typeof parsed.id !== "string" || parsed.id.trim() === "") return void 0;
1091
1091
  if (typeof parsed.label !== "string" || parsed.label.trim() === "") return void 0;
@@ -2059,7 +2059,7 @@ const COMPONENT_ORDER = MNEMON_PACK_COMPONENTS;
2059
2059
  */
2060
2060
  const CONTENT_HASH = /^[a-f0-9]{64}$/u;
2061
2061
  const SQLITE_HEADER = Buffer.from("SQLite format 3\0", "binary");
2062
- function record$8(value) {
2062
+ function record$9(value) {
2063
2063
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
2064
2064
  }
2065
2065
  function utf8(bytes, label) {
@@ -2122,7 +2122,7 @@ function componentsForScope(scope) {
2122
2122
  }
2123
2123
  /** Exported so the sync channel can read the manifest a commit holds without unpacking the archive. */
2124
2124
  function parseManifest(value) {
2125
- const manifest = record$8(value);
2125
+ const manifest = record$9(value);
2126
2126
  if (manifest?.format !== "mnemonpack" || manifest.version !== 1) throw new Error("unsupported Mnemon Pack format or version");
2127
2127
  if (manifest.scope !== "full" && !COMPONENT_ORDER.includes(manifest.scope)) throw new Error("Mnemon Pack scope is invalid");
2128
2128
  if (typeof manifest.exportedAt !== "string") throw new Error("Mnemon Pack exportedAt is invalid");
@@ -2131,11 +2131,11 @@ function parseManifest(value) {
2131
2131
  if (components.length === 0 || new Set(components).size !== components.length || components.some((component) => !COMPONENT_ORDER.includes(component))) throw new Error("Mnemon Pack components are invalid");
2132
2132
  const expected = componentsForScope(manifest.scope);
2133
2133
  if (components.length !== expected.length || expected.some((component) => !components.includes(component))) throw new Error("Mnemon Pack scope does not match its components");
2134
- const source = record$8(manifest.source);
2134
+ const source = record$9(manifest.source);
2135
2135
  if (source?.plugin !== "dsh-mnemon" || typeof source.pluginVersion !== "string") throw new Error("Mnemon Pack source is invalid");
2136
2136
  if (!Array.isArray(manifest.summary)) throw new Error("Mnemon Pack summary is invalid");
2137
2137
  const summary = manifest.summary.map((entry) => {
2138
- const item = record$8(entry);
2138
+ const item = record$9(entry);
2139
2139
  const component = item?.component;
2140
2140
  if (!COMPONENT_ORDER.includes(component) || !Number.isSafeInteger(item?.files) || !Number.isSafeInteger(item?.bytes) || !Number.isSafeInteger(item?.items) || Number(item?.files) < 0 || Number(item?.bytes) < 0 || Number(item?.items) < 0) throw new Error("Mnemon Pack summary entry is invalid");
2141
2141
  return {
@@ -2161,7 +2161,7 @@ function parseManifest(value) {
2161
2161
  /** The sync channel reads its machine identity with this parser; no Pack carries one. */
2162
2162
  function parseMachineIdentity(value) {
2163
2163
  if (value === void 0 || value === null) return void 0;
2164
- const machine = record$8(value);
2164
+ const machine = record$9(value);
2165
2165
  if (typeof machine?.id !== "string" || machine.id.trim() === "" || typeof machine.label !== "string" || typeof machine.createdAt !== "string") throw new Error("Mnemon Pack machine identity is invalid");
2166
2166
  return {
2167
2167
  id: machine.id,
@@ -2171,7 +2171,7 @@ function parseMachineIdentity(value) {
2171
2171
  }
2172
2172
  function parseEntryOrigin(value) {
2173
2173
  if (value === void 0 || value === null) return void 0;
2174
- const origin = record$8(value);
2174
+ const origin = record$9(value);
2175
2175
  if (typeof origin?.machine !== "string" || typeof origin.label !== "string" || typeof origin.at !== "string") return void 0;
2176
2176
  return {
2177
2177
  machine: origin.machine,
@@ -2216,8 +2216,8 @@ function parseArchive(base64, runtimeLimits = RUNTIME_MEMORY_LIMITS) {
2216
2216
  if (path !== "manifest.json" && path !== "checksums.json" && !allowedPayloadPath(path)) throw new Error(`unsupported Mnemon Pack entry: ${path}`);
2217
2217
  }
2218
2218
  const manifest = parseManifest(json$1(files["manifest.json"], "manifest.json"));
2219
- const checksumValue = record$8(json$1(files["checksums.json"], "checksums.json"));
2220
- const checksumFiles = record$8(checksumValue?.files);
2219
+ const checksumValue = record$9(json$1(files["checksums.json"], "checksums.json"));
2220
+ const checksumFiles = record$9(checksumValue?.files);
2221
2221
  if (checksumValue?.algorithm !== "sha256" || checksumFiles === void 0) throw new Error("Mnemon Pack checksums are invalid");
2222
2222
  const payloadNames = names.filter((path) => path.startsWith("payload/")).sort();
2223
2223
  if (Object.keys(checksumFiles).length !== payloadNames.length) throw new Error("Mnemon Pack checksum inventory does not match the payload");
@@ -2240,10 +2240,10 @@ function parseArchive(base64, runtimeLimits = RUNTIME_MEMORY_LIMITS) {
2240
2240
  };
2241
2241
  }
2242
2242
  function parseRuntime(value, limits = RUNTIME_MEMORY_LIMITS) {
2243
- const source = record$8(value);
2243
+ const source = record$9(value);
2244
2244
  if (source?.version !== RUNTIME_MEMORY_VERSION || !Array.isArray(source.entries)) throw new Error("runtime memories.json is invalid");
2245
2245
  const entries = source.entries.map((raw) => {
2246
- const entry = record$8(raw);
2246
+ const entry = record$9(raw);
2247
2247
  if (typeof entry?.content !== "string" || entry.target !== "memory" && entry.target !== "user" || ![
2248
2248
  "critical",
2249
2249
  "normal",
@@ -2280,12 +2280,12 @@ function emptyTombstones() {
2280
2280
  };
2281
2281
  }
2282
2282
  function parseTombstones(value) {
2283
- const source = record$8(value);
2283
+ const source = record$9(value);
2284
2284
  if (source?.version !== 1 || !Array.isArray(source.tombstones)) throw new Error("runtime tombstones.json is invalid");
2285
2285
  return {
2286
2286
  version: 1,
2287
2287
  tombstones: source.tombstones.map((raw) => {
2288
- const tombstone = record$8(raw);
2288
+ const tombstone = record$9(raw);
2289
2289
  if (tombstone?.target !== "memory" && tombstone?.target !== "user") throw new Error("runtime tombstones.json contains an invalid entry");
2290
2290
  if (typeof tombstone.contentHash !== "string" || !CONTENT_HASH.test(tombstone.contentHash) || typeof tombstone.deletedAt !== "string") throw new Error("runtime tombstones.json contains an invalid entry");
2291
2291
  return {
@@ -2700,11 +2700,11 @@ function emptyRuntimeIndex() {
2700
2700
  }
2701
2701
  /** A damaged index only costs forgotten deletions, so it degrades instead of failing an export. */
2702
2702
  function parseRuntimeIndex(value) {
2703
- const source = record$8(value);
2703
+ const source = record$9(value);
2704
2704
  if (source?.version !== 1 || !Array.isArray(source.entries)) return emptyRuntimeIndex();
2705
2705
  const entries = [];
2706
2706
  for (const raw of source.entries) {
2707
- const entry = record$8(raw);
2707
+ const entry = record$9(raw);
2708
2708
  if (entry?.target !== "memory" && entry?.target !== "user") continue;
2709
2709
  if (typeof entry.contentHash !== "string" || !/^[a-f0-9]{64}$/u.test(entry.contentHash)) continue;
2710
2710
  entries.push({
@@ -3356,7 +3356,7 @@ const STATUSES = [
3356
3356
  "accepted",
3357
3357
  "rejected"
3358
3358
  ];
3359
- function record$7(value) {
3359
+ function record$8(value) {
3360
3360
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
3361
3361
  }
3362
3362
  function text$2(value, limit = MAX_REVIEW_TEXT) {
@@ -3368,7 +3368,7 @@ function strings$1(value, limit = 64) {
3368
3368
  function parseOpinions(value) {
3369
3369
  if (!Array.isArray(value)) return [];
3370
3370
  return value.flatMap((raw) => {
3371
- const opinion = record$7(raw);
3371
+ const opinion = record$8(raw);
3372
3372
  if (opinion === void 0 || typeof opinion.id !== "string" || typeof opinion.text !== "string") return [];
3373
3373
  return [{
3374
3374
  id: opinion.id,
@@ -3380,11 +3380,11 @@ function parseOpinions(value) {
3380
3380
  }
3381
3381
  /** A proposal that no longer parses is dropped rather than failing the whole ledger. */
3382
3382
  function parseEntry(value) {
3383
- const entry = record$7(value);
3383
+ const entry = record$8(value);
3384
3384
  if (entry === void 0 || typeof entry.id !== "string" || entry.id.trim() === "") return void 0;
3385
3385
  if (typeof entry.status !== "string" || !STATUSES.includes(entry.status)) return void 0;
3386
3386
  if (!Array.isArray(entry.operations)) return void 0;
3387
- const machine = record$7(entry.machine) ?? {};
3387
+ const machine = record$8(entry.machine) ?? {};
3388
3388
  const createdAt = typeof entry.createdAt === "string" ? entry.createdAt : (/* @__PURE__ */ new Date()).toISOString();
3389
3389
  return {
3390
3390
  id: entry.id,
@@ -3534,7 +3534,7 @@ var MnemonReviewLedger = class {
3534
3534
  version: 1,
3535
3535
  entries: []
3536
3536
  };
3537
- const file = record$7(JSON.parse(readFileSync(this.path(), "utf8")));
3537
+ const file = record$8(JSON.parse(readFileSync(this.path(), "utf8")));
3538
3538
  if (file?.version !== 1 || !Array.isArray(file.entries)) throw new Error("review ledger is invalid: " + this.path());
3539
3539
  return {
3540
3540
  version: 1,
@@ -3985,7 +3985,7 @@ const MNEMON_GITHUB_MAX_INTERVAL_MS = 6e4;
3985
3985
  const MNEMON_GITHUB_FLOW_LIMIT_MS = 36e5;
3986
3986
  const MNEMON_GITHUB_USER_AGENT = "dsh-mnemon-sync";
3987
3987
  const DEVICE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
3988
- function record$6(value) {
3988
+ function record$7(value) {
3989
3989
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
3990
3990
  }
3991
3991
  function text$1(value) {
@@ -3993,7 +3993,7 @@ function text$1(value) {
3993
3993
  }
3994
3994
  /** GitHub answers a refused request with a `error` code or an API `message`. */
3995
3995
  function codeOf(body) {
3996
- const fields = record$6(body);
3996
+ const fields = record$7(body);
3997
3997
  return text$1(fields?.error) ?? text$1(fields?.message);
3998
3998
  }
3999
3999
  /** A positive count GitHub sends as a JSON number, or as a string in a form-encoded answer. */
@@ -4008,7 +4008,7 @@ const FIELD_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/u;
4008
4008
  * device code or a token. Enough to tell a proxy's HTML page from a reply that lost a field.
4009
4009
  */
4010
4010
  function shapeOf(answer) {
4011
- const keys = Object.keys(record$6(answer.body) ?? {});
4011
+ const keys = Object.keys(record$7(answer.body) ?? {});
4012
4012
  const names = keys.filter((key) => FIELD_NAME.test(key)).slice(0, 8);
4013
4013
  const listed = keys.length > names.length ? [...names, String(keys.length - names.length) + " other"] : names;
4014
4014
  return "HTTP " + String(answer.status) + ", content-type " + (answer.type ?? "none") + ", fields: " + (listed.length === 0 ? "none" : listed.join(", "));
@@ -4020,9 +4020,9 @@ function failure$3(action, status, body) {
4020
4020
  }
4021
4021
  /** Read one grant out of a stored record, refusing anything else. */
4022
4022
  function githubGrantFromRecord(record_) {
4023
- const fields = record$6(record_);
4023
+ const fields = record$7(record_);
4024
4024
  if (fields?.kind !== "grant") return void 0;
4025
- const payload = record$6(fields.payload);
4025
+ const payload = record$7(fields.payload);
4026
4026
  if (payload?.version !== 1) return void 0;
4027
4027
  const accessToken = text$1(payload.accessToken);
4028
4028
  if (accessToken === void 0) return void 0;
@@ -4036,13 +4036,13 @@ function githubGrantFromRecord(record_) {
4036
4036
  };
4037
4037
  }
4038
4038
  function repositoryOf(value) {
4039
- const fields = record$6(value);
4039
+ const fields = record$7(value);
4040
4040
  const fullName = text$1(fields?.full_name);
4041
4041
  const url = text$1(fields?.clone_url);
4042
4042
  const name = text$1(fields?.name);
4043
4043
  if (fullName === void 0 || url === void 0 || name === void 0) return void 0;
4044
- const owner = record$6(fields?.owner);
4045
- const permissions = record$6(fields?.permissions);
4044
+ const owner = record$7(fields?.owner);
4045
+ const permissions = record$7(fields?.permissions);
4046
4046
  return {
4047
4047
  name,
4048
4048
  fullName,
@@ -4155,7 +4155,7 @@ var MnemonGitHubAuth = class {
4155
4155
  throw new Error("the GitHub device code request could not reach GitHub: " + describeTransportError(error));
4156
4156
  }
4157
4157
  if (answer.status !== 200) throw failure$3("the GitHub device code request", answer.status, answer.body);
4158
- const fields = record$6(answer.body);
4158
+ const fields = record$7(answer.body);
4159
4159
  const deviceCode = text$1(fields?.device_code);
4160
4160
  const userCode = text$1(fields?.user_code);
4161
4161
  const verificationUri = text$1(fields?.verification_uri);
@@ -4204,7 +4204,7 @@ var MnemonGitHubAuth = class {
4204
4204
  message: describeTransportError(error)
4205
4205
  };
4206
4206
  }
4207
- const fields = record$6(answer.body);
4207
+ const fields = record$7(answer.body);
4208
4208
  const code = text$1(fields?.error);
4209
4209
  if (code === void 0) {
4210
4210
  const accessToken = text$1(fields?.access_token);
@@ -4275,7 +4275,7 @@ var MnemonGitHubAuth = class {
4275
4275
  ...signal === void 0 ? {} : { signal }
4276
4276
  });
4277
4277
  if (status !== 200) return void 0;
4278
- return text$1(record$6(body)?.login);
4278
+ return text$1(record$7(body)?.login);
4279
4279
  } catch {
4280
4280
  return;
4281
4281
  }
@@ -4401,7 +4401,7 @@ const SETTING_KEYS = [
4401
4401
  "autoBackupMinutes"
4402
4402
  ];
4403
4403
  const REPOSITORY_HINT = "sync repository must be an https:// or ssh:// URL, a git@host:path address, or an absolute local path";
4404
- function record$5(value) {
4404
+ function record$6(value) {
4405
4405
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
4406
4406
  }
4407
4407
  function known(key) {
@@ -4505,7 +4505,7 @@ var MnemonSyncSettingsStore = class {
4505
4505
  } catch {
4506
4506
  throw new Error("sync configuration is not valid JSON");
4507
4507
  }
4508
- const stored = record$5(parsed);
4508
+ const stored = record$6(parsed);
4509
4509
  if (stored === void 0) throw new Error("sync configuration is not a JSON object");
4510
4510
  for (const key of Object.keys(stored)) if (!known(key)) throw new Error("sync configuration has an unknown field: " + key);
4511
4511
  const settings = this.defaults();
@@ -4552,7 +4552,7 @@ var MnemonSyncSettingsStore = class {
4552
4552
  * turns the automatic backup off.
4553
4553
  */
4554
4554
  patch(patch) {
4555
- const fields = record$5(patch);
4555
+ const fields = record$6(patch);
4556
4556
  if (fields === void 0) throw new Error("sync configuration must be an object");
4557
4557
  for (const key of Object.keys(fields)) if (!known(key)) throw new Error("unknown sync setting: " + key);
4558
4558
  const next = { ...this.read() };
@@ -4788,7 +4788,7 @@ function remoteFailure(message) {
4788
4788
  function rejectedPush(output) {
4789
4789
  return /\[rejected\]|fetch first|non-fast-forward/iu.test(output);
4790
4790
  }
4791
- function record$4(value) {
4791
+ function record$5(value) {
4792
4792
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
4793
4793
  }
4794
4794
  function tail(output) {
@@ -4853,7 +4853,7 @@ const TIMESTAMP_FIELDS = /* @__PURE__ */ new Set(["exportedAt", "pushedAt"]);
4853
4853
  /** The same manifest without its timestamps describes the same payload. */
4854
4854
  function withoutTimestamps(value) {
4855
4855
  if (Array.isArray(value)) return value.map(withoutTimestamps);
4856
- const parsed = record$4(value);
4856
+ const parsed = record$5(value);
4857
4857
  if (parsed === void 0) return value;
4858
4858
  return Object.fromEntries(Object.entries(parsed).filter(([key]) => !TIMESTAMP_FIELDS.has(key)).map(([key, item]) => [key, withoutTimestamps(item)]));
4859
4859
  }
@@ -4866,7 +4866,7 @@ function manifestIdentity(bytes) {
4866
4866
  } catch {
4867
4867
  return;
4868
4868
  }
4869
- return record$4(value) === void 0 ? void 0 : JSON.stringify(withoutTimestamps(value));
4869
+ return record$5(value) === void 0 ? void 0 : JSON.stringify(withoutTimestamps(value));
4870
4870
  }
4871
4871
  /**
4872
4872
  * Whether the mirror already holds exactly this payload. Every push re-exports
@@ -5071,7 +5071,20 @@ function readFiles(root, limit = MAX_PAYLOAD_BYTES) {
5071
5071
  function unpack(archive) {
5072
5072
  let entries;
5073
5073
  try {
5074
- entries = unzipSync(archive);
5074
+ if (archive.byteLength > 268435456) throw new Error("compressed archive exceeds safety limit");
5075
+ let expandedBytes = 0;
5076
+ let fileCount = 0;
5077
+ entries = unzipSync(archive, { filter(info) {
5078
+ const path = info.name;
5079
+ const normalized = path.endsWith("/") ? path.slice(0, -1) : path;
5080
+ if (path.includes("\\") || path.startsWith("/") || /^[a-z]:/i.test(path) || path.includes("\0") || normalized.split("/").some((part) => !part || part === "." || part === "..")) throw new Error("unsafe archive path");
5081
+ if (path.endsWith("/")) return false;
5082
+ if (info.compression === 0 && info.size !== info.originalSize) throw new Error("invalid stored archive entry size");
5083
+ expandedBytes += info.originalSize;
5084
+ fileCount += 1;
5085
+ if (!Number.isSafeInteger(info.originalSize) || info.originalSize < 0 || info.originalSize > 134217728 || expandedBytes > 268435456 || fileCount > 4096) throw new Error("expanded archive exceeds safety limit");
5086
+ return true;
5087
+ } });
5075
5088
  } catch {
5076
5089
  throw new Error("the Mnemon payload is not a readable archive");
5077
5090
  }
@@ -5229,7 +5242,7 @@ var MnemonGitSync = class {
5229
5242
  }
5230
5243
  async configure(patch) {
5231
5244
  const previous = this.store.read();
5232
- const fields = record$4(patch);
5245
+ const fields = record$5(patch);
5233
5246
  const { machineLabel: name, ...settings } = fields ?? {};
5234
5247
  const naming = fields !== void 0 && "machineLabel" in fields;
5235
5248
  if (naming && name !== null && name !== "") machineLabel(name);
@@ -5437,7 +5450,7 @@ var MnemonGitSync = class {
5437
5450
  /** When memory last travelled through this channel, or nothing when it never did. */
5438
5451
  lastRun() {
5439
5452
  try {
5440
- const value = record$4(JSON.parse(readFileSync(this.lastRunPath(), "utf8")));
5453
+ const value = record$5(JSON.parse(readFileSync(this.lastRunPath(), "utf8")));
5441
5454
  if (value === void 0 || typeof value.at !== "string" || typeof value.commit !== "string") return void 0;
5442
5455
  if (value.kind !== "sync" && value.kind !== "merge") return void 0;
5443
5456
  return {
@@ -5475,13 +5488,13 @@ var MnemonGitSync = class {
5475
5488
  async agreedDocuments(settings, tip, signal) {
5476
5489
  let value;
5477
5490
  try {
5478
- value = record$4(JSON.parse(readFileSync(this.basePath(), "utf8")));
5491
+ value = record$5(JSON.parse(readFileSync(this.basePath(), "utf8")));
5479
5492
  } catch {
5480
5493
  value = void 0;
5481
5494
  }
5482
5495
  if (value === void 0) return this.lastRunDocuments(settings, tip, signal);
5483
5496
  if (value.version !== 1 || value.scope !== this.agreementScope(settings)) return void 0;
5484
- const documents = record$4(value.documents);
5497
+ const documents = record$5(value.documents);
5485
5498
  if (typeof value.commit !== "string" || !AGREED_COMMIT.test(value.commit) || documents === void 0) return void 0;
5486
5499
  if ((await this.git([
5487
5500
  "merge-base",
@@ -5928,9 +5941,9 @@ var MnemonGitSync = class {
5928
5941
  let machine;
5929
5942
  let pushedAt;
5930
5943
  try {
5931
- const raw = record$4(parseJson(bytes, "the backup manifest"));
5944
+ const raw = record$5(parseJson(bytes, "the backup manifest"));
5932
5945
  if (raw === void 0) return void 0;
5933
- const extension = record$4(raw[SYNC_EXTENSION]);
5946
+ const extension = record$5(raw[SYNC_EXTENSION]);
5934
5947
  pushedAt = typeof extension?.pushedAt === "string" ? extension.pushedAt : void 0;
5935
5948
  machine = extensionMachine(extension);
5936
5949
  manifest = parseManifest(raw);
@@ -6237,11 +6250,11 @@ var MnemonGitSync = class {
6237
6250
  if (manifestBytes === void 0 || checksumBytes === void 0) return void 0;
6238
6251
  if (manifestBytes.byteLength > MAX_MANIFEST_BYTES) throw new Error("the remote Mnemon manifest exceeds the safety limit");
6239
6252
  for (const path of Object.keys(files)) if (path !== MANIFEST && path !== CHECKSUMS && !path.startsWith("payload/")) throw new Error("the remote Mnemon payload holds an unexpected file: " + path);
6240
- const parsed = record$4(parseJson(manifestBytes, "the remote Mnemon manifest"));
6253
+ const parsed = record$5(parseJson(manifestBytes, "the remote Mnemon manifest"));
6241
6254
  if (parsed === void 0) throw new Error("the remote Mnemon manifest is not a JSON object");
6242
6255
  if (parsed.format !== "mnemonpack" || parsed.version !== 1) throw new Error("the remote Mnemon manifest is not a supported Mnemon Pack");
6243
- const checksums = record$4(parseJson(checksumBytes, "the remote Mnemon checksum inventory"));
6244
- const inventory = record$4(checksums?.files);
6256
+ const checksums = record$5(parseJson(checksumBytes, "the remote Mnemon checksum inventory"));
6257
+ const inventory = record$5(checksums?.files);
6245
6258
  if (checksums?.algorithm !== "sha256" || inventory === void 0) throw new Error("the remote Mnemon checksum inventory is invalid");
6246
6259
  for (const [path, bytes] of Object.entries(files)) {
6247
6260
  if (path === MANIFEST || path === CHECKSUMS) continue;
@@ -6250,7 +6263,7 @@ var MnemonGitSync = class {
6250
6263
  if (expected !== sha256Hex(bytes)) throw new Error("the remote Mnemon payload failed its checksum: " + path);
6251
6264
  }
6252
6265
  for (const path of Object.keys(inventory)) if (files[path] === void 0) throw new Error("the remote Mnemon payload is missing a checksummed file: " + path);
6253
- const extension = record$4(parsed[SYNC_EXTENSION]);
6266
+ const extension = record$5(parsed[SYNC_EXTENSION]);
6254
6267
  const pushedAt = typeof extension?.pushedAt === "string" ? extension.pushedAt : void 0;
6255
6268
  const machine = extensionMachine(extension);
6256
6269
  const archive = zipSync(files, {
@@ -6471,7 +6484,7 @@ function abandoned(path, now) {
6471
6484
  }
6472
6485
  if (age > STALE_LOCK_MS) return true;
6473
6486
  try {
6474
- const pid = record$4(JSON.parse(readFileSync(join(path, LOCK_OWNER), "utf8")))?.pid;
6487
+ const pid = record$5(JSON.parse(readFileSync(join(path, LOCK_OWNER), "utf8")))?.pid;
6475
6488
  return typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid !== process.pid && !processAlive(pid);
6476
6489
  } catch {
6477
6490
  return age > OWNERLESS_LOCK_MS;
@@ -7992,6 +8005,7 @@ function registerCommands(commands, service, coordinator) {
7992
8005
  const GUIDANCE_SECTION_NAME = "mnemon:routing";
7993
8006
  const RUNTIME_MEMORY_CONTEXT_NAME = "mnemon:runtime-memory";
7994
8007
  const STRATEGY_SECTION_NAME = "mnemon:strategy";
8008
+ const SNAPSHOT_GUIDANCE = "Mnemon memory snapshots are complete projections in chronological order. The latest snapshot supersedes earlier snapshots as the current projected state; do not treat older versions as additional current facts or authority. Absence may reflect filtering or projection budgets and does not imply deletion from storage.";
7995
8009
  const ROUTING_GUIDANCE = "Use memory only when needed. Follow the current Mnemon View: use mnemon_view_route or mnemon_view_action only for offered ids. Installed tools do not imply an available Source. Never infer missing historical facts. An action offer is not authorization; a write exists only after its receipt.";
7996
8010
  /** A View is an own-plugin message, never part of the shared context snapshot. */
7997
8011
  function withoutMemoryViewContext(assembly) {
@@ -8002,12 +8016,20 @@ function withoutMemoryViewContext(assembly) {
8002
8016
  }
8003
8017
  /** Inject trusted Strategy instructions after interpolation; Source text stays quoted in the Wake. */
8004
8018
  function applyMemoryViewGuidance(assembly, view, routingEnabled = true) {
8005
- if (view === void 0) return withoutMemoryViewContext(assembly);
8019
+ if (view === void 0) return withoutMemoryViewContext({
8020
+ ...assembly,
8021
+ sections: assembly.sections.filter((section) => section.name !== "mnemon:snapshot-history")
8022
+ });
8006
8023
  const sections = assembly.sections.filter((section) => ![
8007
8024
  GUIDANCE_SECTION_NAME,
8008
8025
  STRATEGY_SECTION_NAME,
8009
- "mnemon:runtime-memory-protocol"
8026
+ "mnemon:runtime-memory-protocol",
8027
+ "mnemon:snapshot-history"
8010
8028
  ].includes(section.name));
8029
+ sections.push({
8030
+ name: "mnemon:snapshot-history",
8031
+ text: SNAPSHOT_GUIDANCE
8032
+ });
8011
8033
  if (view.guidance?.system) sections.push({
8012
8034
  name: STRATEGY_SECTION_NAME,
8013
8035
  text: view.guidance.system
@@ -8143,7 +8165,7 @@ function pendingOpinions(entries) {
8143
8165
  createdAt: opinion.createdAt
8144
8166
  }))).sort((left, right) => left.createdAt.localeCompare(right.createdAt));
8145
8167
  }
8146
- function record$3(value) {
8168
+ function record$4(value) {
8147
8169
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
8148
8170
  }
8149
8171
  function stringField(value) {
@@ -8292,7 +8314,7 @@ function body(value, index, field) {
8292
8314
  return text.slice(0, MAX_FIELD);
8293
8315
  }
8294
8316
  function parseOperation(value, index, evidence) {
8295
- const operation = record$3(value);
8317
+ const operation = record$4(value);
8296
8318
  if (operation === void 0) throw new Error(`reconcile operation ${index} must be an object`);
8297
8319
  const kind = stringField(operation.kind);
8298
8320
  if (kind === void 0 || !KINDS.includes(kind)) throw new Error(`reconcile operation ${index} has an unsupported kind: ${JSON.stringify(operation.kind)}`);
@@ -8365,7 +8387,7 @@ function emptyDocumentSnapshot(directory, at) {
8365
8387
  }
8366
8388
  /** The host, not the model, decides what a proposal may contain. */
8367
8389
  function parseReconcileResult(value, evidence) {
8368
- const result = record$3(value);
8390
+ const result = record$4(value);
8369
8391
  if (result === void 0) throw new Error("memory reconciliation returned an invalid structured result");
8370
8392
  const action = stringField(result.action);
8371
8393
  if (action === void 0 || ![
@@ -8694,13 +8716,13 @@ async function startGuardedChild(host, parent, start, guard, options) {
8694
8716
  }
8695
8717
  //#endregion
8696
8718
  //#region src/host/review-checkpoint.ts
8697
- function record$2(value) {
8719
+ function record$3(value) {
8698
8720
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
8699
8721
  }
8700
8722
  function textContent(content, toolResult = false) {
8701
8723
  if (!Array.isArray(content)) return "";
8702
8724
  return content.map((block) => {
8703
- const value = record$2(block);
8725
+ const value = record$3(block);
8704
8726
  if (value.type === "text" && typeof value.text === "string") return value.text;
8705
8727
  if (toolResult && value.type === "tool-result" && value.isError !== true) return textContent(value.content);
8706
8728
  return "";
@@ -8724,8 +8746,8 @@ function reviewCheckpoint(session, maxChars) {
8724
8746
  "assistant/message",
8725
8747
  "tool/result"
8726
8748
  ].includes(event.type)) continue;
8727
- const message = record$2(event.type === "user/message" ? event.data : event.data.message);
8728
- const source = record$2(message.source);
8749
+ const message = record$3(event.type === "user/message" ? event.data : event.data.message);
8750
+ const source = record$3(message.source);
8729
8751
  if (event.type === "user/message" && source.kind !== "user") continue;
8730
8752
  const text = textContent(message.content, event.type === "tool/result");
8731
8753
  if (!text) continue;
@@ -8739,8 +8761,14 @@ function reviewCheckpoint(session, maxChars) {
8739
8761
  //#endregion
8740
8762
  //#region src/host/plugin-message.ts
8741
8763
  const MNEMON_PLUGIN_SOURCE = "dsh-mnemon";
8764
+ /** Includes the published V3 wrapper and its official V4 migration. */
8765
+ function isMnemonMessageSource(source) {
8766
+ if (typeof source !== "object" || source === null) return false;
8767
+ const { kind, plugin } = source;
8768
+ return kind === "dsh-mnemon" || kind === `plugin:dsh-mnemon` || kind === "plugin" && plugin === "dsh-mnemon";
8769
+ }
8742
8770
  /** A user-role message this plugin adds to a step, marked with its own source. */
8743
- function createPluginMessage(text, form) {
8771
+ function createPluginMessage(text, form, snapshot) {
8744
8772
  return structuredClone({
8745
8773
  id: randomUUID(),
8746
8774
  role: "user",
@@ -8750,7 +8778,8 @@ function createPluginMessage(text, form) {
8750
8778
  }],
8751
8779
  source: {
8752
8780
  kind: MNEMON_PLUGIN_SOURCE,
8753
- form
8781
+ form,
8782
+ ...snapshot === void 0 ? {} : { snapshot }
8754
8783
  }
8755
8784
  });
8756
8785
  }
@@ -12313,6 +12342,192 @@ var TurnActivityProjection = class {
12313
12342
  }
12314
12343
  };
12315
12344
  //#endregion
12345
+ //#region src/host/memory-snapshot-state.ts
12346
+ const digest = (value) => createHash("sha256").update(canonicalMemoryJson(value)).digest("hex");
12347
+ const hash$1 = (value) => typeof value === "string" && /^[a-f0-9]{64}$/u.test(value);
12348
+ const record$2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
12349
+ function readMemorySnapshotState(value) {
12350
+ if (!record$2(value) || value.version !== 1 || !hash$1(value.boundary) || !Array.isArray(value.entries) || !value.entries.every(hash$1)) return void 0;
12351
+ return {
12352
+ version: 1,
12353
+ boundary: value.boundary,
12354
+ entries: [...value.entries]
12355
+ };
12356
+ }
12357
+ /**
12358
+ * Only Runtime's Source-owned, complete-projection provenance permits additive
12359
+ * history. Unknown Sources and opaque grants are compared in full. Do not use
12360
+ * View ids or source revisions here: ordinary Runtime writes change both.
12361
+ */
12362
+ function memorySnapshotState(view) {
12363
+ if (view === void 0) return void 0;
12364
+ const entries = [];
12365
+ const projection = view.projection.map((fragment) => {
12366
+ const provenance = fragment.provenance;
12367
+ const snapshot = record$2(provenance) ? provenance.snapshot : void 0;
12368
+ if (!record$2(provenance) || provenance.sourceTypeId !== "runtime" || !record$2(snapshot) || snapshot.version !== 1 || !hash$1(snapshot.scope) || !Array.isArray(snapshot.entries) || !snapshot.entries.every(hash$1)) return fragment;
12369
+ entries.push(...snapshot.entries.map((entry) => digest([
12370
+ fragment.sourceInstanceKey,
12371
+ fragment.id,
12372
+ entry
12373
+ ])));
12374
+ const { text: _text, revision: _revision, ...identity } = fragment;
12375
+ return {
12376
+ ...identity,
12377
+ provenance: {
12378
+ ...provenance,
12379
+ snapshot: {
12380
+ version: 1,
12381
+ scope: snapshot.scope
12382
+ }
12383
+ }
12384
+ };
12385
+ });
12386
+ return {
12387
+ version: 1,
12388
+ boundary: digest({
12389
+ generation: view.runtimeGeneration,
12390
+ scope: view.scope,
12391
+ strategy: [
12392
+ view.strategyInstanceKey,
12393
+ view.strategyTypeId,
12394
+ view.strategyExtensions ?? []
12395
+ ],
12396
+ projection,
12397
+ routes: view.routes,
12398
+ actions: view.actionOffers,
12399
+ grants: view.readGrants,
12400
+ guidance: view.guidance ?? null,
12401
+ diagnostics: view.diagnostics ?? []
12402
+ }),
12403
+ entries: entries.sort()
12404
+ };
12405
+ }
12406
+ /** A missing old occurrence is a deletion/correction, even with duplicate facts. */
12407
+ function retainsSnapshotEntries(previous, current) {
12408
+ const counts = /* @__PURE__ */ new Map();
12409
+ for (const entry of current) counts.set(entry, (counts.get(entry) ?? 0) + 1);
12410
+ for (const entry of previous) {
12411
+ const count = counts.get(entry) ?? 0;
12412
+ if (count === 0) return false;
12413
+ counts.set(entry, count - 1);
12414
+ }
12415
+ return true;
12416
+ }
12417
+ //#endregion
12418
+ //#region src/host/memory-snapshot.ts
12419
+ const MAX_SNAPSHOTS = 4;
12420
+ const MAX_SNAPSHOT_BYTES = 65536;
12421
+ const LEGACY_RUNTIME_SNAPSHOT = /^MNEMON RUNTIME MEMORY SNAPSHOT\n[^\n]+(?:\n[^\n]+)*\n\n(?:USER\.md \(user profile\)|Contents of USER\.md \(user profile; entries: \d+; UTF-8 bytes: \d+\/\d+\))\n<runtime-memory-file name="USER.md">\n(?:(?!\n\nMNEMON (?:RUNTIME MEMORY SNAPSHOT|VIEW ))[\s\S])*?\n<\/runtime-memory-file>\n\n(?:MEMORY\.md \(working reference\)|Contents of MEMORY\.md \(working reference; entries: \d+; UTF-8 bytes: \d+\/\d+\))\n<runtime-memory-file name="MEMORY.md">\n(?:(?!\n\nMNEMON (?:RUNTIME MEMORY SNAPSHOT|VIEW ))[\s\S])*?\n<\/runtime-memory-file>(?:$|\n\n)/u;
12422
+ const TRUNCATED_RUNTIME_START = /^MNEMON RUNTIME MEMORY SNAPSHOT\n(?:Revision: [a-f0-9]{64}(?:\nGit branch: [^\r\n]+)?(?:\nMetadata lines are annotations; created\/updated are ages at projection in whole days \(future\/unknown for future\/invalid timestamps\)\. Current instructions win\. For old_text\/oldText, use entry content only\.)?\n\nContents of USER\.md \(user profile; entries: \d+; UTF-8 bytes: \d+\/\d+\)|Entry annotations default to importance=normal and ages=0d \(whole days at projection; future\/unknown for future\/invalid timestamps\)\. Current instructions win\. For old_text\/oldText, use entry content only\.(?:\nGit branch: [^\r\n]+)?\n\nUSER\.md \(user profile\))\n<runtime-memory-file name="USER.md">\n/u;
12423
+ const RUNTIME_WAKE_SEPARATOR = /\n\n(?:MNEMON RUNTIME MEMORY SNAPSHOT\n|MNEMON VIEW TOOLS \(available in this View\): |MNEMON VIEW ROUTES \(quoted routing data; use mnemon_view_route or mnemon_view_action by exact id\): |MNEMON VIEW AVAILABILITY \(quoted diagnostics; unavailable Sources are not evidence\): )/u;
12424
+ function isTruncatedRuntimeSnapshot(text) {
12425
+ const start = TRUNCATED_RUNTIME_START.exec(text);
12426
+ if (start === null) return false;
12427
+ const body = text.slice(start[0].length);
12428
+ const end = body.search(RUNTIME_WAKE_SEPARATOR);
12429
+ const first = end < 0 ? body : body.slice(0, end);
12430
+ if (!first.endsWith("…")) return false;
12431
+ const prefix = first.slice(0, -1);
12432
+ const userEnd = prefix.indexOf("\n</runtime-memory-file>");
12433
+ if (userEnd < 0) return true;
12434
+ const heading = start[0].includes("\nContents of USER.md ") ? [
12435
+ "\n\nContents of MEMORY.md (working reference; entries: ",
12436
+ /^\d+/u,
12437
+ "; UTF-8 bytes: ",
12438
+ /^\d+/u,
12439
+ "/",
12440
+ /^\d+/u,
12441
+ ")"
12442
+ ] : ["\n\nMEMORY.md (working reference)"];
12443
+ heading.push("\n<runtime-memory-file name=\"MEMORY.md\">\n");
12444
+ let rest = prefix.slice(userEnd + 23);
12445
+ for (const part of heading) {
12446
+ if (rest === "") return true;
12447
+ if (typeof part === "string") {
12448
+ if (part.startsWith(rest)) return true;
12449
+ if (!rest.startsWith(part)) return false;
12450
+ rest = rest.slice(part.length);
12451
+ } else {
12452
+ const match = part.exec(rest);
12453
+ if (match === null) return false;
12454
+ rest = rest.slice(match[0].length);
12455
+ }
12456
+ }
12457
+ return true;
12458
+ }
12459
+ /** Read only this producer's snapshot formats; ordinary recalls retain history. */
12460
+ function snapshotText(event) {
12461
+ if (event?.type !== "user/message" || event.data.role !== "user") return void 0;
12462
+ const source = event.data.source;
12463
+ if (!isMnemonMessageSource(source)) return void 0;
12464
+ const content = event.data.content;
12465
+ if (!Array.isArray(content) || content.length !== 1) return void 0;
12466
+ const block = content[0];
12467
+ if (block?.type !== "text" || typeof block.text !== "string") return void 0;
12468
+ if (source?.form === "memory-snapshot") return block.text;
12469
+ if (source?.form !== "recall" || !(LEGACY_RUNTIME_SNAPSHOT.test(block.text) || isTruncatedRuntimeSnapshot(block.text))) return void 0;
12470
+ return block.text;
12471
+ }
12472
+ /**
12473
+ * Prepare a snapshot and its retirements without writing before step/start.
12474
+ * Commit after step/start publication, before the Host builds its request.
12475
+ * Empty developer nodes are a public Session representation that derives no model
12476
+ * message. They contain no instructions, Source text, or tool changes. Each
12477
+ * replacement shadows one owned node and cites it; the append-only audit keeps
12478
+ * the original full message, without touching interleaved conversation.
12479
+ */
12480
+ function prepareMemorySnapshot(session, text, state) {
12481
+ const current = text?.trim() === "" ? void 0 : text;
12482
+ const snapshots = session.surface.nodes.flatMap((seq) => {
12483
+ const event = session.eventAt(seq);
12484
+ const text = snapshotText(event);
12485
+ const source = event?.data.source;
12486
+ return text === void 0 ? [] : [{
12487
+ seq,
12488
+ text,
12489
+ state: source?.form === "memory-snapshot" ? readMemorySnapshotState(source.snapshot) : void 0
12490
+ }];
12491
+ });
12492
+ const latest = snapshots.at(-1);
12493
+ const compatible = state !== void 0 && snapshots.every((snapshot) => snapshot.state?.boundary === state.boundary && retainsSnapshotEntries(snapshot.state.entries, state.entries));
12494
+ const unchanged = current !== void 0 && latest?.text === current;
12495
+ const count = snapshots.length + (unchanged ? 0 : 1);
12496
+ const bytes = snapshots.reduce((total, snapshot) => total + Buffer.byteLength(snapshot.text, "utf8"), 0) + (unchanged || current === void 0 ? 0 : Buffer.byteLength(current, "utf8"));
12497
+ const retained = current === void 0 ? [] : compatible && count <= MAX_SNAPSHOTS && (count <= 1 || bytes <= MAX_SNAPSHOT_BYTES) ? snapshots : state === void 0 && unchanged ? [latest] : [];
12498
+ const stale = snapshots.filter((snapshot) => !retained.includes(snapshot));
12499
+ return {
12500
+ message: current === void 0 || unchanged && retained.includes(latest) ? void 0 : createPluginMessage(current, "memory-snapshot", state),
12501
+ retire(turn, step) {
12502
+ const visible = new Set(session.surface.nodes);
12503
+ for (const { seq } of stale) {
12504
+ if (!visible.has(seq)) continue;
12505
+ if (session.append === void 0) throw new Error("DSH Session append is required to retire superseded memory snapshots");
12506
+ session.append("developer/message", {
12507
+ turn,
12508
+ step,
12509
+ message: {
12510
+ id: randomUUID(),
12511
+ role: "developer",
12512
+ content: [],
12513
+ source: {
12514
+ kind: MNEMON_PLUGIN_SOURCE,
12515
+ form: "memory-snapshot-retired"
12516
+ }
12517
+ }
12518
+ }, {
12519
+ surfaceOp: {
12520
+ op: "replace",
12521
+ startSeq: seq,
12522
+ endSeq: seq
12523
+ },
12524
+ sourceEventSeqs: [seq]
12525
+ });
12526
+ }
12527
+ }
12528
+ };
12529
+ }
12530
+ //#endregion
12316
12531
  //#region src/host/idle-review-watermark.ts
12317
12532
  const MAX_STATE_BYTES = 16384;
12318
12533
  const MAX_TIMESTAMP = 864e13;
@@ -12477,11 +12692,6 @@ function llmService(value) {
12477
12692
  if (typeof value !== "object" || value === null || !("listProviders" in value) || typeof value.listProviders !== "function" || !("listModels" in value) || typeof value.listModels !== "function") return void 0;
12478
12693
  return value;
12479
12694
  }
12480
- function isMnemonMessageSource(source) {
12481
- if (typeof source !== "object" || source === null) return false;
12482
- const { kind, plugin } = source;
12483
- return kind === "dsh-mnemon" || kind === `plugin:dsh-mnemon` || kind === "plugin" && plugin === "dsh-mnemon";
12484
- }
12485
12695
  /**
12486
12696
  * Whether an event is a durable user message this plugin produced.
12487
12697
  */
@@ -12561,16 +12771,9 @@ var MnemonAgentLifecycle = class {
12561
12771
  primePending = true;
12562
12772
  startSource;
12563
12773
  guidedTurns = /* @__PURE__ */ new Set();
12774
+ pendingSnapshot;
12564
12775
  memoryActivity = new TurnActivityProjection();
12565
12776
  turnActivity = /* @__PURE__ */ new Map();
12566
- /**
12567
- * Text of the runtime memory snapshot most recently injected as this
12568
- * plugin's own message. `.context()` used to get supersede-on-change for free
12569
- * from the host's runtime-context projection; carrying the snapshot as an own
12570
- * message means re-emitting on change is this plugin's responsibility, and
12571
- * the rendered text (which carries the revision digest) is the key.
12572
- */
12573
- injectedMemoryText;
12574
12777
  idleReviewTimer;
12575
12778
  reviewController;
12576
12779
  reviewRunning = false;
@@ -12616,6 +12819,10 @@ var MnemonAgentLifecycle = class {
12616
12819
  ];
12617
12820
  return () => {
12618
12821
  this.disposed = true;
12822
+ const pending = this.pendingSnapshot;
12823
+ this.pendingSnapshot = void 0;
12824
+ const started = pending === void 0 ? void 0 : this.agent.session.snapshotEvents().findLast((event) => event.type === "step/start");
12825
+ if (pending !== void 0 && started !== void 0 && eventTurn(started) === pending.turn && started.data.step === pending.step) this.queueSnapshotRetirement(pending);
12619
12826
  this.releaseView();
12620
12827
  this.cancelIdleReview(true);
12621
12828
  for (const dispose of disposers.reverse()) dispose();
@@ -12685,24 +12892,8 @@ var MnemonAgentLifecycle = class {
12685
12892
  for (const seq of this.agent.session.surface.nodes) if (isOwnUserMessageEvent(this.agent.session.eventAt(seq))) return true;
12686
12893
  return false;
12687
12894
  }
12688
- /**
12689
- * The runtime memory snapshot, as this plugin's own message, when it changed.
12690
- *
12691
- * `.context()` used to carry this inside the host's shared runtime-context
12692
- * projection. Carrying it here instead attributes it to dsh-mnemon and keeps
12693
- * a memory write from re-emitting other contributors' sections; supersede
12694
- * stays intact because the block is still a complete state replacing its
12695
- * predecessor, keyed on the rendered text's revision digest.
12696
- */
12697
- memorySnapshotMessage() {
12698
- const wake = this.memoryWake();
12699
- if (wake === void 0) return void 0;
12700
- const text = wake.text;
12701
- if (text.trim() === "" || text === this.injectedMemoryText) return void 0;
12702
- this.injectedMemoryText = text;
12703
- return createPluginMessage(text, "recall");
12704
- }
12705
12895
  async preStep(payload, next) {
12896
+ this.pendingSnapshot = void 0;
12706
12897
  if (payload.step === 1) this.cancelIdleReview(true);
12707
12898
  const decision = await next();
12708
12899
  if (decision.kind === "reject" || payload.signal.aborted) {
@@ -12710,12 +12901,19 @@ var MnemonAgentLifecycle = class {
12710
12901
  return decision;
12711
12902
  }
12712
12903
  if (!this.disposed && openAgentTurn(this.agent) === payload.turn) await this.memoryTurn?.begin(payload.turn, payload.signal);
12904
+ const update = prepareMemorySnapshot(this.agent.session, this.config.lifecycleEnabled ? this.memoryWake()?.text : void 0, this.config.lifecycleEnabled ? memorySnapshotState(this.memoryTurn?.current?.context.view) : void 0);
12905
+ this.pendingSnapshot = {
12906
+ turn: payload.turn,
12907
+ step: payload.step,
12908
+ signal: payload.signal,
12909
+ update
12910
+ };
12713
12911
  if (!this.config.lifecycleEnabled) return decision;
12714
12912
  if (this.config.writeEnabled && this.config.writebackMode === "guided") this.recordTurnMessages(payload.turn, decision.messages);
12715
12913
  if (payload.step !== 1) return decision;
12716
12914
  if (decision.messages.some((message) => isMnemonMessageSource(message.source))) return decision;
12717
12915
  if (decision.messages.length === 0) return decision;
12718
- const snapshot = this.memorySnapshotMessage();
12916
+ const snapshot = update.message;
12719
12917
  const withSnapshot = (messages) => snapshot === void 0 ? messages : [...messages, snapshot];
12720
12918
  if (this.primePending) {
12721
12919
  this.primePending = false;
@@ -12784,12 +12982,40 @@ var MnemonAgentLifecycle = class {
12784
12982
  if (admitted) this.scheduleIdleReview(payload.turn);
12785
12983
  }
12786
12984
  sessionEvent(session, event) {
12787
- if (session !== this.agent.session || event.type !== "turn/end") return;
12985
+ if (session !== this.agent.session) return;
12788
12986
  const turn = eventTurn(event);
12987
+ if (event.type === "step/start") {
12988
+ const pending = this.pendingSnapshot;
12989
+ if (pending === void 0 || pending.turn !== turn || pending.step !== event.data.step) return;
12990
+ this.pendingSnapshot = void 0;
12991
+ this.queueSnapshotRetirement(pending);
12992
+ return;
12993
+ }
12994
+ if (event.type !== "turn/end") return;
12995
+ if (this.pendingSnapshot?.turn === turn) this.pendingSnapshot = void 0;
12789
12996
  const current = this.memoryTurn?.current;
12790
12997
  if ((turn === void 0 || current?.turn !== turn ? void 0 : current) === void 0) return;
12791
12998
  this.releaseView(turn);
12792
12999
  }
13000
+ queueSnapshotRetirement(pending) {
13001
+ queueMicrotask(() => {
13002
+ if (pending.signal.aborted || openAgentTurn(this.agent) !== pending.turn) return;
13003
+ try {
13004
+ pending.update.retire(pending.turn, pending.step);
13005
+ } catch {
13006
+ const reason = "Memory snapshot checkpoint failed; model request cancelled.";
13007
+ this.counters.failures += 1;
13008
+ this.lastPhase = "error";
13009
+ this.lastAt = (/* @__PURE__ */ new Date()).toISOString();
13010
+ this.lastError = reason;
13011
+ this.agent.cancel({
13012
+ kind: "hook",
13013
+ reason
13014
+ }, { keepInbox: true });
13015
+ console.warn("[dsh-mnemon] Memory snapshot checkpoint failed; model request cancelled.");
13016
+ }
13017
+ });
13018
+ }
12793
13019
  scheduleIdleReview(turn) {
12794
13020
  this.cancelIdleReview(true);
12795
13021
  if (!this.restoreWatermark() || !this.idleReviewAllowed()) return;
@@ -14915,12 +15141,15 @@ var SkillEvolution = class {
14915
15141
  const source = retryingSource(port);
14916
15142
  const pack = await source.read("evidence-pack", {
14917
15143
  ...input.suggestionId === void 0 ? {} : { suggestionId: input.suggestionId },
15144
+ ...input.draftId === void 0 ? {} : { draftId: input.draftId },
14918
15145
  ...input.skill === void 0 ? {} : { skill: input.skill }
14919
15146
  });
14920
- const previous = pack.suggestion?.draftId === void 0 ? (await source.read("drafts", {
15147
+ const previousId = input.draftId ?? pack.suggestion?.draftId;
15148
+ const previous = previousId === void 0 ? (await source.read("drafts", {
14921
15149
  skill: pack.skillName,
15150
+ ...pack.skill === void 0 ? {} : { path: pack.skill.path },
14922
15151
  ...input.suggestionId === void 0 ? {} : { suggestionId: input.suggestionId }
14923
- })).find((draft) => draft.suggestionId === input.suggestionId) : (await source.read("draft", { id: pack.suggestion.draftId })).draft;
15152
+ })).find((draft) => draft.suggestionId === input.suggestionId) : (await source.read("draft", { id: previousId })).draft;
14924
15153
  const targetRoot = pack.action === "update" ? pack.skill.root : newSkillRoot(this.host.settings(), source, await source.read("catalog"), input.targetRoot ?? previous?.targetRoot ?? pack.suggestion?.targetRoot);
14925
15154
  const guidance = [...previous?.guidance ?? [], ...input.guidance?.trim() ? [input.guidance.trim()] : []].slice(-8);
14926
15155
  if (input.suggestionId !== void 0) await source.mutate("suggestion-status", {
@@ -14978,6 +15207,7 @@ var SkillEvolution = class {
14978
15207
  signal.throwIfAborted();
14979
15208
  draft = await source.mutate("draft-record", {
14980
15209
  ...input.suggestionId === void 0 ? {} : { suggestionId: input.suggestionId },
15210
+ ...input.draftId === void 0 ? {} : { draftId: input.draftId },
14981
15211
  skillName: pack.skillName,
14982
15212
  content: parsed.content,
14983
15213
  notes: parsed.notes,
@@ -15007,7 +15237,10 @@ var SkillEvolution = class {
15007
15237
  else {
15008
15238
  const baseline = await this.backtest(source, workspace, {
15009
15239
  skillName: pack.skillName,
15010
- target: { kind: pack.action === "update" ? "current" : "none" },
15240
+ target: {
15241
+ kind: pack.action === "update" ? "current" : "none",
15242
+ ...pack.action === "update" ? { draftId: draft.id } : {}
15243
+ },
15011
15244
  ...input.route === void 0 ? {} : { route: input.route }
15012
15245
  });
15013
15246
  await source.mutate("run-link", {
@@ -15543,14 +15776,16 @@ async function skillAssistance(runtime, lifecycle, operation, input, signal) {
15543
15776
  "user-agents"
15544
15777
  ].includes(root)) throw new Error("unknown skill root: " + root);
15545
15778
  const suggestionId = optionalString(input.suggestionId, "suggestionId");
15779
+ const draftId = optionalString(input.draftId, "draftId");
15546
15780
  const skill = optionalString(input.skill, "skill");
15547
- if (suggestionId === void 0 && skill === void 0) throw new Error("a draft needs a suggestion or a skill");
15781
+ if (suggestionId === void 0 && draftId === void 0 && skill === void 0) throw new Error("a draft needs a suggestion, a draft, or a skill");
15548
15782
  const guidance = optionalString(input.guidance, "guidance");
15549
15783
  if (guidance !== void 0 && guidance.length > 4e3) throw new Error("guidance is too long (max 4000 characters)");
15550
15784
  const draftRoute = modelRoute(input);
15551
15785
  return skills.draft(source, workspaceRoot, {
15552
15786
  ...suggestionId === void 0 ? {} : { suggestionId },
15553
15787
  ...skill === void 0 ? {} : { skill },
15788
+ ...draftId === void 0 ? {} : { draftId },
15554
15789
  ...guidance === void 0 ? {} : { guidance },
15555
15790
  ...root === void 0 ? {} : { targetRoot: root },
15556
15791
  ...draftRoute === void 0 ? {} : { route: draftRoute }
@@ -14,10 +14,10 @@ var dependencies = {
14
14
  "dsh-mnemon-provider-openviking": "0.5.10",
15
15
  "dsh-mnemon-provider-retaindb": "0.5.6",
16
16
  "dsh-mnemon-provider-supermemory": "0.5.5",
17
- "dsh-mnemon-source-documents": "0.5.13",
17
+ "dsh-mnemon-source-documents": "0.6.0",
18
18
  "dsh-mnemon-source-memory-spaces": "0.5.25",
19
- "dsh-mnemon-source-runtime": "0.5.17",
20
- "dsh-mnemon-source-skills": "0.5.8",
19
+ "dsh-mnemon-source-runtime": "0.5.18",
20
+ "dsh-mnemon-source-skills": "0.5.9",
21
21
  "dsh-mnemon-strategy-auto-capture": "0.5.5",
22
22
  "dsh-mnemon-strategy-default-three-tier": "0.5.12",
23
23
  "dsh-mnemon-strategy-general": "0.5.1",
package/lib/starter.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as prepareStarterResolution } from "./starter-resolution-xVjONc6g.js";
1
+ import { t as prepareStarterResolution } from "./starter-resolution-B5mdKlvf.js";
2
2
  //#region src/starter.ts
3
3
  const name = "dsh-mnemon-starter";
4
4
  const provide = ["mnemonStarterReady"];
@@ -432,6 +432,7 @@ export declare const zh: {
432
432
  'board.relationNeeds': string;
433
433
  'board.relationNeededBy': string;
434
434
  'options.aria': string;
435
+ 'options.emptySourcesConfirm': string;
435
436
  'options.apply': string;
436
437
  'options.fix': string;
437
438
  'options.applying': string;
@@ -1355,6 +1356,12 @@ export declare const zh: {
1355
1356
  "documents.selectText": string;
1356
1357
  "documents.coldArchive": string;
1357
1358
  "documents.edit": string;
1359
+ "documents.delete": string;
1360
+ "documents.deleteConfirm": string;
1361
+ "documents.deleteDescription": string;
1362
+ "documents.deleteNow": string;
1363
+ "documents.deleting": string;
1364
+ "documents.deleted": string;
1358
1365
  "documents.path": string;
1359
1366
  "documents.revision": string;
1360
1367
  "documents.hash": string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-mnemon",
3
- "version": "0.5.41",
3
+ "version": "0.5.42",
4
4
  "description": "Composable, view-based context for DeepSeek Harness. Pluggable sources and strategies, with layered memory and self-evolving skills out of the box.",
5
5
  "keywords": [
6
6
  "deepseek-harness",
@@ -164,10 +164,10 @@
164
164
  "dsh-mnemon-provider-openviking": "0.5.10",
165
165
  "dsh-mnemon-provider-retaindb": "0.5.6",
166
166
  "dsh-mnemon-provider-supermemory": "0.5.5",
167
- "dsh-mnemon-source-documents": "0.5.13",
167
+ "dsh-mnemon-source-documents": "0.6.0",
168
168
  "dsh-mnemon-source-memory-spaces": "0.5.25",
169
- "dsh-mnemon-source-runtime": "0.5.17",
170
- "dsh-mnemon-source-skills": "0.5.8",
169
+ "dsh-mnemon-source-runtime": "0.5.18",
170
+ "dsh-mnemon-source-skills": "0.5.9",
171
171
  "dsh-mnemon-strategy-auto-capture": "0.5.5",
172
172
  "dsh-mnemon-strategy-default-three-tier": "0.5.12",
173
173
  "dsh-mnemon-strategy-general": "0.5.1",