dsh-mnemon 0.5.38 → 0.5.40

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/README.md CHANGED
@@ -111,7 +111,7 @@ npx @deepseek-ai/dsh web
111
111
  4. For Memory Spaces, install the Mnemon CLI for Mnemon Native with `npm install --global @mnemon-dev/mnemon`, or enable another Provider on the Memory Spaces page.
112
112
  5. Choose the main strategy and enhancements under **Plugins → dsh-mnemon**.
113
113
 
114
- dsh-mnemon supports DSH `0.2.1-rc.2` (npm `latest` and `next`) and `0.2.0-rc.2`. The same package serves the desktop app's Plugins page, `dsh plugin --profile web add dsh-mnemon` on the command line, and Headless with `dsh plugin --profile headless add dsh-mnemon`; older hosts keep the release [compatibility and upgrades](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/en/reference/compatibility.md) names for them. [Getting started](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/en/guides/getting-started.md) continues from here, and [compatibility and upgrades](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/en/reference/compatibility.md) covers existing installations.
114
+ dsh-mnemon supports published DSH `0.2.2-rc.1` and retains support for the `0.2.1` RC line and `0.2.0-rc.2`. RC1 requires Node.js >=24.9.0; older Hosts follow their own Node.js requirements. The same package serves the desktop app's Plugins page, `dsh plugin --profile web add dsh-mnemon` on the command line, and Headless with `dsh plugin --profile headless add dsh-mnemon`; older hosts keep the release [compatibility and upgrades](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/en/reference/compatibility.md) names for them. [Getting started](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/en/guides/getting-started.md) continues from here, and [compatibility and upgrades](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/en/reference/compatibility.md) covers existing installations.
115
115
 
116
116
  ## How it works
117
117
 
package/README.zh-CN.md CHANGED
@@ -112,7 +112,7 @@ npx @deepseek-ai/dsh web
112
112
  4. 使用记忆空间时,可用 `npm install --global @mnemon-dev/mnemon` 安装 Mnemon Native 所需的 CLI,或在记忆空间页面启用其他 Provider。
113
113
  5. 在**插件 → 可组合记忆**中选择主策略与增强。
114
114
 
115
- dsh-mnemon 支持 DSH `0.2.1-rc.2`(npm `latest` 与 `next`)与 `0.2.0-rc.2`。同一个包也用于桌面版的插件页、命令行 `dsh plugin --profile web add dsh-mnemon`,以及 Headless:`dsh plugin --profile headless add dsh-mnemon`;更早的宿主请继续使用[兼容性与升级](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/zh-CN/reference/compatibility.md)为其列出的版本。接下来可以看[入门指南](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/zh-CN/guides/getting-started.md),已有安装的升级见[兼容性与升级](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/zh-CN/reference/compatibility.md)。
115
+ dsh-mnemon 支持已发布的 DSH `0.2.2-rc.1`,同时保留对 `0.2.1` RC 系列和 `0.2.0-rc.2` 的支持。RC1 要求 Node.js >=24.9.0;旧版宿主遵循其各自的 Node.js 要求。同一个包也用于桌面版的插件页、命令行 `dsh plugin --profile web add dsh-mnemon`,以及 Headless:`dsh plugin --profile headless add dsh-mnemon`;更早的宿主请继续使用[兼容性与升级](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/zh-CN/reference/compatibility.md)为其列出的版本。接下来可以看[入门指南](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/zh-CN/guides/getting-started.md),已有安装的升级见[兼容性与升级](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/zh-CN/reference/compatibility.md)。
116
116
 
117
117
  ## 工作原理
118
118
 
@@ -614,6 +614,89 @@ function encodeFrames(text) {
614
614
  return Buffer.concat([text.slice(0, end), text.slice(end)].filter(Boolean).map(part => zlib.zstdCompressSync(part, options)))
615
615
  }
616
616
 
617
+ async function writeRepairCopy(input, output, result) {
618
+ if (resolve(input) === resolve(output)) throw new Error('Output must be a new copy; the input cannot be overwritten.')
619
+ const temporary = await mkdtemp(join(dirname(resolve(output)), '.mnemon-repair-'))
620
+ try {
621
+ const path = join(temporary, 'session')
622
+ const file = await open(path, 'wx', 0o600)
623
+ try { await file.writeFile(result); await file.sync() } finally { await file.close() }
624
+ // Publish exclusively, including when output is a symlink or hard link.
625
+ await link(path, output)
626
+ } finally { await rm(temporary, { recursive: true, force: true }) }
627
+ }
628
+
629
+ /** Preserve the complete audit payload and all offsets; never truncate history. */
630
+ async function repairIdleProbeSession(entries, original, compressed, input, output) {
631
+ const header = entries[0].row
632
+ assertUniqueJson(entries[0].line, header)
633
+ if (header.type !== 'session' || header.version !== 4 || header.isSeeded !== false || header.delegationDepth !== 0 ||
634
+ header.parentSession !== undefined || header.origin !== undefined) throw new Error('Idle probe recovery requires an unseeded v4 root Session.')
635
+ const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u
636
+ const recovered = new Set()
637
+ const pending = new Map()
638
+ const roots = new Set()
639
+ let openTurn
640
+ let completed = false
641
+ const refuse = () => { throw new Error('Unrecognized or incomplete out-of-turn PTC audit; no output written.') }
642
+ for (const entry of entries.slice(1)) {
643
+ const row = entry.row
644
+ if (row.type === 'turn/start' || row.type === 'turn/end') {
645
+ assertUniqueJson(entry.line, row)
646
+ if (pending.size || !count(row.data?.turn)) refuse()
647
+ if (row.type === 'turn/start') {
648
+ if (openTurn !== undefined) refuse()
649
+ openTurn = row.data.turn
650
+ } else {
651
+ if (openTurn !== row.data.turn) refuse()
652
+ openTurn = undefined
653
+ completed = true
654
+ }
655
+ }
656
+ if (!['tool/ptc-dispatch-start', 'tool/ptc-dispatch'].includes(row.type) || openTurn !== undefined) continue
657
+ assertUniqueJson(entry.line, row)
658
+ const data = row.data
659
+ const start = row.type === 'tool/ptc-dispatch-start'
660
+ if (!completed || !exactKeys(row, ['type', 'seq', 'time', 'data']) || !count(row.seq) || !integer(row.time) ||
661
+ !exactKeys(data, ['rootCallId', 'parentCallId', 'subCallId', 'name', 'arguments', ...(start ? [] : ['isError', 'content'])], start ? [] : ['error', 'meta']) ||
662
+ !uuid.test(data.rootCallId) || data.parentCallId !== data.rootCallId || data.subCallId !== `${data.rootCallId}:ptc:1` ||
663
+ data.name !== 'mnemon_subagent_result' || !exactKeys(data.arguments, ['requestId', 'result']) ||
664
+ !uuid.test(data.arguments.requestId) || !exactKeys(data.arguments.result, [])) refuse()
665
+ if (start) {
666
+ if (roots.has(data.rootCallId)) refuse()
667
+ roots.add(data.rootCallId)
668
+ pending.set(data.rootCallId, entry)
669
+ } else {
670
+ const previous = pending.get(data.rootCallId)
671
+ if (!previous || !isDeepStrictEqual(previous.row.data.arguments, data.arguments) || previous.row.seq >= row.seq ||
672
+ typeof data.isError !== 'boolean' || !Array.isArray(data.content) ||
673
+ !data.isError && !isDeepStrictEqual(data.content, [{ type: 'text', text: 'Mnemon subagent result recorded.' }])) refuse()
674
+ pending.delete(data.rootCallId)
675
+ recovered.add(previous)
676
+ recovered.add(entry)
677
+ }
678
+ }
679
+ if (pending.size) refuse()
680
+ const changedSeqs = new Set([...recovered].map(entry => entry.row.seq))
681
+ for (const { row } of entries.slice(1)) {
682
+ for (const range of row.sourceEventSeqs ?? []) {
683
+ if (typeof range === 'number' ? changedSeqs.has(range) : Array.isArray(range) && [...changedSeqs].some(seq => seq >= range[0] && seq <= range[1])) refuse()
684
+ }
685
+ }
686
+ const text = entries.map(entry => recovered.has(entry)
687
+ ? JSON.stringify({ type: 'dsh-mnemon/recovered-idle-probe', seq: entry.row.seq, time: entry.row.time, ignorable: true,
688
+ data: { originalType: entry.row.type, originalData: entry.row.data } }) + '\n'
689
+ : entry.line).join('')
690
+ const plain = Buffer.from(text)
691
+ if (plain.length > maximumBytes) throw new Error('Repaired Session exceeds the 128 MiB repair limit; no output written.')
692
+ const result = recovered.size === 0 ? original : compressed ? encodeFrames(text) : plain
693
+ if (result.length > maximumBytes) throw new Error('Repaired Session exceeds the 128 MiB repair limit; no output written.')
694
+ if (output !== undefined) await writeRepairCopy(input, output, result)
695
+ return { mode: output === undefined ? 'preview' : 'copy', format: 4, encoding: compressed ? 'zstd' : 'jsonl',
696
+ recoveredIdleProbeEvents: recovered.size, inputSha256: sha256(original), outputSha256: sha256(result),
697
+ originalPreserved: true, migrationValidated: false, blockers: [] }
698
+ }
699
+
617
700
  export async function repairLegacySession(input, output) {
618
701
  const original = await readBounded(input)
619
702
  const compressed = original.subarray(0, 4).equals(Buffer.from([0x28, 0xb5, 0x2f, 0xfd]))
@@ -627,6 +710,7 @@ export async function repairLegacySession(input, output) {
627
710
  const entries = lines.map((line, index) => {
628
711
  try { return { line, index, row: JSON.parse(line) } } catch { throw new Error(`Invalid JSON at line ${index + 1}; no output written.`) }
629
712
  })
713
+ if (entries[0]?.row?.version === 4) return repairIdleProbeSession(entries, original, compressed, input, output)
630
714
  const recovery = recoverRecordedToolIdentities(entries)
631
715
  let changes = 0
632
716
  let descriptors = 0
@@ -681,15 +765,7 @@ export async function repairLegacySession(input, output) {
681
765
  if (result.length > maximumBytes) throw new Error('Repaired Session exceeds the 128 MiB repair limit; no output written.')
682
766
  const blockers = diagnostics.report()
683
767
  if (output !== undefined && blockers.length === 0) {
684
- if (resolve(input) === resolve(output)) throw new Error('Output must be a new copy; the input cannot be overwritten.')
685
- const temporary = await mkdtemp(join(dirname(resolve(output)), '.mnemon-repair-'))
686
- try {
687
- const path = join(temporary, 'session')
688
- const file = await open(path, 'wx', 0o600)
689
- try { await file.writeFile(result); await file.sync() } finally { await file.close() }
690
- // Publish exclusively, including when output is a symlink or hard link.
691
- await link(path, output)
692
- } finally { await rm(temporary, { recursive: true, force: true }) }
768
+ await writeRepairCopy(input, output, result)
693
769
  }
694
770
  return {
695
771
  mode: output === undefined ? 'preview' : blockers.length === 0 ? 'copy' : 'refused',
@@ -712,7 +788,7 @@ export async function repairLegacySession(input, output) {
712
788
  }
713
789
 
714
790
  async function main(args) {
715
- const usage = 'Usage: dsh-mnemon-repair-session --input FILE [--output NEW_FILE]\nWithout --output, preview the three known Mnemon v0 summary repairs, exact compatible v2 subagent descriptors, packed deltas with empty IDs/names, property-preserving null-to-empty delta names and proven DeepSeek chains with a previously recorded provider ID. Unsupported descriptor/tool shapes are reported with exit status 1 and prevent output. DSH must still validate the repaired copy. Stop DSH and work on a backup copy. The input and existing output files are never overwritten.'
791
+ const usage = 'Usage: dsh-mnemon-repair-session --input FILE [--output NEW_FILE]\nWithout --output, preview recognized v4 idle-review probe audit recovery or the three known Mnemon v0 summary repairs, exact compatible v2 subagent descriptors, packed deltas with empty IDs/names, property-preserving null-to-empty delta names and proven DeepSeek chains with a previously recorded provider ID. Unsupported descriptor/tool shapes are reported with exit status 1 and prevent output. DSH must still validate the repaired copy. Stop DSH and work on a backup copy. The input and existing output files are never overwritten.'
716
792
  if (args.length === 1 && args[0] === '--help') { console.log(usage); return }
717
793
  const options = new Map()
718
794
  for (let index = 0; index < args.length; index += 2) {
package/lib/bundle.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as prepareStarterResolution } from "./starter-resolution-XVFzvnV0.js";
1
+ import { t as prepareStarterResolution } from "./starter-resolution-C5nNk-cs.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
@@ -316,6 +316,7 @@ window.__ModuleLoader__.load({
316
316
  evolution: false,
317
317
  allowCreate: true,
318
318
  allowUpdate: true,
319
+ targetScope: "user",
319
320
  autoBacktest: true,
320
321
  hints: true,
321
322
  sidebar: false,
@@ -2480,6 +2481,10 @@ window.__ModuleLoader__.load({
2480
2481
  "status.title": "系统状态",
2481
2482
  "status.description": "dsh-mnemon、记忆 Provider 与各层存储的运行状态。",
2482
2483
  "status.nominal": "系统正常",
2484
+ "status.workflowUnavailable": "后台维护未运行",
2485
+ "status.workflowIdleReview": "空闲审查",
2486
+ "status.workflowRuntimeCapacity": "运行时容量维护",
2487
+ "status.workflowUnsupported": "当前策略不驱动:{workflows}。仅开启审查设置不会启动这些维护任务。可在记忆系统中选择支持相应能力的策略(如分层策略)。手动操作仍可使用。",
2483
2488
  "status.reviewFailed": "空闲审查失败",
2484
2489
  "status.reviewFailedDetail": "本轮记忆检查未完成,不会自动重放。后续审查受冷却时间和会话次数限制。",
2485
2490
  "status.reviewPartial": "已有写入提交;请按下列回执核对,未回滚。",
@@ -2772,7 +2777,8 @@ window.__ModuleLoader__.load({
2772
2777
  "details.currentMain": "当前主策略",
2773
2778
  "details.useMain": "设为主策略",
2774
2779
  "details.back": "返回“{component}”",
2775
- "threeTier.offNote": "开启后这些后台任务才会运行",
2780
+ "config.strategyWorkflowNote": "空闲审查与运行时容量维护仅在当前策略支持相应能力时运行。General 策略不驱动这两项维护;设置会保留,可在记忆系统切换回分层策略后使用。",
2781
+ "threeTier.offNote": "当前插件未启用。后台任务还需主策略支持相应能力。",
2776
2782
  "board.otherEnhancements": "适用于其他主策略的增强({count})",
2777
2783
  "board.more": "更多组件可在插件列表中添加",
2778
2784
  "board.relationNeeds": "需要“{component}”",
@@ -3054,7 +3060,7 @@ window.__ModuleLoader__.load({
3054
3060
  "config.syncAuthorDefault": "默认",
3055
3061
  "config.syncAuthorMachine": "本机 Git",
3056
3062
  "config.syncAuthorCustom": "自定义",
3057
- "config.syncAuthorDefaultNote": "以 {identity} 提交",
3063
+ "config.syncAuthorDefaultNote": "优先使用本机 Git 身份;没有配置时以 {identity} 提交",
3058
3064
  "config.syncAuthorMachineNote": "使用这台电脑的 Git 身份;没有配置时用默认身份",
3059
3065
  "config.syncAuthorName": "姓名",
3060
3066
  "config.syncAuthorEmail": "邮箱",
@@ -3130,6 +3136,11 @@ window.__ModuleLoader__.load({
3130
3136
  "skills.allowCreateHint": "允许复盘提出新技能;已有建议仍可手动处理",
3131
3137
  "skills.allowUpdate": "改进已有技能",
3132
3138
  "skills.allowUpdateHint": "允许复盘提出已有技能的改进;两类建议均关闭时暂停复盘",
3139
+ "skills.targetScope": "新技能写入位置",
3140
+ "skills.targetScopeHint": "默认写入用户技能;跟随存储范围时,workspace / workspaces 写入项目,其余写入用户。已有建议和草案保留目标,改进写回原技能;采纳时可手动选择。",
3141
+ "skills.targetScope.user": "用户",
3142
+ "skills.targetScope.project": "项目",
3143
+ "skills.targetScope.storage": "跟随存储范围",
3133
3144
  "skills.evolutionHint": "后台复盘并建议改进技能;会创建落盘的任务及子代理会话,Mnemon 不自动删除这些记录",
3134
3145
  "skills.autoBacktest": "草案自动回测",
3135
3146
  "skills.autoBacktestHint": "草案写好后,用测试用例与当前版本对比",
@@ -3290,6 +3301,10 @@ window.__ModuleLoader__.load({
3290
3301
  "status.title": "System Status",
3291
3302
  "status.description": "How dsh-mnemon, memory Providers and each storage layer are running.",
3292
3303
  "status.nominal": "System nominal",
3304
+ "status.workflowUnavailable": "Background maintenance unavailable",
3305
+ "status.workflowIdleReview": "Idle review",
3306
+ "status.workflowRuntimeCapacity": "Runtime capacity maintenance",
3307
+ "status.workflowUnsupported": "The current Strategy does not drive: {workflows}. Enabling review settings alone does not start these tasks. Select a Strategy that supports them, such as the Layered Strategy, in Memory System. Manual actions remain available.",
3293
3308
  "status.reviewFailed": "Idle review failed",
3294
3309
  "status.reviewFailedDetail": "This checkpoint did not complete and will not be replayed automatically. Later reviews respect the cooldown and session limit.",
3295
3310
  "status.reviewPartial": "Some writes committed. Reconcile the receipts below; they were not rolled back.",
@@ -3582,7 +3597,8 @@ window.__ModuleLoader__.load({
3582
3597
  "details.currentMain": "Current main strategy",
3583
3598
  "details.useMain": "Use as main strategy",
3584
3599
  "details.back": "Back to “{component}”",
3585
- "threeTier.offNote": "These background tasks run once it is on",
3600
+ "config.strategyWorkflowNote": "Idle review and runtime capacity maintenance run only when the current Strategy supports them. The General Strategy drives neither. Settings are retained for use after switching back to the Layered Strategy in Memory System.",
3601
+ "threeTier.offNote": "This plugin is disabled. Background tasks also require a supporting main Strategy.",
3586
3602
  "board.otherEnhancements": "Enhancements for other main strategies ({count})",
3587
3603
  "board.more": "Add more components from the Plugins list",
3588
3604
  "board.relationNeeds": "Needs “{component}”",
@@ -3864,7 +3880,7 @@ window.__ModuleLoader__.load({
3864
3880
  "config.syncAuthorDefault": "Default",
3865
3881
  "config.syncAuthorMachine": "This computer's Git",
3866
3882
  "config.syncAuthorCustom": "Custom",
3867
- "config.syncAuthorDefaultNote": "Commits as {identity}",
3883
+ "config.syncAuthorDefaultNote": "Uses this computer's Git identity; falls back to {identity} when unconfigured",
3868
3884
  "config.syncAuthorMachineNote": "Uses this computer's Git identity, else the default one",
3869
3885
  "config.syncAuthorName": "Name",
3870
3886
  "config.syncAuthorEmail": "Email",
@@ -3940,6 +3956,11 @@ window.__ModuleLoader__.load({
3940
3956
  "skills.allowCreateHint": "Allow reviews to propose new skills; existing suggestions can still be handled manually",
3941
3957
  "skills.allowUpdate": "Suggest skill improvements",
3942
3958
  "skills.allowUpdateHint": "Allow reviews to improve existing skills; reviews pause when both suggestion types are off",
3959
+ "skills.targetScope": "New skill destination",
3960
+ "skills.targetScopeHint": "Defaults to user skills. Follow storage uses the project for workspace / workspaces, otherwise the user. Existing proposals keep their destination; improvements keep their original file. You can choose again at adoption.",
3961
+ "skills.targetScope.user": "User",
3962
+ "skills.targetScope.project": "Project",
3963
+ "skills.targetScope.storage": "Follow storage",
3943
3964
  "skills.evolutionHint": "Review conversations and suggest skills. Task and subagent sessions are saved locally; Mnemon does not automatically delete them.",
3944
3965
  "skills.autoBacktest": "Backtest drafts",
3945
3966
  "skills.autoBacktestHint": "Compare a new draft with the current version on its test cases",
@@ -8519,8 +8540,8 @@ window.__ModuleLoader__.load({
8519
8540
  /**
8520
8541
  * What this computer is called, where on the branch the memory goes and whose name
8521
8542
  * its commits carry. Each field shows the value in use; the computer's name is the
8522
- * host name or a typed one, and the author an explicit choice between the channel's
8523
- * own identity, this computer's Git identity, and a typed one.
8543
+ * host name or a typed one. The default author follows this computer's Git
8544
+ * identity with a placeholder fallback; a custom author overrides it.
8524
8545
  */
8525
8546
  function AdvancedSettings({ client, status, disabled, t, onSaved }) {
8526
8547
  const [open, setOpen] = (0, react.useState)(false);
@@ -12028,8 +12049,8 @@ window.__ModuleLoader__.load({
12028
12049
  }
12029
12050
  /**
12030
12051
  * 技能管理's settings on its page under Plugins. Switches apply at once; the
12031
- * review parameters wait, folded, for their own Apply. Evolution's own
12032
- * switches show only while it is on.
12052
+ * destination and folded review parameters wait for their own Apply. The
12053
+ * destination also applies to manual drafts while evolution is off.
12033
12054
  */
12034
12055
  function SkillsSettings(props) {
12035
12056
  const { scope, page, t } = props;
@@ -12044,6 +12065,9 @@ window.__ModuleLoader__.load({
12044
12065
  const autoBacktest = useLive(saved.autoBacktest, write("autoBacktest"));
12045
12066
  const hints = useLive(saved.hints, write("hints"));
12046
12067
  const sidebar = useLive(saved.sidebar, write("sidebar"));
12068
+ const destination = useStaged({ targetScope: saved.targetScope }, async (draft) => {
12069
+ await scope.mutate([set("targetScope", draft.targetScope)]);
12070
+ });
12047
12071
  const parameters = useStaged(parametersOf(saved), async (draft) => {
12048
12072
  const changed = PARAMETERS.filter((field) => parameterValue(field, draft[field.key]) !== saved[field.key]);
12049
12073
  if (changed.length > 0) await scope.mutate(changed.map((field) => set(field.key, parameterValue(field, draft[field.key]))));
@@ -12080,6 +12104,35 @@ window.__ModuleLoader__.load({
12080
12104
  disabled,
12081
12105
  onChange: allowUpdate.set
12082
12106
  }),
12107
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectRow, {
12108
+ id: "mnemon-skills-target",
12109
+ label: t("skills.targetScope"),
12110
+ hint: t("skills.targetScopeHint"),
12111
+ value: destination.draft.targetScope,
12112
+ options: [
12113
+ "user",
12114
+ "project",
12115
+ "storage"
12116
+ ].map((value) => ({
12117
+ value,
12118
+ label: t(`skills.targetScope.${value}`)
12119
+ })),
12120
+ disabled: disabled || destination.saving,
12121
+ onChange: (targetScope) => destination.edit({ targetScope })
12122
+ }),
12123
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PanelActions, {
12124
+ dirty: destination.dirty,
12125
+ saving: destination.saving,
12126
+ applied: destination.applied,
12127
+ failed: destination.failed,
12128
+ disabled,
12129
+ invalid: null,
12130
+ t,
12131
+ onDiscard: destination.discard,
12132
+ onApply: () => {
12133
+ destination.apply();
12134
+ }
12135
+ }),
12083
12136
  evolution.value && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleRow, {
12084
12137
  id: "mnemon-skills-backtest",
12085
12138
  label: t("skills.autoBacktest"),
@@ -12734,6 +12787,10 @@ window.__ModuleLoader__.load({
12734
12787
  })
12735
12788
  ]
12736
12789
  }),
12790
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
12791
+ className: MnemonSettingsCard_module_css_default.panelNote,
12792
+ children: t("config.strategyWorkflowNote")
12793
+ }),
12737
12794
  !page.component.enabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
12738
12795
  className: MnemonSettingsCard_module_css_default.panelNote,
12739
12796
  children: t("threeTier.offNote")
@@ -15075,6 +15132,18 @@ window.__ModuleLoader__.load({
15075
15132
  })]
15076
15133
  });
15077
15134
  }
15135
+ function BackgroundWorkflowNotice(props) {
15136
+ const t = useT();
15137
+ if (props.workflows === void 0) return null;
15138
+ const missing = [!props.workflows.idleReview ? t("status.workflowIdleReview") : void 0, !props.workflows.runtimeCapacity ? t("status.workflowRuntimeCapacity") : void 0].filter((label) => label !== void 0);
15139
+ if (missing.length === 0) return null;
15140
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15141
+ className: MnemonView_module_css_default.alert,
15142
+ role: "status",
15143
+ "aria-label": t("status.workflowUnavailable"),
15144
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("status.workflowUnavailable") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("status.workflowUnsupported", { workflows: missing.join(" / ") }) })]
15145
+ });
15146
+ }
15078
15147
  function SourceDisabledPage(props) {
15079
15148
  const t = useT();
15080
15149
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -15713,6 +15782,7 @@ window.__ModuleLoader__.load({
15713
15782
  remoteReadOnly,
15714
15783
  reviewPaused: focused ? void 0 : status?.lifecycle?.current?.idleReviewBlocked
15715
15784
  }),
15785
+ !focused && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BackgroundWorkflowNotice, { workflows: status?.memorySystem?.workflows }),
15716
15786
  !focused && status?.lifecycle?.current?.idleReviewWatermark !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
15717
15787
  className: MnemonView_module_css_default.alert,
15718
15788
  role: status.lifecycle.current.idleReviewWatermark.state === "error" ? "alert" : "status",
package/lib/core.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as provideMemoryRuntime } from "./runtime-0u6dOiF9.js";
1
+ import { t as provideMemoryRuntime } from "./runtime-DmL0It3P.js";
2
2
  //#region src/core/plugin.ts
3
3
  const name = "dsh-mnemon-core";
4
4
  const provide = ["mnemonMemory"];