memorix 1.4.3 → 1.4.5

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.
Files changed (158) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +20 -6
  3. package/README.zh-CN.md +16 -3
  4. package/TEAM.md +86 -86
  5. package/assets/star-history-dark.svg +8 -8
  6. package/assets/star-history-light.svg +8 -8
  7. package/assets/star-history.json +16 -2
  8. package/dist/cli/index.js +539 -233
  9. package/dist/cli/memcode.js +0 -0
  10. package/dist/index.js +72 -15
  11. package/dist/maintenance-runner.js +9 -7
  12. package/dist/media-audio-runner.js +9 -7
  13. package/dist/media-video-runner.js +9 -7
  14. package/dist/memcode/index.js +9 -7
  15. package/dist/memcode-runtime/CHANGELOG.md +34 -0
  16. package/dist/sdk.js +71 -14
  17. package/dist/types.d.ts +1 -1
  18. package/dist/vector-backfill-runner.js +9 -7
  19. package/docs/AGENT_OPERATOR_PLAYBOOK.md +6 -5
  20. package/docs/API_REFERENCE.md +9 -5
  21. package/docs/CONFIGURATION.md +15 -5
  22. package/docs/DESIGN_DECISIONS.md +357 -357
  23. package/docs/DEVELOPMENT.md +2 -2
  24. package/docs/INTEGRATIONS.md +9 -2
  25. package/docs/KNOWN_ISSUES_AND_ROADMAP.md +4 -3
  26. package/docs/MEMCODE.md +1 -1
  27. package/docs/MODULES.md +1 -1
  28. package/docs/README.md +1 -1
  29. package/docs/SETUP.md +12 -4
  30. package/docs/hooks-architecture.md +2 -1
  31. package/llms-full.txt +7 -6
  32. package/llms.txt +2 -2
  33. package/package.json +1 -1
  34. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  35. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  36. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  37. package/plugins/copilot/memorix/plugin.json +1 -1
  38. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  39. package/plugins/omp/memorix/package.json +1 -1
  40. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  41. package/plugins/pi/memorix/package.json +1 -1
  42. package/server.json +2 -2
  43. package/src/audit/index.ts +156 -156
  44. package/src/cli/commands/agent-integrations.ts +7 -1
  45. package/src/cli/commands/audit-list.ts +89 -89
  46. package/src/cli/commands/formation.ts +48 -48
  47. package/src/cli/commands/git-hook-install.ts +111 -111
  48. package/src/cli/commands/handoff.ts +54 -54
  49. package/src/cli/commands/hooks-install.ts +2 -0
  50. package/src/cli/commands/hooks-preview.ts +5 -0
  51. package/src/cli/commands/hooks-status.ts +63 -63
  52. package/src/cli/commands/ingest.ts +44 -44
  53. package/src/cli/commands/integrate-shared.ts +15 -15
  54. package/src/cli/commands/integrate.ts +2 -0
  55. package/src/cli/commands/lock.ts +82 -82
  56. package/src/cli/commands/media-image.ts +27 -0
  57. package/src/cli/commands/media.ts +8 -1
  58. package/src/cli/commands/memory.ts +44 -34
  59. package/src/cli/commands/message.ts +104 -104
  60. package/src/cli/commands/operator-shared.ts +62 -18
  61. package/src/cli/commands/poll.ts +58 -58
  62. package/src/cli/commands/purge-all-memory.ts +85 -85
  63. package/src/cli/commands/purge-project-memory.ts +83 -83
  64. package/src/cli/commands/reasoning.ts +118 -118
  65. package/src/cli/commands/setup.ts +57 -2
  66. package/src/cli/commands/skills.ts +114 -114
  67. package/src/cli/commands/task.ts +167 -167
  68. package/src/cli/commands/transfer.ts +47 -47
  69. package/src/cli/commands/uninstall-project-artifacts.ts +85 -85
  70. package/src/cli/commands/uninstall.ts +20 -0
  71. package/src/cli/tui/ChatView.tsx +234 -234
  72. package/src/cli/tui/CommandBar.tsx +312 -312
  73. package/src/cli/tui/ContextRail.tsx +118 -118
  74. package/src/cli/tui/HeaderBar.tsx +72 -72
  75. package/src/cli/tui/LogoBanner.tsx +51 -51
  76. package/src/cli/tui/Sidebar.tsx +179 -179
  77. package/src/cli/tui/index.ts +41 -41
  78. package/src/cli/tui/markdown-render.tsx +371 -371
  79. package/src/cli/tui/use-mouse.ts +157 -157
  80. package/src/cli/tui/useNavigation.ts +56 -56
  81. package/src/cli/version.ts +7 -7
  82. package/src/cli/workbench.ts +1 -1
  83. package/src/dashboard/project-classification.ts +64 -64
  84. package/src/git/hooks-path.ts +85 -85
  85. package/src/hooks/installers/index.ts +43 -2
  86. package/src/hooks/pattern-detector.ts +173 -173
  87. package/src/hooks/significance-filter.ts +250 -250
  88. package/src/hooks/types.ts +2 -0
  89. package/src/integrations/registry.ts +9 -0
  90. package/src/llm/memory-manager.ts +328 -328
  91. package/src/llm/provider.ts +885 -885
  92. package/src/llm/quality.ts +248 -248
  93. package/src/media/minimax.ts +9 -1
  94. package/src/memory/attribution-guard.ts +249 -249
  95. package/src/memory/disclosure-policy.ts +135 -135
  96. package/src/memory/entity-extractor.ts +197 -197
  97. package/src/memory/formation/evaluate.ts +217 -217
  98. package/src/memory/formation/extract.ts +361 -361
  99. package/src/memory/formation/index.ts +417 -417
  100. package/src/memory/formation/resolve.ts +344 -344
  101. package/src/memory/formation/types.ts +315 -315
  102. package/src/memory/freshness.ts +122 -122
  103. package/src/memory/graph.ts +197 -197
  104. package/src/memory/refs.ts +94 -94
  105. package/src/memory/secret-filter.ts +79 -79
  106. package/src/orchestrate/adapters/claude-stream.ts +192 -192
  107. package/src/orchestrate/adapters/claude.ts +111 -111
  108. package/src/orchestrate/adapters/codex-stream.ts +134 -134
  109. package/src/orchestrate/adapters/codex.ts +41 -41
  110. package/src/orchestrate/adapters/gemini-stream.ts +166 -166
  111. package/src/orchestrate/adapters/gemini.ts +42 -42
  112. package/src/orchestrate/adapters/index.ts +73 -73
  113. package/src/orchestrate/adapters/opencode-stream.ts +143 -143
  114. package/src/orchestrate/adapters/opencode.ts +47 -47
  115. package/src/orchestrate/adapters/types.ts +77 -77
  116. package/src/orchestrate/capability-router.ts +284 -284
  117. package/src/orchestrate/context-compact.ts +188 -188
  118. package/src/orchestrate/cost-tracker.ts +219 -219
  119. package/src/orchestrate/error-recovery.ts +191 -191
  120. package/src/orchestrate/evidence.ts +140 -140
  121. package/src/orchestrate/ledger.ts +110 -110
  122. package/src/orchestrate/memorix-bridge.ts +343 -343
  123. package/src/orchestrate/output-budget.ts +80 -80
  124. package/src/orchestrate/permission.ts +152 -152
  125. package/src/orchestrate/pipeline-trace.ts +131 -131
  126. package/src/orchestrate/prompt-builder.ts +155 -155
  127. package/src/orchestrate/ring-buffer.ts +37 -37
  128. package/src/orchestrate/task-graph.ts +389 -389
  129. package/src/project/aliases.ts +374 -374
  130. package/src/rules/adapters/trae.ts +56 -56
  131. package/src/rules/syncer.ts +235 -235
  132. package/src/search/query-expansion.ts +52 -52
  133. package/src/server/formation-timeout.ts +27 -27
  134. package/src/server.ts +23 -1
  135. package/src/skills/mini-skills.ts +386 -386
  136. package/src/store/chat-store.ts +119 -119
  137. package/src/store/graph-store.ts +249 -249
  138. package/src/store/mini-skill-store.ts +349 -349
  139. package/src/store/persistence-json.ts +212 -212
  140. package/src/store/persistence.ts +291 -291
  141. package/src/store/project-affinity.ts +195 -195
  142. package/src/team/event-bus.ts +76 -76
  143. package/src/team/file-locks.ts +173 -173
  144. package/src/team/handoff.ts +161 -161
  145. package/src/team/messages.ts +203 -203
  146. package/src/team/poll.ts +132 -132
  147. package/src/team/tasks.ts +211 -211
  148. package/src/types.ts +1 -1
  149. package/src/workspace/mcp-adapters/codex.ts +191 -191
  150. package/src/workspace/mcp-adapters/copilot.ts +105 -105
  151. package/src/workspace/mcp-adapters/cursor.ts +53 -53
  152. package/src/workspace/mcp-adapters/dsh.ts +147 -0
  153. package/src/workspace/mcp-adapters/kiro.ts +64 -64
  154. package/src/workspace/mcp-adapters/opencode.ts +123 -123
  155. package/src/workspace/mcp-adapters/trae.ts +134 -134
  156. package/src/workspace/mcp-adapters/windsurf.ts +91 -91
  157. package/src/workspace/sanitizer.ts +60 -60
  158. package/dist/memcode-runtime/docs/images/exy.png +0 -0
package/dist/cli/index.js CHANGED
@@ -3221,7 +3221,7 @@ ${import_picocolors.default.gray(m3)} ${s4}
3221
3221
 
3222
3222
  // src/cli/version.ts
3223
3223
  function getCliVersion() {
3224
- return true ? "1.4.3" : pkg.version;
3224
+ return true ? "1.4.5" : pkg.version;
3225
3225
  }
3226
3226
  var init_version = __esm({
3227
3227
  "src/cli/version.ts"() {
@@ -10246,8 +10246,8 @@ async function acquireLock(lockPath) {
10246
10246
  const code = err instanceof Error && "code" in err ? err.code : void 0;
10247
10247
  if (code === "EEXIST" || code === "EPERM") {
10248
10248
  try {
10249
- const stat4 = await fs2.stat(lockPath);
10250
- if (Date.now() - stat4.mtimeMs > LOCK_STALE_MS) {
10249
+ const stat5 = await fs2.stat(lockPath);
10250
+ if (Date.now() - stat5.mtimeMs > LOCK_STALE_MS) {
10251
10251
  await fs2.unlink(lockPath).catch(() => {
10252
10252
  });
10253
10253
  continue;
@@ -27247,11 +27247,11 @@ async function importKnownMedia(input) {
27247
27247
  async function importMediaFile(input) {
27248
27248
  const maxBytes = input.maxBytes ?? DEFAULT_MAX_MEDIA_BYTES;
27249
27249
  const source = path12.resolve(input.filePath);
27250
- const stat4 = await lstat(source);
27251
- if (stat4.isSymbolicLink()) throw new Error("Media import does not follow symbolic links");
27252
- if (!stat4.isFile()) throw new Error("Media import accepts regular files only");
27253
- if (stat4.size <= 0) throw new Error("Media import rejects empty files");
27254
- if (stat4.size > maxBytes) throw new Error(`Media file is too large (${stat4.size} bytes; limit ${maxBytes})`);
27250
+ const stat5 = await lstat(source);
27251
+ if (stat5.isSymbolicLink()) throw new Error("Media import does not follow symbolic links");
27252
+ if (!stat5.isFile()) throw new Error("Media import accepts regular files only");
27253
+ if (stat5.size <= 0) throw new Error("Media import rejects empty files");
27254
+ if (stat5.size > maxBytes) throw new Error(`Media file is too large (${stat5.size} bytes; limit ${maxBytes})`);
27255
27255
  const header = await readHeader(source);
27256
27256
  const detected = detectMedia(header);
27257
27257
  const sha2562 = await sha256File(source);
@@ -27259,7 +27259,7 @@ async function importMediaFile(input) {
27259
27259
  dataDir: input.dataDir,
27260
27260
  projectId: input.projectId,
27261
27261
  sha256: sha2562,
27262
- bytes: stat4.size,
27262
+ bytes: stat5.size,
27263
27263
  detected,
27264
27264
  persist: (destination) => persistFile(source, destination),
27265
27265
  sourceKind: input.sourceKind ?? "import",
@@ -35222,7 +35222,7 @@ var init_image_models_generated = __esm({
35222
35222
  api: "minimax-images",
35223
35223
  provider: "minimax",
35224
35224
  baseUrl: "https://api.minimax.io/v1/image_generation",
35225
- input: ["text"],
35225
+ input: ["text", "image"],
35226
35226
  output: ["image"],
35227
35227
  cost: {
35228
35228
  "input": 0,
@@ -35237,7 +35237,7 @@ var init_image_models_generated = __esm({
35237
35237
  api: "minimax-images",
35238
35238
  provider: "minimax",
35239
35239
  baseUrl: "https://api.minimax.io/v1/image_generation",
35240
- input: ["text"],
35240
+ input: ["text", "image"],
35241
35241
  output: ["image"],
35242
35242
  cost: {
35243
35243
  "input": 0,
@@ -35254,7 +35254,7 @@ var init_image_models_generated = __esm({
35254
35254
  api: "minimax-images",
35255
35255
  provider: "minimax-cn",
35256
35256
  baseUrl: "https://api.minimaxi.com/v1/image_generation",
35257
- input: ["text"],
35257
+ input: ["text", "image"],
35258
35258
  output: ["image"],
35259
35259
  cost: {
35260
35260
  "input": 0,
@@ -35269,7 +35269,7 @@ var init_image_models_generated = __esm({
35269
35269
  api: "minimax-images",
35270
35270
  provider: "minimax-cn",
35271
35271
  baseUrl: "https://api.minimaxi.com/v1/image_generation",
35272
- input: ["text"],
35272
+ input: ["text", "image"],
35273
35273
  output: ["image"],
35274
35274
  cost: {
35275
35275
  "input": 0,
@@ -35368,9 +35368,10 @@ __export(minimax_exports, {
35368
35368
  });
35369
35369
  import { isIP as isIP2 } from "net";
35370
35370
  function buildPayload(model, context, options) {
35371
- if (context.input.some((item) => item.type === "image")) {
35372
- throw new Error(`Model ${model.id} does not support image input`);
35373
- }
35371
+ const subjectReference = context.input.filter((item) => item.type === "image").map((item) => ({
35372
+ type: "character",
35373
+ image_file: `data:${item.mimeType};base64,${item.data}`
35374
+ }));
35374
35375
  const prompt2 = context.input.filter((item) => item.type === "text").map((item) => sanitizeSurrogates(item.text).trim()).filter(Boolean).join("\n");
35375
35376
  if (!prompt2) {
35376
35377
  throw new Error("MiniMax image generation requires a text prompt");
@@ -35381,6 +35382,7 @@ function buildPayload(model, context, options) {
35381
35382
  return {
35382
35383
  model: model.id,
35383
35384
  prompt: prompt2,
35385
+ ...subjectReference.length > 0 ? { subject_reference: subjectReference } : {},
35384
35386
  ...options?.aspectRatio !== void 0 ? { aspect_ratio: options.aspectRatio } : {},
35385
35387
  ...options?.width !== void 0 ? { width: options.width } : {},
35386
35388
  ...options?.height !== void 0 ? { height: options.height } : {},
@@ -78440,21 +78442,21 @@ var init_from = __esm({
78440
78442
  init_fetch_blob();
78441
78443
  ({ stat: stat2 } = fs9);
78442
78444
  blobFromSync = (path47, type) => fromBlob(statSync3(path47), path47, type);
78443
- blobFrom = (path47, type) => stat2(path47).then((stat4) => fromBlob(stat4, path47, type));
78444
- fileFrom = (path47, type) => stat2(path47).then((stat4) => fromFile(stat4, path47, type));
78445
+ blobFrom = (path47, type) => stat2(path47).then((stat5) => fromBlob(stat5, path47, type));
78446
+ fileFrom = (path47, type) => stat2(path47).then((stat5) => fromFile(stat5, path47, type));
78445
78447
  fileFromSync = (path47, type) => fromFile(statSync3(path47), path47, type);
78446
- fromBlob = (stat4, path47, type = "") => new fetch_blob_default([new BlobDataItem({
78448
+ fromBlob = (stat5, path47, type = "") => new fetch_blob_default([new BlobDataItem({
78447
78449
  path: path47,
78448
- size: stat4.size,
78449
- lastModified: stat4.mtimeMs,
78450
+ size: stat5.size,
78451
+ lastModified: stat5.mtimeMs,
78450
78452
  start: 0
78451
78453
  })], { type });
78452
- fromFile = (stat4, path47, type = "") => new file_default([new BlobDataItem({
78454
+ fromFile = (stat5, path47, type = "") => new file_default([new BlobDataItem({
78453
78455
  path: path47,
78454
- size: stat4.size,
78455
- lastModified: stat4.mtimeMs,
78456
+ size: stat5.size,
78457
+ lastModified: stat5.mtimeMs,
78456
78458
  start: 0
78457
- })], basename(path47), { type, lastModified: stat4.mtimeMs });
78459
+ })], basename(path47), { type, lastModified: stat5.mtimeMs });
78458
78460
  BlobDataItem = class _BlobDataItem {
78459
78461
  #path;
78460
78462
  #start;
@@ -85748,7 +85750,7 @@ var require_getCredentials = __commonJS({
85748
85750
  var fs31 = __require("fs");
85749
85751
  var util_1 = __require("util");
85750
85752
  var errorWithCode_1 = require_errorWithCode();
85751
- var readFile9 = fs31.readFile ? (0, util_1.promisify)(fs31.readFile) : async () => {
85753
+ var readFile10 = fs31.readFile ? (0, util_1.promisify)(fs31.readFile) : async () => {
85752
85754
  throw new errorWithCode_1.ErrorWithCode("use key rather than keyFile.", "MISSING_CREDENTIALS");
85753
85755
  };
85754
85756
  var ExtensionFiles;
@@ -85770,7 +85772,7 @@ var require_getCredentials = __commonJS({
85770
85772
  * @returns A promise that resolves with the credentials.
85771
85773
  */
85772
85774
  async getCredentials() {
85773
- const key = await readFile9(this.keyFilePath, "utf8");
85775
+ const key = await readFile10(this.keyFilePath, "utf8");
85774
85776
  let body;
85775
85777
  try {
85776
85778
  body = JSON.parse(key);
@@ -85796,7 +85798,7 @@ var require_getCredentials = __commonJS({
85796
85798
  * @returns A promise that resolves with the private key.
85797
85799
  */
85798
85800
  async getCredentials() {
85799
- const privateKey = await readFile9(this.keyFilePath, "utf8");
85801
+ const privateKey = await readFile10(this.keyFilePath, "utf8");
85800
85802
  return { privateKey };
85801
85803
  }
85802
85804
  };
@@ -87437,7 +87439,7 @@ var require_filesubjecttokensupplier = __commonJS({
87437
87439
  exports.FileSubjectTokenSupplier = void 0;
87438
87440
  var util_1 = __require("util");
87439
87441
  var fs31 = __require("fs");
87440
- var readFile9 = (0, util_1.promisify)(fs31.readFile ?? (() => {
87442
+ var readFile10 = (0, util_1.promisify)(fs31.readFile ?? (() => {
87441
87443
  }));
87442
87444
  var realpath = (0, util_1.promisify)(fs31.realpath ?? (() => {
87443
87445
  }));
@@ -87477,7 +87479,7 @@ var require_filesubjecttokensupplier = __commonJS({
87477
87479
  throw err;
87478
87480
  }
87479
87481
  let subjectToken;
87480
- const rawText = await readFile9(parsedFilePath, { encoding: "utf8" });
87482
+ const rawText = await readFile10(parsedFilePath, { encoding: "utf8" });
87481
87483
  if (this.formatType === "text") {
87482
87484
  subjectToken = rawText;
87483
87485
  } else if (this.formatType === "json" && this.subjectTokenFieldName) {
@@ -176394,6 +176396,7 @@ async function generateMiniMaxImages(input, dependencies = {}) {
176394
176396
  ...input.height !== void 0 ? { height: input.height } : {},
176395
176397
  ...input.seed !== void 0 ? { seed: input.seed } : {},
176396
176398
  ...input.promptOptimizer !== void 0 ? { promptOptimizer: input.promptOptimizer } : {},
176399
+ ...input.subjectImages !== void 0 && input.subjectImages.length > 0 ? { subjectImages: input.subjectImages } : {},
176397
176400
  timeoutMs
176398
176401
  });
176399
176402
  } catch (error40) {
@@ -176433,9 +176436,13 @@ var init_minimax2 = __esm({
176433
176436
  const model = getImageModel(input.provider, input.model);
176434
176437
  if (!model) throw new Error(`MiniMax image model is not registered: ${input.model}`);
176435
176438
  const configuredModel = input.baseUrl ? { ...model, baseUrl: input.baseUrl } : model;
176439
+ const content = [
176440
+ ...(input.subjectImages ?? []).map((image) => ({ type: "image", data: image.data, mimeType: image.mimeType })),
176441
+ { type: "text", text: input.prompt }
176442
+ ];
176436
176443
  const response = await generateImages(
176437
176444
  configuredModel,
176438
- { input: [{ type: "text", text: input.prompt }] },
176445
+ { input: content },
176439
176446
  {
176440
176447
  apiKey: input.apiKey,
176441
176448
  timeoutMs: input.timeoutMs,
@@ -178523,7 +178530,7 @@ function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
178523
178530
  const rel = normalizeCodePath(relative(projectRoot, abs));
178524
178531
  try {
178525
178532
  const text2 = readFileSync7(abs, "utf-8");
178526
- const stat4 = fileStat ?? statSync4(abs);
178533
+ const stat5 = fileStat ?? statSync4(abs);
178527
178534
  const file2 = {
178528
178535
  id: makeCodeFileId(projectId, rel),
178529
178536
  projectId,
@@ -178532,8 +178539,8 @@ function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
178532
178539
  contentHash: hashText(text2),
178533
178540
  // Preserve filesystem precision. Rounding here made same-size edits in
178534
178541
  // a short Windows timestamp window indistinguishable to refresh.
178535
- mtimeMs: Number(stat4.mtimeMs),
178536
- sizeBytes: Number(stat4.size),
178542
+ mtimeMs: Number(stat5.mtimeMs),
178543
+ sizeBytes: Number(stat5.size),
178537
178544
  indexedAt
178538
178545
  };
178539
178546
  return {
@@ -178560,18 +178567,18 @@ async function indexProjectLite(options) {
178560
178567
  let skippedOversizedFiles = 0;
178561
178568
  let unreadableFiles = 0;
178562
178569
  for (const abs of paths) {
178563
- let stat4;
178570
+ let stat5;
178564
178571
  try {
178565
- stat4 = statSync4(abs);
178572
+ stat5 = statSync4(abs);
178566
178573
  } catch {
178567
178574
  unreadableFiles++;
178568
178575
  continue;
178569
178576
  }
178570
- if (Number(stat4.size) > maxFileBytes) {
178577
+ if (Number(stat5.size) > maxFileBytes) {
178571
178578
  skippedOversizedFiles++;
178572
178579
  continue;
178573
178580
  }
178574
- const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat4);
178581
+ const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat5);
178575
178582
  if (!attempt.delta) {
178576
178583
  if (attempt.unreadable) unreadableFiles++;
178577
178584
  continue;
@@ -178599,16 +178606,16 @@ async function refreshProjectLite(store2, options) {
178599
178606
  for (const abs of paths) {
178600
178607
  const rel = normalizeCodePath(relative(options.projectRoot, abs));
178601
178608
  seenPaths.add(rel);
178602
- let stat4;
178609
+ let stat5;
178603
178610
  try {
178604
- stat4 = statSync4(abs);
178611
+ stat5 = statSync4(abs);
178605
178612
  } catch {
178606
178613
  unreadableFiles++;
178607
178614
  continue;
178608
178615
  }
178609
178616
  const existing = existingByPath.get(rel);
178610
- const mtimeMs = Number(stat4.mtimeMs);
178611
- const sizeBytes = Number(stat4.size);
178617
+ const mtimeMs = Number(stat5.mtimeMs);
178618
+ const sizeBytes = Number(stat5.size);
178612
178619
  if (sizeBytes > maxFileBytes) {
178613
178620
  skippedOversizedFiles++;
178614
178621
  if (existing) oversizedExistingFileIds.add(existing.id);
@@ -178618,7 +178625,7 @@ async function refreshProjectLite(store2, options) {
178618
178625
  unchangedFiles++;
178619
178626
  continue;
178620
178627
  }
178621
- const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat4);
178628
+ const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat5);
178622
178629
  if (!attempt.delta) {
178623
178630
  if (attempt.unreadable) unreadableFiles++;
178624
178631
  continue;
@@ -187607,9 +187614,30 @@ function emitError(message, asJson) {
187607
187614
  console.error(asJson ? JSON.stringify({ error: message }, null, 2) : `Error: ${message}`);
187608
187615
  process.exitCode = 1;
187609
187616
  }
187617
+ function asStringArg(value) {
187618
+ if (value == null) return void 0;
187619
+ if (typeof value === "string") {
187620
+ const trimmed = value.trim();
187621
+ return trimmed.length > 0 ? trimmed : void 0;
187622
+ }
187623
+ if (Array.isArray(value)) {
187624
+ const joined = value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean).join(" ");
187625
+ return joined.length > 0 ? joined : void 0;
187626
+ }
187627
+ return void 0;
187628
+ }
187629
+ function lastStringArg(value) {
187630
+ if (typeof value === "string") return value;
187631
+ if (Array.isArray(value)) {
187632
+ const strings = value.filter((item) => typeof item === "string");
187633
+ return strings[strings.length - 1];
187634
+ }
187635
+ return void 0;
187636
+ }
187610
187637
  function parseCsvList(input) {
187611
187638
  if (!input) return [];
187612
- return input.split(",").map((item) => item.trim()).filter(Boolean);
187639
+ const source = Array.isArray(input) ? input.filter((item) => typeof item === "string").join(",") : input;
187640
+ return source.split(",").map((item) => item.trim()).filter(Boolean);
187613
187641
  }
187614
187642
  function parseOptionalJsonObject(input, field = "value") {
187615
187643
  if (!input) return void 0;
@@ -187629,43 +187657,44 @@ function shortId(id) {
187629
187657
  return id ? `${id.slice(0, 8)}\u2026` : "-";
187630
187658
  }
187631
187659
  function parsePositiveInt(input, fallback) {
187632
- if (input == null || input.trim() === "") return fallback;
187633
- if (!/^\d+$/.test(input.trim())) {
187634
- throw new Error(`Expected a positive integer, received "${input}".`);
187660
+ const value = lastStringArg(input);
187661
+ if (value == null || value.trim() === "") return fallback;
187662
+ if (!/^\d+$/.test(value.trim())) {
187663
+ throw new Error(`Expected a positive integer, received "${value}".`);
187635
187664
  }
187636
- const parsed = Number(input);
187665
+ const parsed = Number(value);
187637
187666
  if (!Number.isSafeInteger(parsed) || parsed <= 0) {
187638
- throw new Error(`Expected a positive integer, received "${input}".`);
187667
+ throw new Error(`Expected a positive integer, received "${value}".`);
187639
187668
  }
187640
187669
  return parsed;
187641
187670
  }
187642
187671
  function coerceObservationType(input) {
187643
- const normalized = input ?? "discovery";
187672
+ const normalized = lastStringArg(input) ?? "discovery";
187644
187673
  if (!OBSERVATION_TYPES.includes(normalized)) {
187645
187674
  throw new Error(
187646
- `Unknown observation type "${input}". Valid types: ${OBSERVATION_TYPES.join(", ")}`
187675
+ `Unknown observation type "${String(input ?? "")}". Valid types: ${OBSERVATION_TYPES.join(", ")}`
187647
187676
  );
187648
187677
  }
187649
187678
  return normalized;
187650
187679
  }
187651
187680
  function coerceObservationStatus(input) {
187652
- const normalized = input ?? "resolved";
187681
+ const normalized = lastStringArg(input) ?? "resolved";
187653
187682
  if (!OBSERVATION_STATUSES.includes(normalized)) {
187654
187683
  throw new Error(
187655
- `Unknown observation status "${input}". Valid statuses: ${OBSERVATION_STATUSES.join(", ")}`
187684
+ `Unknown observation status "${String(input ?? "")}". Valid statuses: ${OBSERVATION_STATUSES.join(", ")}`
187656
187685
  );
187657
187686
  }
187658
187687
  return normalized;
187659
187688
  }
187660
187689
  function coerceRetrievalQuality(input) {
187661
- const normalized = (input ?? "balanced").trim().toLowerCase();
187690
+ const normalized = (lastStringArg(input) ?? "balanced").trim().toLowerCase();
187662
187691
  if (!RETRIEVAL_QUALITIES.includes(normalized)) {
187663
187692
  throw new Error("quality must be fast, balanced, or thorough");
187664
187693
  }
187665
187694
  return normalized;
187666
187695
  }
187667
187696
  function coerceObservationVisibility(input) {
187668
- const normalized = (input ?? "project").trim().toLowerCase();
187697
+ const normalized = (lastStringArg(input) ?? "project").trim().toLowerCase();
187669
187698
  if (normalized === "personal" || normalized === "project" || normalized === "team") {
187670
187699
  return normalized;
187671
187700
  }
@@ -188551,23 +188580,23 @@ __export(memory_exports2, {
188551
188580
  default: () => memory_default
188552
188581
  });
188553
188582
  function getStringArg(named, positional) {
188554
- const value = named?.trim() || positional.join(" ").trim();
188583
+ const value = asStringArg(named) || positional.join(" ").trim();
188555
188584
  return value || void 0;
188556
188585
  }
188557
188586
  function getIdArg(args, positional) {
188558
- return args.ids || args.id || positional.join(",");
188587
+ return lastStringArg(args.ids) || lastStringArg(args.id) || positional.join(",");
188559
188588
  }
188560
188589
  function parseObservationId(value) {
188561
- const normalized = value.trim();
188590
+ const normalized = (asStringArg(value) ?? "").trim();
188562
188591
  if (!/^[1-9]\d*$/.test(normalized)) {
188563
- throw new Error(`Invalid observation ID: ${value}`);
188592
+ throw new Error(`Invalid observation ID: ${String(value ?? "")}`);
188564
188593
  }
188565
188594
  const id = Number(normalized);
188566
- if (!Number.isSafeInteger(id)) throw new Error(`Invalid observation ID: ${value}`);
188595
+ if (!Number.isSafeInteger(id)) throw new Error(`Invalid observation ID: ${String(value ?? "")}`);
188567
188596
  return id;
188568
188597
  }
188569
188598
  function parseObservationIds(value) {
188570
- const values = parseCsvList(value);
188599
+ const values = parseCsvList(typeof value === "string" || Array.isArray(value) ? value : void 0);
188571
188600
  if (values.length === 0) return [];
188572
188601
  return values.map(parseObservationId);
188573
188602
  }
@@ -188595,22 +188624,22 @@ function printMemoryUsage() {
188595
188624
  console.log(' memorix memory long-term supersede --id <old-id> --superseded-by <qualified-id> --reason "replaced"');
188596
188625
  }
188597
188626
  function longTermKind(value) {
188598
- const normalized = (value ?? "semantic").trim().toLowerCase();
188627
+ const normalized = (asStringArg(value) ?? "semantic").toLowerCase();
188599
188628
  if (normalized === "episodic" || normalized === "semantic" || normalized === "procedural") return normalized;
188600
188629
  throw new Error("long-term kind must be episodic, semantic, or procedural.");
188601
188630
  }
188602
188631
  function longTermScope(value) {
188603
- const normalized = (value ?? "project").trim().toLowerCase();
188632
+ const normalized = (asStringArg(value) ?? "project").toLowerCase();
188604
188633
  if (normalized === "project" || normalized === "user" || normalized === "team") return normalized;
188605
188634
  throw new Error("long-term scope must be project, user, or team.");
188606
188635
  }
188607
188636
  function longTermPortability(value) {
188608
- const normalized = (value ?? "project-bound").trim().toLowerCase();
188637
+ const normalized = (asStringArg(value) ?? "project-bound").toLowerCase();
188609
188638
  if (normalized === "project-bound" || normalized === "portable") return normalized;
188610
188639
  throw new Error("long-term portability must be project-bound or portable.");
188611
188640
  }
188612
188641
  function requiredLongTermReason(value) {
188613
- const reason = value?.trim();
188642
+ const reason = asStringArg(value);
188614
188643
  if (!reason) throw new Error("reason is required for this long-term memory transition.");
188615
188644
  return reason;
188616
188645
  }
@@ -188674,7 +188703,7 @@ var init_memory3 = __esm({
188674
188703
  run: async ({ args }) => {
188675
188704
  const action = args._?.[0] || "";
188676
188705
  const positional = (args._ ?? []).slice(1);
188677
- const longTermAction = action === "long-term" ? (positional[0] || args.action || "list").trim().toLowerCase() : void 0;
188706
+ const longTermAction = action === "long-term" ? (positional[0] || asStringArg(args.action) || "list").trim().toLowerCase() : void 0;
188678
188707
  const asJson = !!args.json;
188679
188708
  try {
188680
188709
  const readOnlyActions = /* @__PURE__ */ new Set(["", "search", "graph-context", "recent", "suggest-topic-key", "detail", "timeline"]);
@@ -188707,7 +188736,7 @@ var init_memory3 = __esm({
188707
188736
  query,
188708
188737
  limit: parsePositiveInt(args.graphLimit, 5)
188709
188738
  });
188710
- const format = args.format?.trim().toLowerCase();
188739
+ const format = asStringArg(args.format)?.toLowerCase();
188711
188740
  const formatted = format === "prompt" ? formatGraphContextPrompt(packet) : [
188712
188741
  `Graph context packet for ${project.name}`,
188713
188742
  `- ${packet.summary}`,
@@ -188737,15 +188766,15 @@ var init_memory3 = __esm({
188737
188766
  emitError('text is required for "memorix memory store"', asJson);
188738
188767
  return;
188739
188768
  }
188740
- const title = args.title?.trim() || narrative.slice(0, 80);
188769
+ const title = asStringArg(args.title) || narrative.slice(0, 80);
188741
188770
  const type = coerceObservationType(args.type);
188742
- const topicKey = args.topicKey?.trim() || suggestTopicKey(type, title) || void 0;
188771
+ const topicKey = asStringArg(args.topicKey) || suggestTopicKey(type, title) || void 0;
188743
188772
  const writeScope = resolveCliWriteScope(
188744
188773
  { reader, identity },
188745
188774
  args.visibility
188746
188775
  );
188747
188776
  const result = await storeObservation({
188748
- entityName: args.entity?.trim() || "general",
188777
+ entityName: asStringArg(args.entity) || "general",
188749
188778
  type,
188750
188779
  title,
188751
188780
  narrative,
@@ -188766,7 +188795,7 @@ var init_memory3 = __esm({
188766
188795
  }
188767
188796
  case "suggest-topic-key": {
188768
188797
  const type = coerceObservationType(args.type);
188769
- const title = args.title?.trim();
188798
+ const title = asStringArg(args.title);
188770
188799
  if (!title) {
188771
188800
  emitError('title is required for "memorix memory suggest-topic-key"', asJson);
188772
188801
  return;
@@ -188855,7 +188884,7 @@ var init_memory3 = __esm({
188855
188884
  return;
188856
188885
  }
188857
188886
  case "deduplicate": {
188858
- const query = args.query?.trim();
188887
+ const query = asStringArg(args.query);
188859
188888
  const dryRun = !!args.dryRun || !!args["dry-run"];
188860
188889
  const { isLLMEnabled: isLLMEnabled2 } = await Promise.resolve().then(() => (init_provider2(), provider_exports2));
188861
188890
  if (!isLLMEnabled2()) {
@@ -189036,7 +189065,7 @@ var init_memory3 = __esm({
189036
189065
  ...reader.isTeamMember ? { isTeamMember: true } : {}
189037
189066
  };
189038
189067
  const memoryId = () => {
189039
- const id = args.id?.trim() || args.fromObservation?.trim() || longTermPositional[0]?.trim();
189068
+ const id = asStringArg(args.id) || asStringArg(args.fromObservation) || longTermPositional[0]?.trim();
189040
189069
  if (!id) throw new Error("long-term memory id is required.");
189041
189070
  return id;
189042
189071
  };
@@ -189085,11 +189114,11 @@ var init_memory3 = __esm({
189085
189114
  projectId: project.id,
189086
189115
  scope: scope(),
189087
189116
  kind: kind(),
189088
- title: args.title?.trim() || content.slice(0, 100),
189117
+ title: asStringArg(args.title) || content.slice(0, 100),
189089
189118
  content,
189090
189119
  facts: parseCsvList(args.facts),
189091
189120
  tags: parseCsvList(args.tags),
189092
- applicability: args.applicability?.trim(),
189121
+ applicability: asStringArg(args.applicability),
189093
189122
  portability: portability(),
189094
189123
  reader: longTermReader
189095
189124
  });
@@ -189101,7 +189130,7 @@ var init_memory3 = __esm({
189101
189130
  return;
189102
189131
  }
189103
189132
  case "promote": {
189104
- const rawId = args.fromObservation?.trim() || args.id?.trim() || longTermPositional[0]?.trim();
189133
+ const rawId = asStringArg(args.fromObservation) || asStringArg(args.id) || longTermPositional[0]?.trim();
189105
189134
  const observationId2 = Number.parseInt(rawId || "", 10);
189106
189135
  if (!Number.isFinite(observationId2)) {
189107
189136
  emitError('fromObservation or id must be an observation ID for "memorix memory long-term promote"', asJson);
@@ -189118,7 +189147,7 @@ var init_memory3 = __esm({
189118
189147
  scope: scope(),
189119
189148
  kind: kind(),
189120
189149
  tags: parseCsvList(args.tags),
189121
- applicability: args.applicability?.trim(),
189150
+ applicability: asStringArg(args.applicability),
189122
189151
  reader: longTermReader
189123
189152
  });
189124
189153
  emitResult(
@@ -189147,7 +189176,7 @@ var init_memory3 = __esm({
189147
189176
  return;
189148
189177
  }
189149
189178
  case "supersede": {
189150
- const supersededBy = args.supersededBy?.trim() || args["superseded-by"]?.trim();
189179
+ const supersededBy = asStringArg(args.supersededBy) || asStringArg(args["superseded-by"]);
189151
189180
  if (!supersededBy) {
189152
189181
  emitError('supersededBy is required for "memorix memory long-term supersede"', asJson);
189153
189182
  return;
@@ -190509,9 +190538,116 @@ var init_trae = __esm({
190509
190538
  }
190510
190539
  });
190511
190540
 
190512
- // src/workspace/mcp-adapters/codebuddy.ts
190541
+ // src/workspace/mcp-adapters/dsh.ts
190513
190542
  import { homedir as homedir22 } from "os";
190514
190543
  import { join as join19 } from "path";
190544
+ function resolveDshHome() {
190545
+ const configured = process.env.DSH_HOME?.trim();
190546
+ if (configured) return configured;
190547
+ return join19(homedir22(), ".dsh");
190548
+ }
190549
+ function isMemorixRow(row) {
190550
+ if (!row || typeof row !== "object" || Array.isArray(row)) return false;
190551
+ const record2 = row;
190552
+ if (record2.name !== MCP_CLIENT_PLUGIN) return false;
190553
+ const config2 = record2.config;
190554
+ return Boolean(
190555
+ config2 && typeof config2 === "object" && !Array.isArray(config2) && config2.serverName === "memorix"
190556
+ );
190557
+ }
190558
+ function rowToEntry(row) {
190559
+ const config2 = row.config;
190560
+ if (!config2 || typeof config2 !== "object") return null;
190561
+ const entry = {
190562
+ name: "memorix",
190563
+ command: typeof config2.command === "string" ? config2.command : "",
190564
+ args: Array.isArray(config2.args) ? config2.args.filter((arg) => typeof arg === "string") : []
190565
+ };
190566
+ if (typeof config2.url === "string" && config2.url) entry.url = config2.url;
190567
+ if (config2.env && typeof config2.env === "object" && !Array.isArray(config2.env)) {
190568
+ const env3 = {};
190569
+ for (const [key, value] of Object.entries(config2.env)) {
190570
+ if (typeof value === "string") env3[key] = value;
190571
+ }
190572
+ if (Object.keys(env3).length > 0) entry.env = env3;
190573
+ }
190574
+ if (config2.disabled === true) entry.disabled = true;
190575
+ return entry;
190576
+ }
190577
+ function patchRows(document2) {
190578
+ const rows = [];
190579
+ if (!Array.isArray(document2)) return rows;
190580
+ for (const item of document2) {
190581
+ if (!item || typeof item !== "object" || Array.isArray(item)) continue;
190582
+ const record2 = item;
190583
+ if (Array.isArray(record2.insert)) {
190584
+ for (const row of record2.insert) {
190585
+ if (row && typeof row === "object" && !Array.isArray(row)) {
190586
+ rows.push(row);
190587
+ }
190588
+ }
190589
+ continue;
190590
+ }
190591
+ rows.push(record2);
190592
+ }
190593
+ return rows;
190594
+ }
190595
+ var import_yaml4, MCP_CLIENT_PLUGIN, MEMORIX_ROW_ID, DshMCPAdapter;
190596
+ var init_dsh = __esm({
190597
+ "src/workspace/mcp-adapters/dsh.ts"() {
190598
+ "use strict";
190599
+ init_esm_shims();
190600
+ import_yaml4 = __toESM(require_dist(), 1);
190601
+ MCP_CLIENT_PLUGIN = "@deepseek-ai/dsh-mcp-client";
190602
+ MEMORIX_ROW_ID = "memory-memorix";
190603
+ DshMCPAdapter = class {
190604
+ source = "dsh";
190605
+ parse(content) {
190606
+ if (!content.trim()) return [];
190607
+ let document2;
190608
+ try {
190609
+ document2 = (0, import_yaml4.parse)(content);
190610
+ } catch {
190611
+ return [];
190612
+ }
190613
+ return patchRows(document2).filter(isMemorixRow).map(rowToEntry).filter((entry) => entry !== null);
190614
+ }
190615
+ generate(servers) {
190616
+ const rows = servers.filter((server) => server.name === "memorix").map((server) => {
190617
+ const config2 = {
190618
+ serverName: server.name
190619
+ };
190620
+ if (server.url) {
190621
+ config2.transport = "streamable-http";
190622
+ config2.url = server.url;
190623
+ if (server.headers && Object.keys(server.headers).length > 0) config2.headers = server.headers;
190624
+ } else {
190625
+ config2.transport = "stdio";
190626
+ config2.command = server.command;
190627
+ if (server.args && server.args.length > 0) config2.args = server.args;
190628
+ if (server.env && Object.keys(server.env).length > 0) config2.env = server.env;
190629
+ }
190630
+ const row = {
190631
+ id: MEMORIX_ROW_ID,
190632
+ name: MCP_CLIENT_PLUGIN,
190633
+ config: config2
190634
+ };
190635
+ if (server.disabled === true) row.disabled = true;
190636
+ return row;
190637
+ });
190638
+ if (rows.length === 0) return "";
190639
+ return (0, import_yaml4.stringify)([{ insert: rows }], { lineWidth: 0 }) + "\n";
190640
+ }
190641
+ getConfigPath(_projectRoot) {
190642
+ return join19(resolveDshHome(), "cordis.patch.yml");
190643
+ }
190644
+ };
190645
+ }
190646
+ });
190647
+
190648
+ // src/workspace/mcp-adapters/codebuddy.ts
190649
+ import { homedir as homedir23 } from "os";
190650
+ import { join as join20 } from "path";
190515
190651
  var CodeBuddyMCPAdapter;
190516
190652
  var init_codebuddy = __esm({
190517
190653
  "src/workspace/mcp-adapters/codebuddy.ts"() {
@@ -190543,7 +190679,7 @@ var init_codebuddy = __esm({
190543
190679
  return JSON.stringify({ mcpServers }, null, 2);
190544
190680
  }
190545
190681
  getConfigPath(projectRoot) {
190546
- return projectRoot ? join19(projectRoot, ".mcp.json") : join19(homedir22(), ".codebuddy", ".mcp.json");
190682
+ return projectRoot ? join20(projectRoot, ".mcp.json") : join20(homedir23(), ".codebuddy", ".mcp.json");
190547
190683
  }
190548
190684
  };
190549
190685
  }
@@ -190684,6 +190820,15 @@ var init_registry2 = __esm({
190684
190820
  install: "memorix setup --agent trae",
190685
190821
  surfaces: ["MCP", "rules"]
190686
190822
  },
190823
+ {
190824
+ agent: "dsh",
190825
+ name: "DeepSeek Harness",
190826
+ entry: "official-config",
190827
+ status: "ready",
190828
+ install: "memorix setup --agent dsh",
190829
+ surfaces: ["MCP", "AGENTS.md", "skills"],
190830
+ note: "DeepSeek Harness support writes a @deepseek-ai/dsh-mcp-client row into $DSH_HOME/cordis.patch.yml (default ~/.dsh/cordis.patch.yml), guidance into the harness AGENTS.md, and skills under $DSH_HOME/skills."
190831
+ },
190687
190832
  {
190688
190833
  agent: "memcode",
190689
190834
  name: "memcode",
@@ -190977,9 +191122,9 @@ __export(audit_exports, {
190977
191122
  });
190978
191123
  import * as fs18 from "fs/promises";
190979
191124
  import * as path28 from "path";
190980
- import { homedir as homedir23 } from "os";
191125
+ import { homedir as homedir24 } from "os";
190981
191126
  function getAuditFilePath() {
190982
- return process.env.MEMORIX_AUDIT_FILE || path28.join(homedir23(), ".memorix", "audit.json");
191127
+ return process.env.MEMORIX_AUDIT_FILE || path28.join(homedir24(), ".memorix", "audit.json");
190983
191128
  }
190984
191129
  async function loadAudit() {
190985
191130
  try {
@@ -191292,7 +191437,7 @@ async function installOfficialSkillsForAgent(agent, projectRoot, global2 = false
191292
191437
  const dirs = AGENT_SKILL_DIRS[agent];
191293
191438
  const relativeDir = global2 ? dirs?.global : dirs?.project;
191294
191439
  if (!relativeDir) return [];
191295
- const root = global2 ? os3.homedir() : projectRoot;
191440
+ const root = global2 ? agent === "dsh" ? process.env.DSH_HOME?.trim() || path29.join(os3.homedir(), ".dsh") : os3.homedir() : projectRoot;
191296
191441
  const skillPaths = [];
191297
191442
  for (const skillEntry of OFFICIAL_MEMORIX_SKILLS) {
191298
191443
  const skillPath = path29.join(root, relativeDir, skillEntry.name, "SKILL.md");
@@ -191524,6 +191669,8 @@ function getProjectConfigPath(agent, projectRoot) {
191524
191669
  return path29.join(projectRoot, "AGENTS.md");
191525
191670
  case "trae":
191526
191671
  return path29.join(projectRoot, ".trae", "rules", "project_rules.md");
191672
+ case "dsh":
191673
+ return path29.join(projectRoot, "AGENTS.md");
191527
191674
  case "opencode":
191528
191675
  return path29.join(projectRoot, ".opencode", "plugins", "memorix.js");
191529
191676
  case "pi":
@@ -191569,6 +191716,8 @@ function getGlobalConfigPath(agent) {
191569
191716
  return path29.join(home, ".omp", "agent", "packages", "memorix", "extensions", "memorix.js");
191570
191717
  case "trae":
191571
191718
  return path29.join(home, ".trae", "rules", "project_rules.md");
191719
+ case "dsh":
191720
+ return path29.join(process.env.DSH_HOME?.trim() || path29.join(home, ".dsh"), "AGENTS.md");
191572
191721
  default:
191573
191722
  return path29.join(home, ".memorix", "hooks.json");
191574
191723
  }
@@ -191593,6 +191742,8 @@ function getAgentRulesPath(agent, root, global2 = false) {
191593
191742
  return path29.join(root, ".gemini", "GEMINI.md");
191594
191743
  case "trae":
191595
191744
  return path29.join(root, ".trae", "rules", "project_rules.md");
191745
+ case "dsh":
191746
+ return path29.join(process.env.DSH_HOME?.trim() || path29.join(root, ".dsh"), "AGENTS.md");
191596
191747
  default:
191597
191748
  return path29.join(root, ".agent", "rules", "memorix.md");
191598
191749
  }
@@ -191617,6 +191768,8 @@ function getAgentRulesPath(agent, root, global2 = false) {
191617
191768
  return path29.join(root, "GEMINI.md");
191618
191769
  case "trae":
191619
191770
  return path29.join(root, ".trae", "rules", "project_rules.md");
191771
+ case "dsh":
191772
+ return path29.join(root, "AGENTS.md");
191620
191773
  default:
191621
191774
  return path29.join(root, ".agent", "rules", "memorix.md");
191622
191775
  }
@@ -191699,6 +191852,12 @@ async function detectInstalledAgents() {
191699
191852
  agents.push("trae");
191700
191853
  } catch {
191701
191854
  }
191855
+ const dshDir = process.env.DSH_HOME?.trim() || path29.join(home, ".dsh");
191856
+ try {
191857
+ await fs19.access(dshDir);
191858
+ agents.push("dsh");
191859
+ } catch {
191860
+ }
191702
191861
  return agents;
191703
191862
  }
191704
191863
  async function installHooks(agent, projectRoot, global2 = false) {
@@ -191781,6 +191940,19 @@ async function installHooks(agent, projectRoot, global2 = false) {
191781
191940
  generated: { note: "Trae has no hooks system, only rules (.trae/rules/project_rules.md) installed" }
191782
191941
  };
191783
191942
  }
191943
+ case "dsh": {
191944
+ const rulesPath = await installAgentRules(agent, projectRoot, global2);
191945
+ const skillPaths2 = await installOfficialSkillsForAgent(agent, projectRoot, global2);
191946
+ return {
191947
+ agent,
191948
+ configPath: rulesPath,
191949
+ events: [],
191950
+ generated: {
191951
+ note: "DeepSeek Harness has no hook system \u2014 installed AGENTS.md guidance and skills; the MCP row is installed by `memorix setup --agent dsh`.",
191952
+ ...skillPaths2.length > 0 ? { skillPaths: skillPaths2, skillPath: skillPaths2[0] } : {}
191953
+ }
191954
+ };
191955
+ }
191784
191956
  case "opencode": {
191785
191957
  const pluginContent = generateOpenCodePlugin();
191786
191958
  const pluginPath = global2 ? getGlobalConfigPath(agent) : getProjectConfigPath(agent, projectRoot);
@@ -191915,7 +192087,7 @@ async function installAgentRules(agent, projectRoot, global2 = false) {
191915
192087
  const rulesPath = getAgentRulesPath(agent, rulesRoot, global2);
191916
192088
  try {
191917
192089
  await fs19.mkdir(path29.dirname(rulesPath), { recursive: true });
191918
- if (agent === "claude" || agent === "codex" || agent === "opencode" || agent === "antigravity" || agent === "gemini-cli") {
192090
+ if (agent === "claude" || agent === "codex" || agent === "opencode" || agent === "antigravity" || agent === "gemini-cli" || agent === "dsh") {
191919
192091
  try {
191920
192092
  const existing = await fs19.readFile(rulesPath, "utf-8");
191921
192093
  await fs19.writeFile(rulesPath, mergeMemorixRulesContent(existing, rulesContent), "utf-8");
@@ -192204,7 +192376,10 @@ var init_installers = __esm({
192204
192376
  windsurf: { project: path29.join(".windsurf", "skills"), global: path29.join(".windsurf", "skills") },
192205
192377
  kiro: { project: path29.join(".kiro", "skills"), global: path29.join(".kiro", "skills") },
192206
192378
  opencode: { project: path29.join(".opencode", "skills"), global: path29.join(".config", "opencode", "skills") },
192207
- trae: { project: path29.join(".trae", "skills"), global: path29.join(".trae", "skills") }
192379
+ trae: { project: path29.join(".trae", "skills"), global: path29.join(".trae", "skills") },
192380
+ // DSH's user skill root is <harness home>/skills; the global root below is
192381
+ // resolved to $DSH_HOME (or ~/.dsh) for dsh by installOfficialSkillsForAgent.
192382
+ dsh: { project: path29.join(".dsh", "skills"), global: "skills" }
192208
192383
  };
192209
192384
  PACKAGE_OWNED_HOOK_AGENTS = /* @__PURE__ */ new Set(["openclaw", "hermes", "omp"]);
192210
192385
  }
@@ -192237,7 +192412,7 @@ __export(setup_exports, {
192237
192412
  import { spawnSync } from "child_process";
192238
192413
  import { existsSync as existsSync14 } from "fs";
192239
192414
  import { copyFile as copyFile2, mkdir as mkdir6, readFile as readFile6, readdir as readdir3, rm as rm2, writeFile as writeFile7 } from "fs/promises";
192240
- import { homedir as homedir25 } from "os";
192415
+ import { homedir as homedir26 } from "os";
192241
192416
  import path30 from "path";
192242
192417
  import { fileURLToPath as fileURLToPath7 } from "url";
192243
192418
  function getSetupAgentTargets() {
@@ -192361,7 +192536,7 @@ async function stripHookCaptureFromOpenClawBundle(bundlePath) {
192361
192536
  function mergeHermesPluginEnabled(existingContent, pluginName) {
192362
192537
  let config2 = {};
192363
192538
  try {
192364
- const loaded = existingContent ? (0, import_yaml4.parse)(existingContent) : {};
192539
+ const loaded = existingContent ? (0, import_yaml5.parse)(existingContent) : {};
192365
192540
  config2 = loaded && typeof loaded === "object" && !Array.isArray(loaded) ? loaded : {};
192366
192541
  } catch {
192367
192542
  config2 = {};
@@ -192370,7 +192545,7 @@ function mergeHermesPluginEnabled(existingContent, pluginName) {
192370
192545
  const plugins = pluginsValue && typeof pluginsValue === "object" && !Array.isArray(pluginsValue) ? pluginsValue : {};
192371
192546
  const enabled = Array.isArray(plugins.enabled) ? plugins.enabled.filter((value) => typeof value === "string") : [];
192372
192547
  if (!enabled.includes(pluginName)) enabled.push(pluginName);
192373
- return (0, import_yaml4.stringify)({
192548
+ return (0, import_yaml5.stringify)({
192374
192549
  ...config2,
192375
192550
  plugins: {
192376
192551
  ...plugins,
@@ -192398,7 +192573,8 @@ function getMcpAdapter(agent) {
192398
192573
  omp: new OmpMCPAdapter(),
192399
192574
  kiro: new KiroMCPAdapter(),
192400
192575
  opencode: new OpenCodeMCPAdapter(),
192401
- trae: new TraeMCPAdapter()
192576
+ trae: new TraeMCPAdapter(),
192577
+ dsh: new DshMCPAdapter()
192402
192578
  };
192403
192579
  return adapters[agent];
192404
192580
  }
@@ -192518,7 +192694,7 @@ function isOwnedLegacyCodexMcp(content) {
192518
192694
  const server = new CodexMCPAdapter().parse(content).find((entry) => entry.name === "memorix");
192519
192695
  return Boolean(server && isLegacyCodexMemorixNodeServer(server));
192520
192696
  }
192521
- async function removeLegacyCodexMemorixMcpConfig(configPath = path30.join(homedir25(), ".codex", "config.toml")) {
192697
+ async function removeLegacyCodexMemorixMcpConfig(configPath = path30.join(homedir26(), ".codex", "config.toml")) {
192522
192698
  let existingContent;
192523
192699
  try {
192524
192700
  existingContent = await readFile6(configPath, "utf-8");
@@ -192575,7 +192751,7 @@ async function removeOwnedLegacyCodexPluginFolder(homeDir) {
192575
192751
  }
192576
192752
  }
192577
192753
  async function migrateLegacyCodexIntegration(options = {}) {
192578
- const homeDir = options.homeDir ?? homedir25();
192754
+ const homeDir = options.homeDir ?? homedir26();
192579
192755
  const projectRoot = options.projectRoot ?? process.cwd();
192580
192756
  const configPath = path30.join(homeDir, ".codex", "config.toml");
192581
192757
  let mcp = "missing";
@@ -192606,14 +192782,14 @@ async function migrateLegacyCodexIntegration(options = {}) {
192606
192782
  function mergeYamlMcpConfig(existingContent, generatedContent) {
192607
192783
  let existing = {};
192608
192784
  try {
192609
- const loaded = existingContent ? (0, import_yaml4.parse)(existingContent) : {};
192785
+ const loaded = existingContent ? (0, import_yaml5.parse)(existingContent) : {};
192610
192786
  existing = loaded && typeof loaded === "object" && !Array.isArray(loaded) ? loaded : {};
192611
192787
  } catch {
192612
192788
  existing = {};
192613
192789
  }
192614
192790
  let generated = {};
192615
192791
  try {
192616
- const loaded = (0, import_yaml4.parse)(generatedContent);
192792
+ const loaded = (0, import_yaml5.parse)(generatedContent);
192617
192793
  generated = loaded && typeof loaded === "object" && !Array.isArray(loaded) ? loaded : {};
192618
192794
  } catch {
192619
192795
  return generatedContent.endsWith("\n") ? generatedContent : `${generatedContent}
@@ -192629,7 +192805,46 @@ function mergeYamlMcpConfig(existingContent, generatedContent) {
192629
192805
  ...generatedServers
192630
192806
  }
192631
192807
  };
192632
- return (0, import_yaml4.stringify)(merged, { lineWidth: 0 });
192808
+ return (0, import_yaml5.stringify)(merged, { lineWidth: 0 });
192809
+ }
192810
+ function mergeDshPatchConfig(existingContent, generatedContent) {
192811
+ const generatedTrimmed = generatedContent.trimEnd();
192812
+ if (!existingContent?.trim()) {
192813
+ return generatedTrimmed.endsWith("\n") ? generatedTrimmed : `${generatedTrimmed}
192814
+ `;
192815
+ }
192816
+ const isMemorixInsertRow = (row) => {
192817
+ if (!row || typeof row !== "object" || Array.isArray(row)) return false;
192818
+ const record2 = row;
192819
+ if (record2.name !== "@deepseek-ai/dsh-mcp-client") return false;
192820
+ const config2 = record2.config;
192821
+ return Boolean(
192822
+ config2 && typeof config2 === "object" && !Array.isArray(config2) && config2.serverName === "memorix"
192823
+ );
192824
+ };
192825
+ const opContainsMemorixRow = (op) => {
192826
+ if (!op || typeof op !== "object" || Array.isArray(op)) return false;
192827
+ const insert4 = op.insert;
192828
+ return Array.isArray(insert4) && insert4.some(isMemorixInsertRow);
192829
+ };
192830
+ let existingDocument;
192831
+ try {
192832
+ existingDocument = (0, import_yaml5.parse)(existingContent);
192833
+ } catch {
192834
+ return `${existingContent.trimEnd()}
192835
+
192836
+ ${generatedTrimmed}
192837
+ `;
192838
+ }
192839
+ if (!Array.isArray(existingDocument)) {
192840
+ return `${existingContent.trimEnd()}
192841
+
192842
+ ${generatedTrimmed}
192843
+ `;
192844
+ }
192845
+ const kept = existingDocument.filter((op) => !opContainsMemorixRow(op));
192846
+ const merged = [...kept, ...(0, import_yaml5.parse)(generatedContent)];
192847
+ return (0, import_yaml5.stringify)(merged, { lineWidth: 0 }) + "\n";
192633
192848
  }
192634
192849
  async function installMcpConfig(options) {
192635
192850
  const adapter = getMcpAdapter(options.agent);
@@ -192646,7 +192861,7 @@ async function installMcpConfig(options) {
192646
192861
  existingContent = null;
192647
192862
  }
192648
192863
  const generated = adapter.generate([server]);
192649
- const content = options.agent === "codex" ? mergeTomlMcpConfig(existingContent, generated) : options.agent === "hermes" ? mergeYamlMcpConfig(existingContent, generated) : mergeJsonMcpConfig(existingContent, generated);
192864
+ const content = options.agent === "codex" ? mergeTomlMcpConfig(existingContent, generated) : options.agent === "hermes" ? mergeYamlMcpConfig(existingContent, generated) : options.agent === "dsh" ? mergeDshPatchConfig(existingContent, generated) : mergeJsonMcpConfig(existingContent, generated);
192650
192865
  await mkdir6(path30.dirname(configPath), { recursive: true });
192651
192866
  await writeFile7(configPath, content, "utf-8");
192652
192867
  return { agent: options.agent, configPath, transport: options.mcp };
@@ -192737,7 +192952,7 @@ async function stripCodeBuddyHookCapture(pluginPath) {
192737
192952
  await writeFile7(manifestPath, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
192738
192953
  }
192739
192954
  async function installCodeBuddyPluginPackage(options = {}) {
192740
- const home = options.homeDir ?? homedir25();
192955
+ const home = options.homeDir ?? homedir26();
192741
192956
  const packageRoot = findPackageRoot();
192742
192957
  const source = path30.join(packageRoot, "plugins", "codebuddy", "memorix");
192743
192958
  if (!existsSync14(source)) throw new Error(`CodeBuddy plugin template not found: ${source}`);
@@ -192757,7 +192972,7 @@ async function installCodeBuddyPluginPackage(options = {}) {
192757
192972
  };
192758
192973
  }
192759
192974
  async function installPluginPackage(options) {
192760
- const home = options.homeDir ?? homedir25();
192975
+ const home = options.homeDir ?? homedir26();
192761
192976
  const packageRoot = findPackageRoot();
192762
192977
  const source = path30.join(packageRoot, "plugins", options.agent, "memorix");
192763
192978
  const includeHooks = options.includeHooks ?? true;
@@ -192806,7 +193021,7 @@ async function installPluginPackage(options) {
192806
193021
  };
192807
193022
  }
192808
193023
  async function installGeminiExtensionPackage(options = {}) {
192809
- const home = options.homeDir ?? homedir25();
193024
+ const home = options.homeDir ?? homedir26();
192810
193025
  const packageRoot = findPackageRoot();
192811
193026
  const source = path30.join(packageRoot, "plugins", "gemini", "memorix");
192812
193027
  if (!existsSync14(source)) {
@@ -192826,7 +193041,7 @@ async function installAntigravityPluginPackage(options = {}) {
192826
193041
  if (!existsSync14(source)) {
192827
193042
  throw new Error(`Antigravity plugin template not found: ${source}`);
192828
193043
  }
192829
- const pluginPath = options.global === false ? path30.join(options.projectRoot ?? process.cwd(), ".agents", "plugins", "memorix") : path30.join(options.homeDir ?? homedir25(), ".gemini", "config", "plugins", "memorix");
193044
+ const pluginPath = options.global === false ? path30.join(options.projectRoot ?? process.cwd(), ".agents", "plugins", "memorix") : path30.join(options.homeDir ?? homedir26(), ".gemini", "config", "plugins", "memorix");
192830
193045
  await copyDir(source, pluginPath);
192831
193046
  if (options.includeHooks === false) {
192832
193047
  await rm2(path30.join(pluginPath, "hooks.json"), { force: true });
@@ -192844,7 +193059,7 @@ async function installPiPackage(options = {}) {
192844
193059
  if (!existsSync14(source)) {
192845
193060
  throw new Error(`Pi package template not found: ${source}`);
192846
193061
  }
192847
- const defaultRoot = options.global ? path30.join(options.homeDir ?? homedir25(), ".pi", "agent", "packages") : path30.join(process.cwd(), ".pi", "packages");
193062
+ const defaultRoot = options.global ? path30.join(options.homeDir ?? homedir26(), ".pi", "agent", "packages") : path30.join(process.cwd(), ".pi", "packages");
192848
193063
  const packagePath = options.packageDir ?? path30.join(defaultRoot, "memorix");
192849
193064
  await copyDir(source, packagePath);
192850
193065
  await writeOfficialSkills(path30.join(packagePath, "skills"));
@@ -192856,7 +193071,7 @@ async function installPiPackage(options = {}) {
192856
193071
  };
192857
193072
  }
192858
193073
  async function installOpenClawBundlePackage(options = {}) {
192859
- const home = options.homeDir ?? homedir25();
193074
+ const home = options.homeDir ?? homedir26();
192860
193075
  const packageRoot = findPackageRoot();
192861
193076
  const source = path30.join(packageRoot, "plugins", "openclaw", "memorix");
192862
193077
  if (!existsSync14(source)) {
@@ -192905,7 +193120,7 @@ async function installOmpPackage(options = {}) {
192905
193120
  if (!existsSync14(source)) {
192906
193121
  throw new Error(`Oh-my-Pi package template not found: ${source}`);
192907
193122
  }
192908
- const defaultRoot = options.global ? path30.join(options.homeDir ?? homedir25(), ".omp", "agent", "packages") : path30.join(process.cwd(), ".omp", "packages");
193123
+ const defaultRoot = options.global ? path30.join(options.homeDir ?? homedir26(), ".omp", "agent", "packages") : path30.join(process.cwd(), ".omp", "packages");
192909
193124
  const packagePath = options.packageDir ?? path30.join(defaultRoot, "memorix");
192910
193125
  await copyDir(source, packagePath);
192911
193126
  await writeOfficialSkills(path30.join(packagePath, "skills"));
@@ -193179,7 +193394,7 @@ ${result.stdout || ""}`.toLowerCase();
193179
193394
  }
193180
193395
  async function installAgentSetup(agent, plan, global2) {
193181
193396
  const { installAgentGuidance: installAgentGuidance2, installHooks: installHooks2 } = await Promise.resolve().then(() => (init_installers(), installers_exports));
193182
- const targetRoot = global2 ? homedir25() : process.cwd();
193397
+ const targetRoot = global2 ? homedir26() : process.cwd();
193183
193398
  const hasPluginPackage = plan.actions.includes("plugin-package") && PLUGIN_PACKAGE_AGENTS.has(agent);
193184
193399
  const hasExtensionPackage = plan.actions.includes("extension-package") && agent === "gemini-cli";
193185
193400
  const hasPiPackage = plan.actions.includes("pi-package") && agent === "pi";
@@ -193365,14 +193580,14 @@ function printSetupIntegrationRows() {
193365
193580
  ].join("\n");
193366
193581
  ye2(table, "Memorix integrations");
193367
193582
  }
193368
- var import_yaml4, PLUGIN_PACKAGE_AGENTS, EXTENSION_PACKAGE_AGENTS, PI_PACKAGE_AGENTS, OPENCLAW_BUNDLE_AGENTS, ANTIGRAVITY_PLUGIN_AGENTS, HERMES_PLUGIN_AGENTS, OMP_PACKAGE_AGENTS, CODEBUDDY_PLUGIN_AGENTS, PACKAGE_OWNED_INTEGRATION_AGENTS, SUPPORTED_SETUP_AGENTS, getSetupIntegrationRows2, setup_default;
193583
+ var import_yaml5, PLUGIN_PACKAGE_AGENTS, EXTENSION_PACKAGE_AGENTS, PI_PACKAGE_AGENTS, OPENCLAW_BUNDLE_AGENTS, ANTIGRAVITY_PLUGIN_AGENTS, HERMES_PLUGIN_AGENTS, OMP_PACKAGE_AGENTS, CODEBUDDY_PLUGIN_AGENTS, PACKAGE_OWNED_INTEGRATION_AGENTS, SUPPORTED_SETUP_AGENTS, getSetupIntegrationRows2, setup_default;
193369
193584
  var init_setup = __esm({
193370
193585
  "src/cli/commands/setup.ts"() {
193371
193586
  "use strict";
193372
193587
  init_esm_shims();
193373
193588
  init_dist2();
193374
193589
  init_dist4();
193375
- import_yaml4 = __toESM(require_dist(), 1);
193590
+ import_yaml5 = __toESM(require_dist(), 1);
193376
193591
  init_claude_code();
193377
193592
  init_codex();
193378
193593
  init_cursor();
@@ -193386,6 +193601,7 @@ var init_setup = __esm({
193386
193601
  init_kiro();
193387
193602
  init_opencode();
193388
193603
  init_trae();
193604
+ init_dsh();
193389
193605
  init_codebuddy();
193390
193606
  init_registry2();
193391
193607
  init_official_skills();
@@ -193414,6 +193630,7 @@ var init_setup = __esm({
193414
193630
  "omp",
193415
193631
  "kiro",
193416
193632
  "trae",
193633
+ "dsh",
193417
193634
  "pi"
193418
193635
  ];
193419
193636
  getSetupIntegrationRows2 = getSetupIntegrationRows;
@@ -193425,7 +193642,7 @@ var init_setup = __esm({
193425
193642
  args: {
193426
193643
  agent: {
193427
193644
  type: "string",
193428
- description: "Target agent (claude, codex, codebuddy, opencode, cursor, windsurf, copilot, gemini-cli, antigravity, openclaw, hermes, omp, kiro, trae, pi, all)",
193645
+ description: "Target agent (claude, codex, codebuddy, opencode, cursor, windsurf, copilot, gemini-cli, antigravity, openclaw, hermes, omp, kiro, trae, dsh, pi, all)",
193429
193646
  required: false
193430
193647
  },
193431
193648
  mcp: {
@@ -193497,6 +193714,7 @@ var init_setup = __esm({
193497
193714
  { value: "hermes", label: "Hermes Agent", hint: "plugin + hooks + commands + skills + MCP" },
193498
193715
  { value: "omp", label: "Oh-my-Pi", hint: "package + extension + command + MCP" },
193499
193716
  { value: "pi", label: "Pi coding agent", hint: "package + extension + skill" },
193717
+ { value: "dsh", label: "DeepSeek Harness", hint: "MCP patch + AGENTS.md + skills" },
193500
193718
  { value: "opencode", label: "OpenCode", hint: "local plugin + AGENTS.md + MCP" },
193501
193719
  { value: "windsurf", label: "Windsurf", hint: "rules + hooks + MCP" },
193502
193720
  { value: "all", label: "All supported agents", hint: "install detected-compatible files" }
@@ -193556,7 +193774,7 @@ var config_path_exports = {};
193556
193774
  __export(config_path_exports, {
193557
193775
  default: () => config_path_default
193558
193776
  });
193559
- import { homedir as homedir26 } from "os";
193777
+ import { homedir as homedir27 } from "os";
193560
193778
  var config_path_default;
193561
193779
  var init_config_path = __esm({
193562
193780
  "src/cli/commands/config-path.ts"() {
@@ -193574,7 +193792,7 @@ var init_config_path = __esm({
193574
193792
  run: async () => {
193575
193793
  const project = detectProject(process.cwd());
193576
193794
  ye2([
193577
- `Global: ${getGlobalConfigTomlPath(homedir26())}`,
193795
+ `Global: ${getGlobalConfigTomlPath(homedir27())}`,
193578
193796
  `Project: ${project ? getProjectConfigTomlPath(project.rootPath) : "not inside a git project"}`
193579
193797
  ].join("\n"), "Memorix config");
193580
193798
  }
@@ -193650,7 +193868,7 @@ __export(config_migrate_exports, {
193650
193868
  serializeResolvedConfigToToml: () => serializeResolvedConfigToToml
193651
193869
  });
193652
193870
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
193653
- import { homedir as homedir27 } from "os";
193871
+ import { homedir as homedir28 } from "os";
193654
193872
  import { dirname as dirname4 } from "path";
193655
193873
  function serializeResolvedConfigToToml(config2, options = {}) {
193656
193874
  const includeSecrets = options.includeSecrets === true;
@@ -193743,7 +193961,7 @@ var init_config_migrate = __esm({
193743
193961
  v3.error("Not inside a git project. Use `memorix config migrate --global` for global config.");
193744
193962
  return;
193745
193963
  }
193746
- const target = isGlobal ? getGlobalConfigTomlPath(homedir27()) : getProjectConfigTomlPath(project.rootPath);
193964
+ const target = isGlobal ? getGlobalConfigTomlPath(homedir28()) : getProjectConfigTomlPath(project.rootPath);
193747
193965
  const resolved = getResolvedConfig({ projectRoot: project?.rootPath ?? null });
193748
193966
  const content = serializeResolvedConfigToToml(resolved, { includeSecrets: isGlobal });
193749
193967
  mkdirSync2(dirname4(target), { recursive: true });
@@ -193755,8 +193973,8 @@ var init_config_migrate = __esm({
193755
193973
  });
193756
193974
 
193757
193975
  // src/cli/commands/integrate-shared.ts
193758
- import { homedir as homedir28 } from "os";
193759
- function getIntegrationTargetRoot(useGlobalDefaults, cwd, homeDir = homedir28()) {
193976
+ import { homedir as homedir29 } from "os";
193977
+ function getIntegrationTargetRoot(useGlobalDefaults, cwd, homeDir = homedir29()) {
193760
193978
  return useGlobalDefaults ? homeDir : cwd;
193761
193979
  }
193762
193980
  function getIntegrationScopeLabel(useGlobalDefaults) {
@@ -193793,7 +194011,8 @@ function getAgentLabel(agent) {
193793
194011
  codex: "Codex",
193794
194012
  antigravity: "Antigravity",
193795
194013
  "gemini-cli": "Gemini CLI",
193796
- trae: "Trae"
194014
+ trae: "Trae",
194015
+ dsh: "DeepSeek Harness"
193797
194016
  };
193798
194017
  return labels[agent] || agent;
193799
194018
  }
@@ -193808,7 +194027,8 @@ function getAgentHint(agent) {
193808
194027
  codex: "AGENTS.md",
193809
194028
  antigravity: "plugin + MCP + hooks + skills",
193810
194029
  "gemini-cli": "settings + GEMINI.md",
193811
- trae: "rules"
194030
+ trae: "rules",
194031
+ dsh: "MCP patch + AGENTS.md + skills"
193812
194032
  };
193813
194033
  return hints[agent] || "integration files";
193814
194034
  }
@@ -194801,7 +195021,7 @@ __export(external_provider_exports, {
194801
195021
  });
194802
195022
  import { spawn as spawn5 } from "child_process";
194803
195023
  import { existsSync as existsSync16, readFileSync as readFileSync9 } from "fs";
194804
- import { delimiter, dirname as dirname5, extname, isAbsolute as isAbsolute2, join as join22, relative as relative2, resolve as resolve3, sep as sep2 } from "path";
195024
+ import { delimiter, dirname as dirname5, extname, isAbsolute as isAbsolute2, join as join23, relative as relative2, resolve as resolve3, sep as sep2 } from "path";
194805
195025
  function boundedTimeout(value) {
194806
195026
  if (!Number.isFinite(value)) return DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS;
194807
195027
  return Math.max(100, Math.min(Math.floor(value), MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS));
@@ -194830,10 +195050,10 @@ function resolveCommandCandidates(command) {
194830
195050
  }
194831
195051
  const names = extname(requested) ? [requested] : process.platform === "win32" ? [requested + ".exe", requested + ".cmd", requested + ".js", requested] : [requested];
194832
195052
  const directories = [
194833
- ...process.platform === "win32" && process.env.LOCALAPPDATA ? [join22(process.env.LOCALAPPDATA, "codegraph", "current", "bin")] : [],
195053
+ ...process.platform === "win32" && process.env.LOCALAPPDATA ? [join23(process.env.LOCALAPPDATA, "codegraph", "current", "bin")] : [],
194834
195054
  ...(process.env.PATH ?? "").split(delimiter).filter(Boolean)
194835
195055
  ];
194836
- return [...new Set(directories.flatMap((directory) => names.map((name) => join22(directory, name))))];
195056
+ return [...new Set(directories.flatMap((directory) => names.map((name) => join23(directory, name))))];
194837
195057
  }
194838
195058
  function resolveLaunch(command) {
194839
195059
  for (const candidate2 of resolveCommandCandidates(command)) {
@@ -194841,8 +195061,8 @@ function resolveLaunch(command) {
194841
195061
  const extension3 = extname(candidate2).toLowerCase();
194842
195062
  if (extension3 === ".cmd") {
194843
195063
  const bundleRoot = resolve3(dirname5(candidate2), "..");
194844
- const node = join22(bundleRoot, "node.exe");
194845
- const entry = join22(bundleRoot, "lib", "dist", "bin", "codegraph.js");
195064
+ const node = join23(bundleRoot, "node.exe");
195065
+ const entry = join23(bundleRoot, "lib", "dist", "bin", "codegraph.js");
194846
195066
  if (existsSync16(node) && existsSync16(entry)) {
194847
195067
  return { executable: node, prefixArgs: ["--liftoff-only", entry] };
194848
195068
  }
@@ -194973,7 +195193,7 @@ async function inspectExternalCodeGraph(input) {
194973
195193
  const health2 = { state: "disabled", reason: "External CodeGraph is disabled by configuration." };
194974
195194
  return { health: health2, quality: providerQuality({ mode, health: health2 }) };
194975
195195
  }
194976
- if (!existsSync16(join22(input.projectRoot, ".codegraph"))) {
195196
+ if (!existsSync16(join23(input.projectRoot, ".codegraph"))) {
194977
195197
  const health2 = { state: "not-detected", reason: "No local .codegraph index is present for this project." };
194978
195198
  return { health: health2, quality: providerQuality({ mode, health: health2 }) };
194979
195199
  }
@@ -196908,9 +197128,9 @@ function existingLensCandidates(rootPath, lens) {
196908
197128
  const absolute = path33.join(rootPath, candidate2);
196909
197129
  try {
196910
197130
  if (!existsSync17(absolute)) continue;
196911
- const stat4 = statSync5(absolute);
196912
- if (stat4.isFile()) out.push(candidate2);
196913
- if (stat4.isDirectory()) out.push(candidate2.replace(/\\/g, "/"));
197131
+ const stat5 = statSync5(absolute);
197132
+ if (stat5.isFile()) out.push(candidate2);
197133
+ if (stat5.isDirectory()) out.push(candidate2.replace(/\\/g, "/"));
196914
197134
  } catch {
196915
197135
  }
196916
197136
  }
@@ -200200,8 +200420,8 @@ __export(engine_exports2, {
200200
200420
  SkillsEngine: () => SkillsEngine
200201
200421
  });
200202
200422
  import { existsSync as existsSync18, readFileSync as readFileSync10, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, readdirSync as readdirSync3 } from "fs";
200203
- import { join as join23 } from "path";
200204
- import { homedir as homedir29 } from "os";
200423
+ import { join as join24 } from "path";
200424
+ import { homedir as homedir30 } from "os";
200205
200425
  var SKILLS_DIRS, SKILL_WORTHY_TYPES, MIN_OBS_FOR_SKILL, MIN_SCORE_FOR_SKILL, LOW_SIGNAL_TITLE_PATTERNS, LOW_SIGNAL_ENTITY_PATTERNS, COMMAND_TRACE_PATTERNS2, SkillsEngine;
200206
200426
  var init_engine4 = __esm({
200207
200427
  "src/skills/engine.ts"() {
@@ -200272,12 +200492,12 @@ var init_engine4 = __esm({
200272
200492
  listSkills() {
200273
200493
  const skills = [];
200274
200494
  const seen = /* @__PURE__ */ new Set();
200275
- const home = homedir29();
200495
+ const home = homedir30();
200276
200496
  for (const [agent, dirs] of Object.entries(SKILLS_DIRS)) {
200277
200497
  for (const dir of dirs) {
200278
- const paths = [join23(this.projectRoot, dir)];
200498
+ const paths = [join24(this.projectRoot, dir)];
200279
200499
  if (!this.skipGlobal) {
200280
- paths.push(join23(home, dir));
200500
+ paths.push(join24(home, dir));
200281
200501
  }
200282
200502
  for (const skillsRoot of paths) {
200283
200503
  if (!existsSync18(skillsRoot)) continue;
@@ -200287,7 +200507,7 @@ var init_engine4 = __esm({
200287
200507
  if (!entry.isDirectory()) continue;
200288
200508
  const name = entry.name;
200289
200509
  if (seen.has(name)) continue;
200290
- const skillMd = join23(skillsRoot, name, "SKILL.md");
200510
+ const skillMd = join24(skillsRoot, name, "SKILL.md");
200291
200511
  if (!existsSync18(skillMd)) continue;
200292
200512
  try {
200293
200513
  const content = readFileSync10(skillMd, "utf-8");
@@ -200295,7 +200515,7 @@ var init_engine4 = __esm({
200295
200515
  skills.push({
200296
200516
  name,
200297
200517
  description,
200298
- sourcePath: join23(skillsRoot, name),
200518
+ sourcePath: join24(skillsRoot, name),
200299
200519
  sourceAgent: agent,
200300
200520
  content,
200301
200521
  generated: false
@@ -200338,11 +200558,11 @@ var init_engine4 = __esm({
200338
200558
  writeSkill(skill2, target) {
200339
200559
  const dirs = SKILLS_DIRS[target];
200340
200560
  if (!dirs || dirs.length === 0) return null;
200341
- const targetDir = join23(this.projectRoot, dirs[0], skill2.name);
200561
+ const targetDir = join24(this.projectRoot, dirs[0], skill2.name);
200342
200562
  try {
200343
200563
  mkdirSync3(targetDir, { recursive: true });
200344
- writeFileSync3(join23(targetDir, "SKILL.md"), skill2.content, "utf-8");
200345
- return join23(dirs[0], skill2.name, "SKILL.md");
200564
+ writeFileSync3(join24(targetDir, "SKILL.md"), skill2.content, "utf-8");
200565
+ return join24(dirs[0], skill2.name, "SKILL.md");
200346
200566
  } catch {
200347
200567
  return null;
200348
200568
  }
@@ -201511,7 +201731,7 @@ var init_task_graph = __esm({
201511
201731
  // src/orchestrate/context-collector.ts
201512
201732
  import { execFileSync as execFileSync2 } from "child_process";
201513
201733
  import { readFileSync as readFileSync11, existsSync as existsSync19 } from "fs";
201514
- import { join as join24 } from "path";
201734
+ import { join as join25 } from "path";
201515
201735
  function normalizeEntryLimit(value, fallback) {
201516
201736
  if (!Number.isSafeInteger(value) || value < 1) return fallback;
201517
201737
  return Math.min(value, 500);
@@ -201586,7 +201806,7 @@ function collectFileTree(projectDir2, maxEntries) {
201586
201806
  }
201587
201807
  function collectDependencies(projectDir2) {
201588
201808
  try {
201589
- const pkgPath = join24(projectDir2, "package.json");
201809
+ const pkgPath = join25(projectDir2, "package.json");
201590
201810
  if (!existsSync19(pkgPath)) return "";
201591
201811
  const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
201592
201812
  const parts = [];
@@ -215641,8 +215861,8 @@ var init_syncer = __esm({
215641
215861
  const dir = path37.dirname(pattern);
215642
215862
  const fileGlob = path37.basename(pattern);
215643
215863
  try {
215644
- const stat4 = await fs22.stat(dir);
215645
- if (!stat4.isDirectory()) {
215864
+ const stat5 = await fs22.stat(dir);
215865
+ if (!stat5.isDirectory()) {
215646
215866
  try {
215647
215867
  await fs22.access(pattern);
215648
215868
  return [pattern];
@@ -215826,8 +216046,8 @@ __export(engine_exports3, {
215826
216046
  WorkspaceSyncEngine: () => WorkspaceSyncEngine
215827
216047
  });
215828
216048
  import { readFileSync as readFileSync13, readdirSync as readdirSync4, existsSync as existsSync22, cpSync, mkdirSync as mkdirSync5 } from "fs";
215829
- import { join as join26 } from "path";
215830
- import { homedir as homedir30 } from "os";
216049
+ import { join as join27 } from "path";
216050
+ import { homedir as homedir31 } from "os";
215831
216051
  var WorkspaceSyncEngine;
215832
216052
  var init_engine5 = __esm({
215833
216053
  "src/workspace/engine.ts"() {
@@ -215899,9 +216119,9 @@ var init_engine5 = __esm({
215899
216119
  const globalPath = adapter.getConfigPath();
215900
216120
  const pathsToCheck = [configPath, globalPath];
215901
216121
  if (target === "antigravity") {
215902
- pathsToCheck.push(join26(this.projectRoot, ".gemini", "settings.json"));
215903
- pathsToCheck.push(join26(homedir30(), ".gemini", "settings.json"));
215904
- pathsToCheck.push(join26(homedir30(), ".gemini", "antigravity", "mcp_config.json"));
216122
+ pathsToCheck.push(join27(this.projectRoot, ".gemini", "settings.json"));
216123
+ pathsToCheck.push(join27(homedir31(), ".gemini", "settings.json"));
216124
+ pathsToCheck.push(join27(homedir31(), ".gemini", "antigravity", "mcp_config.json"));
215905
216125
  }
215906
216126
  const merged = /* @__PURE__ */ new Map();
215907
216127
  for (const path47 of pathsToCheck) {
@@ -216018,7 +216238,7 @@ var init_engine5 = __esm({
216018
216238
  getTargetSkillsDir(target) {
216019
216239
  const dirs = _WorkspaceSyncEngine.SKILLS_DIRS[target];
216020
216240
  if (!dirs || dirs.length === 0) return null;
216021
- return join26(this.projectRoot, dirs[0]);
216241
+ return join27(this.projectRoot, dirs[0]);
216022
216242
  }
216023
216243
  /**
216024
216244
  * Scan all agent skills directories and collect unique skills.
@@ -216027,12 +216247,12 @@ var init_engine5 = __esm({
216027
216247
  const skills = [];
216028
216248
  const conflicts = [];
216029
216249
  const seen = /* @__PURE__ */ new Map();
216030
- const home = homedir30();
216250
+ const home = homedir31();
216031
216251
  for (const [agent, dirs] of Object.entries(_WorkspaceSyncEngine.SKILLS_DIRS)) {
216032
216252
  for (const dir of dirs) {
216033
216253
  const paths = [
216034
- join26(this.projectRoot, dir),
216035
- join26(home, dir)
216254
+ join27(this.projectRoot, dir),
216255
+ join27(home, dir)
216036
216256
  ];
216037
216257
  for (const skillsRoot of paths) {
216038
216258
  if (!existsSync22(skillsRoot)) continue;
@@ -216040,7 +216260,7 @@ var init_engine5 = __esm({
216040
216260
  const entries = readdirSync4(skillsRoot, { withFileTypes: true });
216041
216261
  for (const entry of entries) {
216042
216262
  if (!entry.isDirectory()) continue;
216043
- const skillMd = join26(skillsRoot, entry.name, "SKILL.md");
216263
+ const skillMd = join27(skillsRoot, entry.name, "SKILL.md");
216044
216264
  if (!existsSync22(skillMd)) continue;
216045
216265
  let description = "";
216046
216266
  try {
@@ -216052,7 +216272,7 @@ var init_engine5 = __esm({
216052
216272
  const newEntry = {
216053
216273
  name: entry.name,
216054
216274
  description,
216055
- sourcePath: join26(skillsRoot, entry.name),
216275
+ sourcePath: join27(skillsRoot, entry.name),
216056
216276
  sourceAgent: agent
216057
216277
  };
216058
216278
  const existing = seen.get(entry.name);
@@ -216089,7 +216309,7 @@ var init_engine5 = __esm({
216089
216309
  }
216090
216310
  for (const skill2 of skills) {
216091
216311
  if (skill2.sourceAgent === target) continue;
216092
- const dest = join26(targetDir, skill2.name);
216312
+ const dest = join27(targetDir, skill2.name);
216093
216313
  if (existsSync22(dest)) {
216094
216314
  skipped.push(`${skill2.name} (already exists in ${target})`);
216095
216315
  continue;
@@ -216105,13 +216325,13 @@ var init_engine5 = __esm({
216105
216325
  }
216106
216326
  scanWorkflows() {
216107
216327
  const workflows = [];
216108
- const wfDir = join26(this.projectRoot, ".windsurf", "workflows");
216328
+ const wfDir = join27(this.projectRoot, ".windsurf", "workflows");
216109
216329
  if (!existsSync22(wfDir)) return workflows;
216110
216330
  try {
216111
216331
  const files = readdirSync4(wfDir).filter((f7) => f7.endsWith(".md"));
216112
216332
  for (const file2 of files) {
216113
216333
  try {
216114
- const content = readFileSync13(join26(wfDir, file2), "utf-8");
216334
+ const content = readFileSync13(join27(wfDir, file2), "utf-8");
216115
216335
  workflows.push(this.workflowSyncer.parseWindsurfWorkflow(file2, content));
216116
216336
  } catch {
216117
216337
  }
@@ -216319,7 +216539,7 @@ __export(behavior_exports, {
216319
216539
  resetBehaviorConfigCache: () => resetBehaviorConfigCache
216320
216540
  });
216321
216541
  import { existsSync as existsSync23, readFileSync as readFileSync14 } from "fs";
216322
- import { homedir as homedir31 } from "os";
216542
+ import { homedir as homedir32 } from "os";
216323
216543
  function isSessionInject(value) {
216324
216544
  return value === "full" || value === "minimal" || value === "silent";
216325
216545
  }
@@ -216337,7 +216557,7 @@ function legacyBehavior(homeDir) {
216337
216557
  }
216338
216558
  }
216339
216559
  function getBehaviorConfig(options = {}) {
216340
- const homeDir = options.homeDir ?? homedir31();
216560
+ const homeDir = options.homeDir ?? homedir32();
216341
216561
  const projectRoot = options.projectRoot === void 0 ? detectProject()?.rootPath ?? null : options.projectRoot;
216342
216562
  const cacheKey2 = `${homeDir}\0${projectRoot ?? ""}`;
216343
216563
  const cached2 = cache4.get(cacheKey2);
@@ -217306,7 +217526,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
217306
217526
  case "/config": {
217307
217527
  const os6 = await import("os");
217308
217528
  const { existsSync: existsSync33 } = await import("fs");
217309
- const { join: join33 } = await import("path");
217529
+ const { join: join34 } = await import("path");
217310
217530
  let yml = {};
217311
217531
  const configProjectRoot = effectiveProjectRoot;
217312
217532
  try {
@@ -217331,11 +217551,11 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
217331
217551
  try {
217332
217552
  const home = os6.homedir();
217333
217553
  const paths = {
217334
- "project memorix.yml": configProjectRoot ? join33(configProjectRoot, "memorix.yml") : null,
217335
- "user memorix.yml": join33(home, ".memorix", "memorix.yml"),
217336
- "project .env": configProjectRoot ? join33(configProjectRoot, ".env") : null,
217337
- "user .env": join33(home, ".memorix", ".env"),
217338
- "legacy config.json": join33(home, ".memorix", "config.json")
217554
+ "project memorix.yml": configProjectRoot ? join34(configProjectRoot, "memorix.yml") : null,
217555
+ "user memorix.yml": join34(home, ".memorix", "memorix.yml"),
217556
+ "project .env": configProjectRoot ? join34(configProjectRoot, ".env") : null,
217557
+ "user .env": join34(home, ".memorix", ".env"),
217558
+ "legacy config.json": join34(home, ".memorix", "config.json")
217339
217559
  };
217340
217560
  for (const [key, fpath] of Object.entries(paths)) {
217341
217561
  if (fpath === null) {
@@ -257832,11 +258052,11 @@ import path40 from "path";
257832
258052
  function resolveGitDir(projectRoot) {
257833
258053
  const dotGit = path40.join(projectRoot, ".git");
257834
258054
  if (!existsSync24(dotGit)) return null;
257835
- const stat4 = statSync6(dotGit);
257836
- if (stat4.isDirectory()) {
258055
+ const stat5 = statSync6(dotGit);
258056
+ if (stat5.isDirectory()) {
257837
258057
  return dotGit;
257838
258058
  }
257839
- if (stat4.isFile()) {
258059
+ if (stat5.isFile()) {
257840
258060
  try {
257841
258061
  const content = readFileSync15(dotGit, "utf-8").trim();
257842
258062
  const match2 = content.match(/^gitdir:\s*(.+)$/);
@@ -258239,7 +258459,7 @@ The path should point to a directory containing a .git folder.`
258239
258459
  };
258240
258460
  const server = existingServer ?? new McpServer({
258241
258461
  name: "memorix",
258242
- version: true ? "1.4.3" : "1.0.1"
258462
+ version: true ? "1.4.5" : "1.0.1"
258243
258463
  });
258244
258464
  const originalRegisterTool = server.registerTool.bind(server);
258245
258465
  server.registerTool = ((name, ...args) => {
@@ -260241,10 +260461,10 @@ ${Math.max(0, managedIds.size - result.resolved.length)} visible writable observ
260241
260461
  );
260242
260462
  let enableKG = isToolInProfile("create_entities", toolProfile);
260243
260463
  try {
260244
- const { homedir: homedir35 } = await import("os");
260245
- const { join: join33 } = await import("path");
260246
- const { readFile: readFile9 } = await import("fs/promises");
260247
- const raw = await readFile9(join33(homedir35(), ".memorix", "settings.json"), "utf-8");
260464
+ const { homedir: homedir36 } = await import("os");
260465
+ const { join: join34 } = await import("path");
260466
+ const { readFile: readFile10 } = await import("fs/promises");
260467
+ const raw = await readFile10(join34(homedir36(), ".memorix", "settings.json"), "utf-8");
260248
260468
  const s4 = JSON.parse(raw);
260249
260469
  if (s4.knowledgeGraph === true) enableKG = true;
260250
260470
  } catch {
@@ -261922,6 +262142,16 @@ ${lines.join("\n")}` }] };
261922
262142
  return { content: [{ type: "text", text: lines.filter(Boolean).join("\n") }] };
261923
262143
  }
261924
262144
  );
262145
+ function matchesImagePrefix2(bytes, prefix) {
262146
+ return prefix.every((byte, index) => bytes[index] === byte);
262147
+ }
262148
+ function detectReferenceImageMimeType2(bytes) {
262149
+ if (bytes.length >= 8 && matchesImagePrefix2(bytes, [137, 80, 78, 71, 13, 10, 26, 10])) return "image/png";
262150
+ if (bytes.length >= 3 && matchesImagePrefix2(bytes, [255, 216, 255])) return "image/jpeg";
262151
+ if (bytes.length >= 6 && (Buffer.from(bytes.subarray(0, 6)).toString("ascii") === "GIF87a" || Buffer.from(bytes.subarray(0, 6)).toString("ascii") === "GIF89a")) return "image/gif";
262152
+ if (bytes.length >= 12 && Buffer.from(bytes.subarray(0, 4)).toString("ascii") === "RIFF" && Buffer.from(bytes.subarray(8, 12)).toString("ascii") === "WEBP") return "image/webp";
262153
+ return void 0;
262154
+ }
261925
262155
  server.registerTool(
261926
262156
  "memorix_media",
261927
262157
  {
@@ -261937,6 +262167,7 @@ ${lines.join("\n")}` }] };
261937
262167
  title: external_exports2.string().optional().describe("Observation title when attaching generated/imported output."),
261938
262168
  narrative: external_exports2.string().optional().describe("Short retrieval text when attaching an asset."),
261939
262169
  prompt: external_exports2.string().optional().describe("Explicit MiniMax generation prompt."),
262170
+ image: external_exports2.string().optional().describe("Base64-encoded reference image for image-to-image generation."),
261940
262171
  model: external_exports2.string().max(160).optional().describe("Provider model for the selected media action."),
261941
262172
  provider: external_exports2.enum(["openai", "groq"]).optional().describe("Explicit audio transcription provider."),
261942
262173
  language: external_exports2.string().max(32).optional().describe("Optional ISO-639-1 hint for audio transcription."),
@@ -261951,7 +262182,7 @@ ${lines.join("\n")}` }] };
261951
262182
  attach: external_exports2.boolean().optional().describe("Attach generated/imported output to normal project memory explicitly.")
261952
262183
  }
261953
262184
  },
261954
- async ({ action, path: assetPath, assetId, jobId, kind, limit: limit2, title, narrative, prompt: prompt2, model, provider: provider2, language, region, n: n3, ratio, width, height, duration: duration3, maxPages, maxChars, attach }) => {
262185
+ async ({ action, path: assetPath, assetId, jobId, kind, limit: limit2, title, narrative, prompt: prompt2, image, model, provider: provider2, language, region, n: n3, ratio, width, height, duration: duration3, maxPages, maxChars, attach }) => {
261955
262186
  const unresolved = requireResolvedProject("manage controlled media");
261956
262187
  if (unresolved) return unresolved;
261957
262188
  const safeError4 = (error40) => sanitizeCredentials(
@@ -262080,6 +262311,14 @@ ${lines.join("\n")}` }] };
262080
262311
  if (model && !imageModel) throw new Error("generate-image accepts image-01 or image-01-live");
262081
262312
  const imageRatio = ratio === "1:1" || ratio === "16:9" || ratio === "4:3" || ratio === "3:2" || ratio === "2:3" || ratio === "3:4" || ratio === "9:16" || ratio === "21:9" ? ratio : void 0;
262082
262313
  if (ratio && !imageRatio) throw new Error("generate-image received an unsupported aspect ratio");
262314
+ let subjectImages;
262315
+ if (image?.trim()) {
262316
+ const { decodeBase64ImagePayload: decodeBase64ImagePayload2 } = await Promise.resolve().then(() => (init_image_payload(), image_payload_exports));
262317
+ const bytes = decodeBase64ImagePayload2(image);
262318
+ const mimeType = detectReferenceImageMimeType2(bytes);
262319
+ if (!mimeType) throw new Error("Reference image must be a PNG, JPEG, GIF, or WebP image");
262320
+ subjectImages = [{ data: bytes.toString("base64"), mimeType }];
262321
+ }
262083
262322
  const { generateMiniMaxImages: generateMiniMaxImages2 } = await Promise.resolve().then(() => (init_minimax2(), minimax_exports2));
262084
262323
  const generated = await generateMiniMaxImages2({
262085
262324
  dataDir: projectDir2,
@@ -262090,7 +262329,8 @@ ${lines.join("\n")}` }] };
262090
262329
  n: n3,
262091
262330
  aspectRatio: imageRatio,
262092
262331
  width,
262093
- height
262332
+ height,
262333
+ subjectImages
262094
262334
  });
262095
262335
  const observations2 = attach === true ? await Promise.all(generated.assets.map(({ asset }) => attachAsset(
262096
262336
  asset,
@@ -262527,8 +262767,8 @@ __export(update_checker_exports, {
262527
262767
  });
262528
262768
  import { execFile as execFile3 } from "child_process";
262529
262769
  import { readFile as readFile7, writeFile as writeFile8, mkdir as mkdir7 } from "fs/promises";
262530
- import { join as join27 } from "path";
262531
- import { homedir as homedir32 } from "os";
262770
+ import { join as join28 } from "path";
262771
+ import { homedir as homedir33 } from "os";
262532
262772
  function getCurrentVersion() {
262533
262773
  try {
262534
262774
  return getCliVersion();
@@ -262707,8 +262947,8 @@ var init_update_checker = __esm({
262707
262947
  MIN_AUTO_UPDATE_TIMEOUT_MS = 5e3;
262708
262948
  MAX_AUTO_UPDATE_TIMEOUT_MS = 30 * 60 * 1e3;
262709
262949
  REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
262710
- CACHE_DIR2 = join27(homedir32(), ".memorix");
262711
- CACHE_FILE2 = join27(CACHE_DIR2, "update-check.json");
262950
+ CACHE_DIR2 = join28(homedir33(), ".memorix");
262951
+ CACHE_FILE2 = join28(CACHE_DIR2, "update-check.json");
262712
262952
  _testing = {
262713
262953
  CACHE_FILE: CACHE_FILE2,
262714
262954
  CHECK_INTERVAL_MS,
@@ -262764,7 +263004,7 @@ var init_serve = __esm({
262764
263004
  const { StdioServerTransport: StdioServerTransport2 } = await Promise.resolve().then(() => (init_stdio2(), stdio_exports));
262765
263005
  const { createMemorixServer: createMemorixServer2 } = await Promise.resolve().then(() => (init_server4(), server_exports2));
262766
263006
  const { detectProject: detectProject2, findGitInSubdirs: findGitInSubdirs2, isSystemDirectory: isSystemDirectory2 } = await Promise.resolve().then(() => (init_detector(), detector_exports));
262767
- const { homedir: homedir35 } = await import("os");
263007
+ const { homedir: homedir36 } = await import("os");
262768
263008
  const { resolveServeProject: resolveServeProject2 } = await Promise.resolve().then(() => (init_serve_shared(), serve_shared_exports));
262769
263009
  process.stdin.on("end", () => {
262770
263010
  console.error("[memorix] stdin closed \u2014 exiting");
@@ -262774,7 +263014,7 @@ var init_serve = __esm({
262774
263014
  try {
262775
263015
  safeCwd = process.cwd();
262776
263016
  } catch {
262777
- safeCwd = homedir35();
263017
+ safeCwd = homedir36();
262778
263018
  }
262779
263019
  const resolution = resolveServeProject2(
262780
263020
  {
@@ -262782,7 +263022,7 @@ var init_serve = __esm({
262782
263022
  envProjectRoot: process.env.MEMORIX_PROJECT_ROOT,
262783
263023
  initCwd: process.env.INIT_CWD,
262784
263024
  processCwd: safeCwd,
262785
- homeDir: homedir35()
263025
+ homeDir: homedir36()
262786
263026
  },
262787
263027
  { detectProject: detectProject2, findGitInSubdirs: findGitInSubdirs2, isSystemDirectory: isSystemDirectory2 }
262788
263028
  );
@@ -265073,7 +265313,7 @@ var init_serve_http = __esm({
265073
265313
  const { createProjectBindingController: createProjectBindingController2 } = await Promise.resolve().then(() => (init_request_context(), request_context_exports));
265074
265314
  const { findGitInSubdirs: findGitInSubdirs2 } = await Promise.resolve().then(() => (init_detector(), detector_exports));
265075
265315
  const { writeFileSync: writeFileSync11, mkdirSync: mkdirSync11 } = await import("fs");
265076
- const { homedir: homedir35 } = await import("os");
265316
+ const { homedir: homedir36 } = await import("os");
265077
265317
  const port = parseTcpPortOrReport(args.port, 3211);
265078
265318
  if (port === void 0) {
265079
265319
  process.exitCode = 1;
@@ -265085,7 +265325,7 @@ var init_serve_http = __esm({
265085
265325
  try {
265086
265326
  safeCwd = process.cwd();
265087
265327
  } catch {
265088
- safeCwd = homedir35();
265328
+ safeCwd = homedir36();
265089
265329
  }
265090
265330
  let projectRoot = args.cwd || process.env.MEMORIX_PROJECT_ROOT || safeCwd;
265091
265331
  console.error(`[memorix] HTTP transport starting on ${host}:${port}`);
@@ -265795,7 +266035,7 @@ var init_serve_http = __esm({
265795
266035
  const { projectId: configProjectId } = await resolveRequestProject(url2);
265796
266036
  const os6 = await import("os");
265797
266037
  const { existsSync: existsSync33 } = await import("fs");
265798
- const { join: join33 } = await import("path");
266038
+ const { join: join34 } = await import("path");
265799
266039
  const { loadYamlConfig: loadYamlConfig2 } = await Promise.resolve().then(() => (init_yaml_loader(), yaml_loader_exports));
265800
266040
  const { loadFileConfig: loadFileConfig2, loadDotenv: loadDotenv2, getLoadedEnvFiles: getLoadedEnvFiles2 } = await Promise.resolve().then(() => (init_config(), config_exports));
265801
266041
  const isStartupProject = configProjectId === defaultProject.id;
@@ -265809,11 +266049,11 @@ var init_serve_http = __esm({
265809
266049
  const home = os6.homedir();
265810
266050
  if (effectiveRoot) {
265811
266051
  const paths = {
265812
- "project memorix.yml": join33(effectiveRoot, "memorix.yml"),
265813
- "user memorix.yml": join33(home, ".memorix", "memorix.yml"),
265814
- "project .env": join33(effectiveRoot, ".env"),
265815
- "user .env": join33(home, ".memorix", ".env"),
265816
- "legacy config.json": join33(home, ".memorix", "config.json")
266052
+ "project memorix.yml": join34(effectiveRoot, "memorix.yml"),
266053
+ "user memorix.yml": join34(home, ".memorix", "memorix.yml"),
266054
+ "project .env": join34(effectiveRoot, ".env"),
266055
+ "user .env": join34(home, ".memorix", ".env"),
266056
+ "legacy config.json": join34(home, ".memorix", "config.json")
265817
266057
  };
265818
266058
  for (const [key, fpath] of Object.entries(paths)) {
265819
266059
  files[key] = { exists: existsSync33(fpath), path: fpath };
@@ -265822,9 +266062,9 @@ var init_serve_http = __esm({
265822
266062
  files["project memorix.yml"] = { exists: false, path: "unavailable", unavailable: true };
265823
266063
  files["project .env"] = { exists: false, path: "unavailable", unavailable: true };
265824
266064
  const userPaths = {
265825
- "user memorix.yml": join33(home, ".memorix", "memorix.yml"),
265826
- "user .env": join33(home, ".memorix", ".env"),
265827
- "legacy config.json": join33(home, ".memorix", "config.json")
266065
+ "user memorix.yml": join34(home, ".memorix", "memorix.yml"),
266066
+ "user .env": join34(home, ".memorix", ".env"),
266067
+ "legacy config.json": join34(home, ".memorix", "config.json")
265828
266068
  };
265829
266069
  for (const [key, fpath] of Object.entries(userPaths)) {
265830
266070
  files[key] = { exists: existsSync33(fpath), path: fpath };
@@ -268501,6 +268741,7 @@ var init_types9 = __esm({
268501
268741
  hermes: "community",
268502
268742
  opencode: "community",
268503
268743
  trae: "community",
268744
+ dsh: "community",
268504
268745
  pi: "community",
268505
268746
  omp: "community",
268506
268747
  antigravity: "community"
@@ -268559,7 +268800,8 @@ function getAgentLabel2(agent) {
268559
268800
  openclaw: "OpenClaw",
268560
268801
  hermes: "Hermes Agent",
268561
268802
  omp: "Oh-my-Pi",
268562
- trae: "Trae"
268803
+ trae: "Trae",
268804
+ dsh: "DeepSeek Harness"
268563
268805
  };
268564
268806
  return labels[agent] || agent;
268565
268807
  }
@@ -268577,6 +268819,7 @@ function getAgentHint2(agent) {
268577
268819
  hermes: "Hermes plugin hooks; use `memorix setup --agent hermes`",
268578
268820
  omp: "Oh-my-Pi package hooks; use `memorix setup --agent omp`",
268579
268821
  trae: ".trae/rules/project_rules.md (rules only, no hooks system)",
268822
+ dsh: "~/.dsh/cordis.patch.yml MCP row via `memorix setup --agent dsh` (no hooks system)",
268580
268823
  codex: "Codex plugin hooks; use `memorix setup --agent codex`"
268581
268824
  };
268582
268825
  return hints[agent] || "";
@@ -268684,7 +268927,8 @@ function estimateFileSize(agent, configPath) {
268684
268927
  codex: "~1KB",
268685
268928
  antigravity: "~2KB",
268686
268929
  opencode: "~3KB",
268687
- trae: "~1KB"
268930
+ trae: "~1KB",
268931
+ dsh: "~1KB"
268688
268932
  };
268689
268933
  return sizes[agent] || "~2KB";
268690
268934
  }
@@ -268702,6 +268946,8 @@ function getRulesPath(agent, cwd, global2) {
268702
268946
  return path42.join(home, ".gemini", "GEMINI.md");
268703
268947
  case "trae":
268704
268948
  return path42.join(home, ".trae", "rules", "project_rules.md");
268949
+ case "dsh":
268950
+ return path42.join(process.env.DSH_HOME?.trim() || path42.join(home, ".dsh"), "AGENTS.md");
268705
268951
  default:
268706
268952
  return "";
268707
268953
  }
@@ -268717,6 +268963,8 @@ function getRulesPath(agent, cwd, global2) {
268717
268963
  return path42.join(cwd, "GEMINI.md");
268718
268964
  case "trae":
268719
268965
  return path42.join(cwd, ".trae", "rules", "project_rules.md");
268966
+ case "dsh":
268967
+ return path42.join(cwd, "AGENTS.md");
268720
268968
  default:
268721
268969
  return "";
268722
268970
  }
@@ -269025,11 +269273,11 @@ function getCommitInfo(cwd, ref = "HEAD") {
269025
269273
  const date5 = lines[3];
269026
269274
  const subject = lines[4];
269027
269275
  const body = lines.slice(5).join("\n").trim();
269028
- const stat4 = runGit3(cwd, ["diff-tree", "--no-commit-id", "--numstat", hash4]).trim();
269276
+ const stat5 = runGit3(cwd, ["diff-tree", "--no-commit-id", "--numstat", hash4]).trim();
269029
269277
  let insertions = 0;
269030
269278
  let deletions = 0;
269031
269279
  const filesChanged = [];
269032
- for (const line of stat4.split("\n").filter(Boolean)) {
269280
+ for (const line of stat5.split("\n").filter(Boolean)) {
269033
269281
  const parts = line.split(" ");
269034
269282
  if (parts.length >= 3) {
269035
269283
  const ins = parseInt(parts[0], 10) || 0;
@@ -269869,6 +270117,37 @@ var init_embedding = __esm({
269869
270117
  }
269870
270118
  });
269871
270119
 
270120
+ // src/cli/commands/media-image.ts
270121
+ import { readFile as readFile8, stat as stat4 } from "fs/promises";
270122
+ function matchesImagePrefix(bytes, prefix) {
270123
+ return prefix.every((byte, index) => bytes[index] === byte);
270124
+ }
270125
+ function detectReferenceImageMimeType(bytes) {
270126
+ if (bytes.length >= 8 && matchesImagePrefix(bytes, [137, 80, 78, 71, 13, 10, 26, 10])) return "image/png";
270127
+ if (bytes.length >= 3 && matchesImagePrefix(bytes, [255, 216, 255])) return "image/jpeg";
270128
+ if (bytes.length >= 6 && (bytes.subarray(0, 6).toString("ascii") === "GIF87a" || bytes.subarray(0, 6).toString("ascii") === "GIF89a")) return "image/gif";
270129
+ if (bytes.length >= 12 && bytes.subarray(0, 4).toString("ascii") === "RIFF" && bytes.subarray(8, 12).toString("ascii") === "WEBP") return "image/webp";
270130
+ return void 0;
270131
+ }
270132
+ async function readSubjectImage(filePath) {
270133
+ const fileStats = await stat4(filePath);
270134
+ if (fileStats.size > MAX_VISION_IMAGE_BYTES) {
270135
+ throw new Error(`Reference image exceeds the ${MAX_VISION_IMAGE_BYTES}-byte visual analysis limit`);
270136
+ }
270137
+ const bytes = await readFile8(filePath);
270138
+ if (bytes.length === 0) throw new Error(`Reference image is empty: ${filePath}`);
270139
+ const mimeType = detectReferenceImageMimeType(bytes);
270140
+ if (!mimeType) throw new Error("Reference image must be a PNG, JPEG, GIF, or WebP file");
270141
+ return { data: bytes.toString("base64"), mimeType };
270142
+ }
270143
+ var init_media_image = __esm({
270144
+ "src/cli/commands/media-image.ts"() {
270145
+ "use strict";
270146
+ init_esm_shims();
270147
+ init_image_payload();
270148
+ }
270149
+ });
270150
+
269872
270151
  // src/cli/commands/media.ts
269873
270152
  var media_exports = {};
269874
270153
  __export(media_exports, {
@@ -269954,7 +270233,7 @@ function help() {
269954
270233
  ' memorix media attach --asset <asset-id> [--title "Architecture"] [--text "..."]',
269955
270234
  " memorix media embed --asset <asset-id>",
269956
270235
  " memorix media similar --asset <asset-id> [--limit 10]",
269957
- ' memorix media generate image --prompt "..." [--model image-01] [--attach]',
270236
+ ' memorix media generate image --prompt "..." [--model image-01] [--image ./reference.png] [--attach]',
269958
270237
  ' memorix media generate video --prompt "..." [--model MiniMax-H3] [--duration 5] [--ratio 16:9] [--attach]',
269959
270238
  " memorix media status --job <media-job-id>",
269960
270239
  " memorix media cancel --job <media-job-id>",
@@ -269979,6 +270258,7 @@ var init_media = __esm({
269979
270258
  init_minimax2();
269980
270259
  init_video_jobs();
269981
270260
  init_audio_jobs();
270261
+ init_media_image();
269982
270262
  init_operator_shared();
269983
270263
  media_default = defineCommand({
269984
270264
  meta: {
@@ -269996,6 +270276,7 @@ var init_media = __esm({
269996
270276
  concepts: { type: "string", description: "Comma-separated concepts when attaching" },
269997
270277
  visibility: { type: "string", description: "Observation visibility when attaching" },
269998
270278
  prompt: { type: "string", description: "Generation prompt" },
270279
+ image: { type: "string", description: "Path to a reference image for image-to-image generation" },
269999
270280
  model: { type: "string", description: "Provider model" },
270000
270281
  provider: { type: "string", description: "Audio transcription provider: openai or groq" },
270001
270282
  language: { type: "string", description: "Optional ISO-639-1 hint for audio transcription" },
@@ -270067,6 +270348,8 @@ var init_media = __esm({
270067
270348
  );
270068
270349
  return;
270069
270350
  }
270351
+ const referenceImagePath = getValue(args.image);
270352
+ const subjectImages = referenceImagePath ? [await readSubjectImage(referenceImagePath)] : void 0;
270070
270353
  const generated = await generateMiniMaxImages({
270071
270354
  dataDir,
270072
270355
  projectId: project.id,
@@ -270079,6 +270362,7 @@ var init_media = __esm({
270079
270362
  height: parseOptionalInteger(args.height, "height", 1, 8192),
270080
270363
  seed: parseOptionalInteger(args.seed, "seed", 0, 2147483647),
270081
270364
  promptOptimizer: args.promptOptimizer === true || args["prompt-optimizer"] === true,
270365
+ subjectImages,
270082
270366
  maxBytes: parseByteLimit(args.maxBytes ?? args["max-bytes"], 100 * 1024 * 1024)
270083
270367
  });
270084
270368
  const observations2 = args.attach === true ? await Promise.all(generated.assets.map(({ asset }) => attachMediaAssetToObservation({
@@ -271045,14 +271329,14 @@ function doLogs(follow, lines) {
271045
271329
  let position = fs26.statSync(logFile).size;
271046
271330
  const watcher = fs26.watch(logFile, () => {
271047
271331
  try {
271048
- const stat4 = fs26.statSync(logFile);
271049
- if (stat4.size > position) {
271332
+ const stat5 = fs26.statSync(logFile);
271333
+ if (stat5.size > position) {
271050
271334
  const fd = fs26.openSync(logFile, "r");
271051
- const buf = Buffer.alloc(stat4.size - position);
271335
+ const buf = Buffer.alloc(stat5.size - position);
271052
271336
  fs26.readSync(fd, buf, 0, buf.length, position);
271053
271337
  fs26.closeSync(fd);
271054
271338
  process.stdout.write(buf.toString("utf-8"));
271055
- position = stat4.size;
271339
+ position = stat5.size;
271056
271340
  }
271057
271341
  } catch {
271058
271342
  }
@@ -271169,9 +271453,9 @@ __export(agent_integrations_exports, {
271169
271453
  });
271170
271454
  import { spawnSync as spawnSync2 } from "child_process";
271171
271455
  import { existsSync as existsSync28 } from "fs";
271172
- import { mkdir as mkdir8, readFile as readFile8, writeFile as writeFile9 } from "fs/promises";
271456
+ import { mkdir as mkdir8, readFile as readFile9, writeFile as writeFile9 } from "fs/promises";
271173
271457
  import { basename as basename5, dirname as dirname8, resolve as resolve4 } from "path";
271174
- import { homedir as homedir33 } from "os";
271458
+ import { homedir as homedir34 } from "os";
271175
271459
  function requestedAgents(agent) {
271176
271460
  const all = getSetupAgentTargets();
271177
271461
  if (!agent || agent === "all") return all;
@@ -271249,16 +271533,16 @@ function asRecordArray(value) {
271249
271533
  return Array.isArray(value) ? value.map(asRecord3).filter((entry) => entry !== null) : [];
271250
271534
  }
271251
271535
  function codexPluginPath() {
271252
- return `${homedir33()}/plugins/${CODEX_PLUGIN_NAME}`;
271536
+ return `${homedir34()}/plugins/${CODEX_PLUGIN_NAME}`;
271253
271537
  }
271254
271538
  function codexPluginMcpPath() {
271255
271539
  return `${codexPluginPath()}/.mcp.json`;
271256
271540
  }
271257
271541
  function codexMarketplacePath() {
271258
- return `${homedir33()}/.agents/plugins/marketplace.json`;
271542
+ return `${homedir34()}/.agents/plugins/marketplace.json`;
271259
271543
  }
271260
271544
  function codexConfigPath() {
271261
- return `${homedir33()}/.codex/config.toml`;
271545
+ return `${homedir34()}/.codex/config.toml`;
271262
271546
  }
271263
271547
  function normalizeMarketplacePath(value) {
271264
271548
  return value.replace(/\\/g, "/").replace(/^\.\//, "");
@@ -271312,7 +271596,7 @@ async function inspectCodexPluginBundle() {
271312
271596
  }
271313
271597
  let manifest = null;
271314
271598
  try {
271315
- manifest = asRecord3(JSON.parse(await readFile8(manifestPath, "utf-8")));
271599
+ manifest = asRecord3(JSON.parse(await readFile9(manifestPath, "utf-8")));
271316
271600
  } catch {
271317
271601
  return {
271318
271602
  scope: "global",
@@ -271341,7 +271625,7 @@ async function inspectCodexPluginBundle() {
271341
271625
  issues.push("codex-plugin-mcp-manifest-missing");
271342
271626
  } else {
271343
271627
  try {
271344
- const mcpConfig = asRecord3(JSON.parse(await readFile8(mcpPath, "utf-8")));
271628
+ const mcpConfig = asRecord3(JSON.parse(await readFile9(mcpPath, "utf-8")));
271345
271629
  const server = coerceMcpServer("memorix", asRecord3(mcpConfig?.mcpServers)?.memorix);
271346
271630
  if (!server || !isRecommendedStdioServer(server)) {
271347
271631
  issues.push("codex-plugin-mcp-manifest-invalid");
@@ -271355,7 +271639,7 @@ async function inspectCodexPluginBundle() {
271355
271639
  issues.push("codex-hook-manifest-missing");
271356
271640
  } else {
271357
271641
  try {
271358
- const hooksConfig = asRecord3(JSON.parse(await readFile8(hooksPath, "utf-8")));
271642
+ const hooksConfig = asRecord3(JSON.parse(await readFile9(hooksPath, "utf-8")));
271359
271643
  const hooks = asRecord3(hooksConfig?.hooks);
271360
271644
  declared = hooks ? Object.keys(hooks) : [];
271361
271645
  if (CODEX_HOOK_EVENTS.some((event) => !declared.includes(event))) {
@@ -271390,7 +271674,7 @@ async function inspectCodexMarketplace() {
271390
271674
  }
271391
271675
  let catalog = null;
271392
271676
  try {
271393
- catalog = asRecord3(JSON.parse(await readFile8(marketplacePath, "utf-8")));
271677
+ catalog = asRecord3(JSON.parse(await readFile9(marketplacePath, "utf-8")));
271394
271678
  } catch {
271395
271679
  return {
271396
271680
  scope: "global",
@@ -271480,7 +271764,7 @@ async function inspectCodexHookTrust() {
271480
271764
  }
271481
271765
  let config2 = "";
271482
271766
  try {
271483
- config2 = await readFile8(configPath, "utf-8");
271767
+ config2 = await readFile9(configPath, "utf-8");
271484
271768
  } catch {
271485
271769
  return {
271486
271770
  scope: "global",
@@ -271568,7 +271852,7 @@ function defaultClaudeProjectKey(projectRoot) {
271568
271852
  return resolve4(projectRoot).replace(/\\/g, "/");
271569
271853
  }
271570
271854
  function getClaudeLocalConfigPath() {
271571
- return `${homedir33()}/.claude.json`;
271855
+ return `${homedir34()}/.claude.json`;
271572
271856
  }
271573
271857
  function coerceMcpServer(name, value) {
271574
271858
  const entry = asRecord3(value);
@@ -271607,7 +271891,7 @@ async function inspectClaudeLocalMcp(projectRoot) {
271607
271891
  }
271608
271892
  let config2 = {};
271609
271893
  try {
271610
- config2 = JSON.parse(await readFile8(configPath, "utf-8"));
271894
+ config2 = JSON.parse(await readFile9(configPath, "utf-8"));
271611
271895
  } catch {
271612
271896
  return {
271613
271897
  scope: "local",
@@ -271656,7 +271940,7 @@ async function installClaudeLocalMcpConfig(projectRoot) {
271656
271940
  const configPath = getClaudeLocalConfigPath();
271657
271941
  let config2 = {};
271658
271942
  try {
271659
- config2 = JSON.parse(await readFile8(configPath, "utf-8"));
271943
+ config2 = JSON.parse(await readFile9(configPath, "utf-8"));
271660
271944
  } catch {
271661
271945
  config2 = {};
271662
271946
  }
@@ -271695,7 +271979,7 @@ async function inspectCodexPluginMcp() {
271695
271979
  };
271696
271980
  }
271697
271981
  try {
271698
- const config2 = asRecord3(JSON.parse(await readFile8(mcpPath, "utf-8")));
271982
+ const config2 = asRecord3(JSON.parse(await readFile9(mcpPath, "utf-8")));
271699
271983
  const server = coerceMcpServer("memorix", asRecord3(config2?.mcpServers)?.memorix);
271700
271984
  if (!server) {
271701
271985
  return {
@@ -271749,7 +272033,9 @@ async function inspectMcp(agent, projectRoot, scope) {
271749
272033
  }
271750
272034
  }
271751
272035
  const configPath = adapter.getConfigPath(targetScope === "project" ? projectRoot : void 0);
271752
- if (targetScope === "global" && configPath === adapter.getConfigPath(projectRoot)) continue;
272036
+ if (targetScope === "global" && configPath === adapter.getConfigPath(projectRoot) && scope === "all") {
272037
+ continue;
272038
+ }
271753
272039
  if (!existsSync28(configPath)) {
271754
272040
  checks.push({
271755
272041
  scope: targetScope,
@@ -271760,7 +272046,7 @@ async function inspectMcp(agent, projectRoot, scope) {
271760
272046
  });
271761
272047
  continue;
271762
272048
  }
271763
- const content = await readFile8(configPath, "utf-8");
272049
+ const content = await readFile9(configPath, "utf-8");
271764
272050
  if (agent === "claude" && targetScope === "global") {
271765
272051
  try {
271766
272052
  const parsed = JSON.parse(content);
@@ -271825,7 +272111,7 @@ async function inspectGuidance(agent, projectRoot, scope) {
271825
272111
  }
271826
272112
  const checks = [];
271827
272113
  for (const targetScope of requestedGuidanceScopes(scope)) {
271828
- const root = targetScope === "project" ? projectRoot : homedir33();
272114
+ const root = targetScope === "project" ? projectRoot : homedir34();
271829
272115
  const rulesPath = getAgentRulesPath(agent, root, targetScope === "global");
271830
272116
  if (!existsSync28(rulesPath)) {
271831
272117
  checks.push({
@@ -271837,7 +272123,7 @@ async function inspectGuidance(agent, projectRoot, scope) {
271837
272123
  });
271838
272124
  continue;
271839
272125
  }
271840
- const content = await readFile8(rulesPath, "utf-8");
272126
+ const content = await readFile9(rulesPath, "utf-8");
271841
272127
  const issues = isCurrentGuidance(content) ? [] : ["guidance-outdated"];
271842
272128
  checks.push({
271843
272129
  scope: targetScope,
@@ -272041,7 +272327,8 @@ var init_agent_integrations = __esm({
272041
272327
  "antigravity",
272042
272328
  "kiro",
272043
272329
  "opencode",
272044
- "trae"
272330
+ "trae",
272331
+ "dsh"
272045
272332
  ]);
272046
272333
  CODEX_PLUGIN_NAME = "memorix";
272047
272334
  CODEX_PLUGIN_MARKETPLACE = "personal";
@@ -272103,8 +272390,8 @@ var init_doctor = __esm({
272103
272390
  return;
272104
272391
  }
272105
272392
  const { existsSync: existsSync33, readFileSync: readFileSync22 } = await import("fs");
272106
- const { join: join33, basename: basename7 } = await import("path");
272107
- const { homedir: homedir35 } = await import("os");
272393
+ const { join: join34, basename: basename7 } = await import("path");
272394
+ const { homedir: homedir36 } = await import("os");
272108
272395
  const { execSync: execSync5 } = await import("child_process");
272109
272396
  const report = {};
272110
272397
  const issues = [];
@@ -272166,8 +272453,8 @@ var init_doctor = __esm({
272166
272453
  }
272167
272454
  lines.push("");
272168
272455
  lines.push("\u250C\u2500 Runtime Mode \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
272169
- const memorixDir = join33(homedir35(), ".memorix");
272170
- const bgStatePath = join33(memorixDir, "background.json");
272456
+ const memorixDir = join34(homedir36(), ".memorix");
272457
+ const bgStatePath = join34(memorixDir, "background.json");
272171
272458
  let bgRunning = false;
272172
272459
  let bgPort = 0;
272173
272460
  let bgPid = 0;
@@ -272264,7 +272551,7 @@ var init_doctor = __esm({
272264
272551
  report.embedding = { mode, status: "temporarily_unavailable" };
272265
272552
  }
272266
272553
  try {
272267
- const cachePath = join33(memorixDir, "embedding-cache.json");
272554
+ const cachePath = join34(memorixDir, "embedding-cache.json");
272268
272555
  if (existsSync33(cachePath)) {
272269
272556
  const cache5 = JSON.parse(readFileSync22(cachePath, "utf-8"));
272270
272557
  const cacheCount = Object.keys(cache5).length;
@@ -272458,7 +272745,7 @@ var init_doctor = __esm({
272458
272745
  lines.push("\u250C\u2500 Conflict Check \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
272459
272746
  let conflictsFound = false;
272460
272747
  if (dataDir) {
272461
- const lockFile = join33(dataDir, ".memorix.lock");
272748
+ const lockFile = join34(dataDir, ".memorix.lock");
272462
272749
  if (existsSync33(lockFile)) {
272463
272750
  try {
272464
272751
  const lockData = JSON.parse(readFileSync22(lockFile, "utf-8"));
@@ -272968,6 +273255,16 @@ function checkTOML(p3) {
272968
273255
  return false;
272969
273256
  }
272970
273257
  }
273258
+ function checkDshPatch(p3) {
273259
+ if (!exists(p3)) return false;
273260
+ try {
273261
+ const content = fs27.readFileSync(p3, "utf-8");
273262
+ if (!content.includes("memory-memorix")) return false;
273263
+ return /serverName:\s*['"]?memorix['"]?/.test(content);
273264
+ } catch {
273265
+ return false;
273266
+ }
273267
+ }
272971
273268
  function getMCPConfigEntries(home, cwd) {
272972
273269
  const entries = [];
272973
273270
  entries.push({
@@ -273099,6 +273396,15 @@ function getMCPConfigEntries(home, cwd) {
273099
273396
  detected: checkJSON(traeCfg),
273100
273397
  note: 'Remove the "memorix" key from mcpServers in this file.'
273101
273398
  });
273399
+ const dshPatchPath = path45.join(process.env.DSH_HOME?.trim() || path45.join(home, ".dsh"), "cordis.patch.yml");
273400
+ entries.push({
273401
+ agent: "DeepSeek Harness",
273402
+ path: dshPatchPath,
273403
+ kind: "global",
273404
+ format: "json",
273405
+ detected: checkDshPatch(dshPatchPath),
273406
+ note: "Remove the memory-memorix insert row from this patch file."
273407
+ });
273102
273408
  return entries;
273103
273409
  }
273104
273410
  function checkBackground(home) {
@@ -274603,7 +274909,7 @@ var init_pipeline_trace = __esm({
274603
274909
  // src/orchestrate/worktree.ts
274604
274910
  import { execFileSync as execFileSync5 } from "child_process";
274605
274911
  import { existsSync as existsSync30, rmSync as rmSync2 } from "fs";
274606
- import { join as join31, basename as basename6 } from "path";
274912
+ import { join as join32, basename as basename6 } from "path";
274607
274913
  function runGit4(cwd, args, timeout = 5e3) {
274608
274914
  return String(execFileSync5("git", args, {
274609
274915
  cwd,
@@ -274642,7 +274948,7 @@ function isManagedWorktreePath(worktreePath, worktreeBase) {
274642
274948
  function createWorktree(projectDir2, taskId, pipelineId) {
274643
274949
  const shortId2 = taskId.slice(0, 8);
274644
274950
  const shortPipeline = pipelineId.slice(0, 8);
274645
- const worktreeBase = join31(projectDir2, WORKTREE_DIR, `task-${shortId2}`);
274951
+ const worktreeBase = join32(projectDir2, WORKTREE_DIR, `task-${shortId2}`);
274646
274952
  const branchBase = `pipeline/${shortPipeline}/task-${shortId2}`;
274647
274953
  for (let attempt = 1; attempt <= 100; attempt++) {
274648
274954
  const suffix = attempt === 1 ? "" : `-${attempt}`;
@@ -274732,7 +275038,7 @@ function listWorktrees(projectDir2) {
274732
275038
  }
274733
275039
  }
274734
275040
  if (current) worktrees.push(current);
274735
- const worktreeBase = join31(projectDir2, WORKTREE_DIR);
275041
+ const worktreeBase = join32(projectDir2, WORKTREE_DIR);
274736
275042
  return worktrees.filter((w4) => isManagedWorktreePath(w4.path, worktreeBase));
274737
275043
  } catch {
274738
275044
  return [];
@@ -275154,16 +275460,16 @@ var init_cost_tracker = __esm({
275154
275460
 
275155
275461
  // src/orchestrate/evidence.ts
275156
275462
  import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
275157
- import { join as join32 } from "path";
275463
+ import { join as join33 } from "path";
275158
275464
  function writeTaskEvidence(projectDir2, pipelineId, evidence) {
275159
275465
  try {
275160
- const dir = join32(projectDir2, ".pipeline", pipelineId, "evidence", evidence.taskId.slice(0, 12));
275466
+ const dir = join33(projectDir2, ".pipeline", pipelineId, "evidence", evidence.taskId.slice(0, 12));
275161
275467
  mkdirSync9(dir, { recursive: true });
275162
275468
  if (evidence.prompt) {
275163
- safeWrite(join32(dir, "prompt.md"), evidence.prompt);
275469
+ safeWrite(join33(dir, "prompt.md"), evidence.prompt);
275164
275470
  }
275165
275471
  if (evidence.tailOutput) {
275166
- safeWrite(join32(dir, "output.txt"), evidence.tailOutput);
275472
+ safeWrite(join33(dir, "output.txt"), evidence.tailOutput);
275167
275473
  }
275168
275474
  if (evidence.gateResults) {
275169
275475
  for (const g4 of evidence.gateResults) {
@@ -275172,7 +275478,7 @@ Status: ${g4.passed ? "PASS" : "FAIL"}
275172
275478
  Duration: ${(g4.durationMs / 1e3).toFixed(1)}s
275173
275479
 
275174
275480
  ${g4.output}`;
275175
- safeWrite(join32(dir, `${g4.gate}.txt`), content);
275481
+ safeWrite(join33(dir, `${g4.gate}.txt`), content);
275176
275482
  }
275177
275483
  }
275178
275484
  const resultJson = {
@@ -275186,7 +275492,7 @@ ${g4.output}`;
275186
275492
  tokenUsage: evidence.tokenUsage,
275187
275493
  costUSD: evidence.costUSD
275188
275494
  };
275189
- safeWrite(join32(dir, "result.json"), JSON.stringify(resultJson, null, 2));
275495
+ safeWrite(join33(dir, "result.json"), JSON.stringify(resultJson, null, 2));
275190
275496
  return dir;
275191
275497
  } catch {
275192
275498
  return null;
@@ -275194,7 +275500,7 @@ ${g4.output}`;
275194
275500
  }
275195
275501
  function writePipelineSummary(projectDir2, summary) {
275196
275502
  try {
275197
- const dir = join32(projectDir2, ".pipeline", summary.pipelineId);
275503
+ const dir = join33(projectDir2, ".pipeline", summary.pipelineId);
275198
275504
  mkdirSync9(dir, { recursive: true });
275199
275505
  const elapsed = (summary.elapsedMs / 1e3).toFixed(0);
275200
275506
  const lines = [
@@ -275215,8 +275521,8 @@ function writePipelineSummary(projectDir2, summary) {
275215
275521
  lines.push(`- [${status}] ${t4.taskDescription.slice(0, 80)} \u2014 ${t4.agentName}, ${dur}s${fixes}`);
275216
275522
  }
275217
275523
  const content = lines.join("\n") + "\n";
275218
- safeWrite(join32(dir, "summary.md"), content);
275219
- return join32(dir, "summary.md");
275524
+ safeWrite(join33(dir, "summary.md"), content);
275525
+ return join33(dir, "summary.md");
275220
275526
  } catch {
275221
275527
  return null;
275222
275528
  }