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/sdk.js CHANGED
@@ -17863,7 +17863,7 @@ var init_image_models_generated = __esm({
17863
17863
  api: "minimax-images",
17864
17864
  provider: "minimax",
17865
17865
  baseUrl: "https://api.minimax.io/v1/image_generation",
17866
- input: ["text"],
17866
+ input: ["text", "image"],
17867
17867
  output: ["image"],
17868
17868
  cost: {
17869
17869
  "input": 0,
@@ -17878,7 +17878,7 @@ var init_image_models_generated = __esm({
17878
17878
  api: "minimax-images",
17879
17879
  provider: "minimax",
17880
17880
  baseUrl: "https://api.minimax.io/v1/image_generation",
17881
- input: ["text"],
17881
+ input: ["text", "image"],
17882
17882
  output: ["image"],
17883
17883
  cost: {
17884
17884
  "input": 0,
@@ -17895,7 +17895,7 @@ var init_image_models_generated = __esm({
17895
17895
  api: "minimax-images",
17896
17896
  provider: "minimax-cn",
17897
17897
  baseUrl: "https://api.minimaxi.com/v1/image_generation",
17898
- input: ["text"],
17898
+ input: ["text", "image"],
17899
17899
  output: ["image"],
17900
17900
  cost: {
17901
17901
  "input": 0,
@@ -17910,7 +17910,7 @@ var init_image_models_generated = __esm({
17910
17910
  api: "minimax-images",
17911
17911
  provider: "minimax-cn",
17912
17912
  baseUrl: "https://api.minimaxi.com/v1/image_generation",
17913
- input: ["text"],
17913
+ input: ["text", "image"],
17914
17914
  output: ["image"],
17915
17915
  cost: {
17916
17916
  "input": 0,
@@ -18009,9 +18009,10 @@ __export(minimax_exports, {
18009
18009
  });
18010
18010
  import { isIP as isIP2 } from "net";
18011
18011
  function buildPayload(model, context, options) {
18012
- if (context.input.some((item) => item.type === "image")) {
18013
- throw new Error(`Model ${model.id} does not support image input`);
18014
- }
18012
+ const subjectReference = context.input.filter((item) => item.type === "image").map((item) => ({
18013
+ type: "character",
18014
+ image_file: `data:${item.mimeType};base64,${item.data}`
18015
+ }));
18015
18016
  const prompt = context.input.filter((item) => item.type === "text").map((item) => sanitizeSurrogates(item.text).trim()).filter(Boolean).join("\n");
18016
18017
  if (!prompt) {
18017
18018
  throw new Error("MiniMax image generation requires a text prompt");
@@ -18022,6 +18023,7 @@ function buildPayload(model, context, options) {
18022
18023
  return {
18023
18024
  model: model.id,
18024
18025
  prompt,
18026
+ ...subjectReference.length > 0 ? { subject_reference: subjectReference } : {},
18025
18027
  ...options?.aspectRatio !== void 0 ? { aspect_ratio: options.aspectRatio } : {},
18026
18028
  ...options?.width !== void 0 ? { width: options.width } : {},
18027
18029
  ...options?.height !== void 0 ? { height: options.height } : {},
@@ -143172,6 +143174,7 @@ async function generateMiniMaxImages(input, dependencies = {}) {
143172
143174
  ...input.height !== void 0 ? { height: input.height } : {},
143173
143175
  ...input.seed !== void 0 ? { seed: input.seed } : {},
143174
143176
  ...input.promptOptimizer !== void 0 ? { promptOptimizer: input.promptOptimizer } : {},
143177
+ ...input.subjectImages !== void 0 && input.subjectImages.length > 0 ? { subjectImages: input.subjectImages } : {},
143175
143178
  timeoutMs
143176
143179
  });
143177
143180
  } catch (error) {
@@ -143211,9 +143214,13 @@ var init_minimax2 = __esm({
143211
143214
  const model = getImageModel(input.provider, input.model);
143212
143215
  if (!model) throw new Error(`MiniMax image model is not registered: ${input.model}`);
143213
143216
  const configuredModel = input.baseUrl ? { ...model, baseUrl: input.baseUrl } : model;
143217
+ const content = [
143218
+ ...(input.subjectImages ?? []).map((image) => ({ type: "image", data: image.data, mimeType: image.mimeType })),
143219
+ { type: "text", text: input.prompt }
143220
+ ];
143214
143221
  const response = await generateImages(
143215
143222
  configuredModel,
143216
- { input: [{ type: "text", text: input.prompt }] },
143223
+ { input: content },
143217
143224
  {
143218
143225
  apiKey: input.apiKey,
143219
143226
  timeoutMs: input.timeoutMs,
@@ -160273,7 +160280,7 @@ async function installOfficialSkillsForAgent(agent, projectRoot, global2 = false
160273
160280
  const dirs = AGENT_SKILL_DIRS[agent];
160274
160281
  const relativeDir = global2 ? dirs?.global : dirs?.project;
160275
160282
  if (!relativeDir) return [];
160276
- const root = global2 ? os3.homedir() : projectRoot;
160283
+ const root = global2 ? agent === "dsh" ? process.env.DSH_HOME?.trim() || path32.join(os3.homedir(), ".dsh") : os3.homedir() : projectRoot;
160277
160284
  const skillPaths = [];
160278
160285
  for (const skillEntry of OFFICIAL_MEMORIX_SKILLS) {
160279
160286
  const skillPath = path32.join(root, relativeDir, skillEntry.name, "SKILL.md");
@@ -160505,6 +160512,8 @@ function getProjectConfigPath(agent, projectRoot) {
160505
160512
  return path32.join(projectRoot, "AGENTS.md");
160506
160513
  case "trae":
160507
160514
  return path32.join(projectRoot, ".trae", "rules", "project_rules.md");
160515
+ case "dsh":
160516
+ return path32.join(projectRoot, "AGENTS.md");
160508
160517
  case "opencode":
160509
160518
  return path32.join(projectRoot, ".opencode", "plugins", "memorix.js");
160510
160519
  case "pi":
@@ -160550,6 +160559,8 @@ function getGlobalConfigPath(agent) {
160550
160559
  return path32.join(home, ".omp", "agent", "packages", "memorix", "extensions", "memorix.js");
160551
160560
  case "trae":
160552
160561
  return path32.join(home, ".trae", "rules", "project_rules.md");
160562
+ case "dsh":
160563
+ return path32.join(process.env.DSH_HOME?.trim() || path32.join(home, ".dsh"), "AGENTS.md");
160553
160564
  default:
160554
160565
  return path32.join(home, ".memorix", "hooks.json");
160555
160566
  }
@@ -160574,6 +160585,8 @@ function getAgentRulesPath(agent, root, global2 = false) {
160574
160585
  return path32.join(root, ".gemini", "GEMINI.md");
160575
160586
  case "trae":
160576
160587
  return path32.join(root, ".trae", "rules", "project_rules.md");
160588
+ case "dsh":
160589
+ return path32.join(process.env.DSH_HOME?.trim() || path32.join(root, ".dsh"), "AGENTS.md");
160577
160590
  default:
160578
160591
  return path32.join(root, ".agent", "rules", "memorix.md");
160579
160592
  }
@@ -160598,6 +160611,8 @@ function getAgentRulesPath(agent, root, global2 = false) {
160598
160611
  return path32.join(root, "GEMINI.md");
160599
160612
  case "trae":
160600
160613
  return path32.join(root, ".trae", "rules", "project_rules.md");
160614
+ case "dsh":
160615
+ return path32.join(root, "AGENTS.md");
160601
160616
  default:
160602
160617
  return path32.join(root, ".agent", "rules", "memorix.md");
160603
160618
  }
@@ -160680,6 +160695,12 @@ async function detectInstalledAgents() {
160680
160695
  agents.push("trae");
160681
160696
  } catch {
160682
160697
  }
160698
+ const dshDir = process.env.DSH_HOME?.trim() || path32.join(home, ".dsh");
160699
+ try {
160700
+ await fs21.access(dshDir);
160701
+ agents.push("dsh");
160702
+ } catch {
160703
+ }
160683
160704
  return agents;
160684
160705
  }
160685
160706
  async function installHooks(agent, projectRoot, global2 = false) {
@@ -160762,6 +160783,19 @@ async function installHooks(agent, projectRoot, global2 = false) {
160762
160783
  generated: { note: "Trae has no hooks system, only rules (.trae/rules/project_rules.md) installed" }
160763
160784
  };
160764
160785
  }
160786
+ case "dsh": {
160787
+ const rulesPath = await installAgentRules(agent, projectRoot, global2);
160788
+ const skillPaths2 = await installOfficialSkillsForAgent(agent, projectRoot, global2);
160789
+ return {
160790
+ agent,
160791
+ configPath: rulesPath,
160792
+ events: [],
160793
+ generated: {
160794
+ note: "DeepSeek Harness has no hook system \u2014 installed AGENTS.md guidance and skills; the MCP row is installed by `memorix setup --agent dsh`.",
160795
+ ...skillPaths2.length > 0 ? { skillPaths: skillPaths2, skillPath: skillPaths2[0] } : {}
160796
+ }
160797
+ };
160798
+ }
160765
160799
  case "opencode": {
160766
160800
  const pluginContent = generateOpenCodePlugin();
160767
160801
  const pluginPath = global2 ? getGlobalConfigPath(agent) : getProjectConfigPath(agent, projectRoot);
@@ -160896,7 +160930,7 @@ async function installAgentRules(agent, projectRoot, global2 = false) {
160896
160930
  const rulesPath = getAgentRulesPath(agent, rulesRoot, global2);
160897
160931
  try {
160898
160932
  await fs21.mkdir(path32.dirname(rulesPath), { recursive: true });
160899
- if (agent === "claude" || agent === "codex" || agent === "opencode" || agent === "antigravity" || agent === "gemini-cli") {
160933
+ if (agent === "claude" || agent === "codex" || agent === "opencode" || agent === "antigravity" || agent === "gemini-cli" || agent === "dsh") {
160900
160934
  try {
160901
160935
  const existing = await fs21.readFile(rulesPath, "utf-8");
160902
160936
  await fs21.writeFile(rulesPath, mergeMemorixRulesContent(existing, rulesContent), "utf-8");
@@ -161185,7 +161219,10 @@ var init_installers = __esm({
161185
161219
  windsurf: { project: path32.join(".windsurf", "skills"), global: path32.join(".windsurf", "skills") },
161186
161220
  kiro: { project: path32.join(".kiro", "skills"), global: path32.join(".kiro", "skills") },
161187
161221
  opencode: { project: path32.join(".opencode", "skills"), global: path32.join(".config", "opencode", "skills") },
161188
- trae: { project: path32.join(".trae", "skills"), global: path32.join(".trae", "skills") }
161222
+ trae: { project: path32.join(".trae", "skills"), global: path32.join(".trae", "skills") },
161223
+ // DSH's user skill root is <harness home>/skills; the global root below is
161224
+ // resolved to $DSH_HOME (or ~/.dsh) for dsh by installOfficialSkillsForAgent.
161225
+ dsh: { project: path32.join(".dsh", "skills"), global: "skills" }
161189
161226
  };
161190
161227
  PACKAGE_OWNED_HOOK_AGENTS = /* @__PURE__ */ new Set(["openclaw", "hermes", "omp"]);
161191
161228
  }
@@ -165367,7 +165404,7 @@ The path should point to a directory containing a .git folder.`
165367
165404
  };
165368
165405
  const server = existingServer ?? new McpServer({
165369
165406
  name: "memorix",
165370
- version: true ? "1.4.3" : "1.0.1"
165407
+ version: true ? "1.4.5" : "1.0.1"
165371
165408
  });
165372
165409
  const originalRegisterTool = server.registerTool.bind(server);
165373
165410
  server.registerTool = ((name, ...args) => {
@@ -169050,6 +169087,16 @@ ${lines.join("\n")}` }] };
169050
169087
  return { content: [{ type: "text", text: lines.filter(Boolean).join("\n") }] };
169051
169088
  }
169052
169089
  );
169090
+ function matchesImagePrefix(bytes, prefix) {
169091
+ return prefix.every((byte, index) => bytes[index] === byte);
169092
+ }
169093
+ function detectReferenceImageMimeType(bytes) {
169094
+ if (bytes.length >= 8 && matchesImagePrefix(bytes, [137, 80, 78, 71, 13, 10, 26, 10])) return "image/png";
169095
+ if (bytes.length >= 3 && matchesImagePrefix(bytes, [255, 216, 255])) return "image/jpeg";
169096
+ 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";
169097
+ 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";
169098
+ return void 0;
169099
+ }
169053
169100
  server.registerTool(
169054
169101
  "memorix_media",
169055
169102
  {
@@ -169065,6 +169112,7 @@ ${lines.join("\n")}` }] };
169065
169112
  title: z626.string().optional().describe("Observation title when attaching generated/imported output."),
169066
169113
  narrative: z626.string().optional().describe("Short retrieval text when attaching an asset."),
169067
169114
  prompt: z626.string().optional().describe("Explicit MiniMax generation prompt."),
169115
+ image: z626.string().optional().describe("Base64-encoded reference image for image-to-image generation."),
169068
169116
  model: z626.string().max(160).optional().describe("Provider model for the selected media action."),
169069
169117
  provider: z626.enum(["openai", "groq"]).optional().describe("Explicit audio transcription provider."),
169070
169118
  language: z626.string().max(32).optional().describe("Optional ISO-639-1 hint for audio transcription."),
@@ -169079,7 +169127,7 @@ ${lines.join("\n")}` }] };
169079
169127
  attach: z626.boolean().optional().describe("Attach generated/imported output to normal project memory explicitly.")
169080
169128
  }
169081
169129
  },
169082
- async ({ action, path: assetPath, assetId, jobId, kind, limit: limit2, title, narrative, prompt, model, provider: provider2, language, region, n, ratio, width, height, duration, maxPages, maxChars, attach }) => {
169130
+ async ({ action, path: assetPath, assetId, jobId, kind, limit: limit2, title, narrative, prompt, image, model, provider: provider2, language, region, n, ratio, width, height, duration, maxPages, maxChars, attach }) => {
169083
169131
  const unresolved = requireResolvedProject("manage controlled media");
169084
169132
  if (unresolved) return unresolved;
169085
169133
  const safeError4 = (error) => sanitizeCredentials(
@@ -169208,6 +169256,14 @@ ${lines.join("\n")}` }] };
169208
169256
  if (model && !imageModel) throw new Error("generate-image accepts image-01 or image-01-live");
169209
169257
  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;
169210
169258
  if (ratio && !imageRatio) throw new Error("generate-image received an unsupported aspect ratio");
169259
+ let subjectImages;
169260
+ if (image?.trim()) {
169261
+ const { decodeBase64ImagePayload: decodeBase64ImagePayload2 } = await Promise.resolve().then(() => (init_image_payload(), image_payload_exports));
169262
+ const bytes = decodeBase64ImagePayload2(image);
169263
+ const mimeType = detectReferenceImageMimeType(bytes);
169264
+ if (!mimeType) throw new Error("Reference image must be a PNG, JPEG, GIF, or WebP image");
169265
+ subjectImages = [{ data: bytes.toString("base64"), mimeType }];
169266
+ }
169211
169267
  const { generateMiniMaxImages: generateMiniMaxImages2 } = await Promise.resolve().then(() => (init_minimax2(), minimax_exports2));
169212
169268
  const generated = await generateMiniMaxImages2({
169213
169269
  dataDir: projectDir2,
@@ -169218,7 +169274,8 @@ ${lines.join("\n")}` }] };
169218
169274
  n,
169219
169275
  aspectRatio: imageRatio,
169220
169276
  width,
169221
- height
169277
+ height,
169278
+ subjectImages
169222
169279
  });
169223
169280
  const observations2 = attach === true ? await Promise.all(generated.assets.map(({ asset }) => attachAsset(
169224
169281
  asset,
package/dist/types.d.ts CHANGED
@@ -592,7 +592,7 @@ interface MemoryRef {
592
592
  /** MCP config format adapter interface */
593
593
  interface MCPConfigAdapter {
594
594
  /** Setup-only adapters may support a host that does not participate in workspace sync. */
595
- readonly source: AgentTarget | 'codebuddy';
595
+ readonly source: AgentTarget | 'codebuddy' | 'dsh';
596
596
  /** Parse MCP server entries from a config file */
597
597
  parse(content: string): MCPServerEntry[];
598
598
  /** Generate config file content from MCP server entries */
@@ -18216,7 +18216,7 @@ var init_image_models_generated = __esm({
18216
18216
  api: "minimax-images",
18217
18217
  provider: "minimax",
18218
18218
  baseUrl: "https://api.minimax.io/v1/image_generation",
18219
- input: ["text"],
18219
+ input: ["text", "image"],
18220
18220
  output: ["image"],
18221
18221
  cost: {
18222
18222
  "input": 0,
@@ -18231,7 +18231,7 @@ var init_image_models_generated = __esm({
18231
18231
  api: "minimax-images",
18232
18232
  provider: "minimax",
18233
18233
  baseUrl: "https://api.minimax.io/v1/image_generation",
18234
- input: ["text"],
18234
+ input: ["text", "image"],
18235
18235
  output: ["image"],
18236
18236
  cost: {
18237
18237
  "input": 0,
@@ -18248,7 +18248,7 @@ var init_image_models_generated = __esm({
18248
18248
  api: "minimax-images",
18249
18249
  provider: "minimax-cn",
18250
18250
  baseUrl: "https://api.minimaxi.com/v1/image_generation",
18251
- input: ["text"],
18251
+ input: ["text", "image"],
18252
18252
  output: ["image"],
18253
18253
  cost: {
18254
18254
  "input": 0,
@@ -18263,7 +18263,7 @@ var init_image_models_generated = __esm({
18263
18263
  api: "minimax-images",
18264
18264
  provider: "minimax-cn",
18265
18265
  baseUrl: "https://api.minimaxi.com/v1/image_generation",
18266
- input: ["text"],
18266
+ input: ["text", "image"],
18267
18267
  output: ["image"],
18268
18268
  cost: {
18269
18269
  "input": 0,
@@ -18355,9 +18355,10 @@ __export(minimax_exports, {
18355
18355
  });
18356
18356
  import { isIP as isIP2 } from "net";
18357
18357
  function buildPayload(model, context, options) {
18358
- if (context.input.some((item) => item.type === "image")) {
18359
- throw new Error(`Model ${model.id} does not support image input`);
18360
- }
18358
+ const subjectReference = context.input.filter((item) => item.type === "image").map((item) => ({
18359
+ type: "character",
18360
+ image_file: `data:${item.mimeType};base64,${item.data}`
18361
+ }));
18361
18362
  const prompt = context.input.filter((item) => item.type === "text").map((item) => sanitizeSurrogates(item.text).trim()).filter(Boolean).join("\n");
18362
18363
  if (!prompt) {
18363
18364
  throw new Error("MiniMax image generation requires a text prompt");
@@ -18368,6 +18369,7 @@ function buildPayload(model, context, options) {
18368
18369
  return {
18369
18370
  model: model.id,
18370
18371
  prompt,
18372
+ ...subjectReference.length > 0 ? { subject_reference: subjectReference } : {},
18371
18373
  ...options?.aspectRatio !== void 0 ? { aspect_ratio: options.aspectRatio } : {},
18372
18374
  ...options?.width !== void 0 ? { width: options.width } : {},
18373
18375
  ...options?.height !== void 0 ? { height: options.height } : {},
@@ -23,11 +23,11 @@ It supports:
23
23
  - HTTP MCP service + dashboard (`memorix background start` or `memorix serve-http --port 3211`)
24
24
  - bundled terminal agent (`memorix` or `memcode`) that uses the same shared memory pool
25
25
  - local-first project-scoped memory
26
- - cross-agent recall across Cursor, Claude Code, Codex, CodeBuddy Code, Windsurf, Gemini CLI, GitHub Copilot, OpenCode, OpenClaw, Hermes Agent, Oh-my-Pi, Pi, Kiro, Antigravity, and Trae
26
+ - cross-agent recall across Cursor, Claude Code, Codex, CodeBuddy Code, Windsurf, Gemini CLI, GitHub Copilot, OpenCode, OpenClaw, Hermes Agent, Oh-my-Pi, Pi, Kiro, Antigravity, Trae, and DeepSeek Harness
27
27
 
28
- ### Current 1.2 Baseline
28
+ ### Current 1.4 Baseline
29
29
 
30
- For the 1.2 release line, the visible product shape is:
30
+ For the 1.4 release line, the visible product shape is:
31
31
 
32
32
  - `memorix setup --agent <agent> --global` is the default integration command for an existing coding agent or IDE
33
33
  - setup installs plugin packages where supported, MCP config, usage guidance, hooks, and skills according to agent capability
@@ -41,7 +41,7 @@ For the 1.2 release line, the visible product shape is:
41
41
  - `memorix_project_context` / `memorix context "..."` is the normal black-box entry for non-trivial coding work: it assembles a bounded task Workset instead of injecting a generic memory dump; `memorix resume "..."` is the explicit CLI continuation projection
42
42
  - Code State keeps local snapshots and freshness links; a healthy pre-existing local CodeGraph index can add a bounded semantic outline, but Memorix never initializes or synchronizes that external index itself
43
43
  - `memorix knowledge` is an explicit review path for source-backed Markdown knowledge and canonical workflows. Do not initialize a versioned workspace or apply a proposal unless the user asks for that managed artifact
44
- - integration surfaces are agent-specific: Claude Code, Codex, GitHub Copilot CLI, Antigravity, and Hermes receive plugin packages; OpenClaw receives a compatible bundle; Pi and Oh-my-Pi receive package entries; Gemini CLI receives an extension package; OpenCode receives a plugin file and skill; Cursor and other agents receive MCP/rules/hooks where supported
44
+ - integration surfaces are agent-specific: Claude Code, Codex, GitHub Copilot CLI, Antigravity, and Hermes receive plugin packages; OpenClaw receives a compatible bundle; Pi and Oh-my-Pi receive package entries; Gemini CLI receives an extension package; OpenCode receives a plugin file and skill; DeepSeek Harness receives an MCP patch row, AGENTS.md guidance, and skills; Cursor and other agents receive MCP/rules/hooks where supported
45
45
  - privacy-safe diagnostics and receipts avoid raw chat, memory text, query text, tool payloads, and local file paths
46
46
 
47
47
  ---
@@ -50,7 +50,7 @@ For the 1.2 release line, the visible product shape is:
50
50
 
51
51
  ### CLI is the direct command surface; MCP is the integration layer
52
52
 
53
- For direct use, prefer `memorix ...` commands first. In the 1.3 line, the CLI covers session, memory, reviewed long-term memory, Code State, knowledge workspaces, reasoning, retention, formation, audit, transfer, skills, orchestration coordination, sync, ingest workflows, and the bundled terminal agent.
53
+ For direct use, prefer `memorix ...` commands first. In the 1.4 line, the CLI covers session, memory, reviewed long-term memory, Code State, knowledge workspaces, reasoning, retention, formation, audit, transfer, skills, orchestration coordination, sync, controlled media, ingest workflows, and the bundled terminal agent.
54
54
 
55
55
  Do not ask memory-only users to join coordination state. A lightweight session is enough for memory, retrieval, reasoning, and continuation. Use `joinTeam` / `team_manage(join)` only for explicit task/message/lock coordination or for CLI-agent work managed by `memorix orchestrate`.
56
56
 
@@ -256,6 +256,7 @@ What this installs depends on the target agent:
256
256
  - Hermes Agent: Hermes plugin under Hermes home (`%LOCALAPPDATA%\hermes` on native Windows, `~/.hermes` elsewhere, or `HERMES_HOME`), enabled in `config.yaml`, with plugin hooks, slash command, CLI command, skills, and MCP config.
257
257
  - Oh-my-Pi: `omp.extensions` package linked through `omp plugin link <path>` when available, with extension hook events, a `memorix` command, skills, and MCP config.
258
258
  - Windsurf, Kiro, Trae: MCP config plus rules/hooks where supported.
259
+ - DeepSeek Harness: a Memorix `@deepseek-ai/dsh-mcp-client` row in `$DSH_HOME/cordis.patch.yml` (default `~/.dsh/cordis.patch.yml`), harness `AGENTS.md` guidance, and official skills under `$DSH_HOME/skills`. Tools appear as `mcp__memorix__*`; there is no hooks surface. Project-local setup writes project `AGENTS.md` guidance and `.dsh/skills`, while the MCP row stays in the harness-level patch file.
259
260
 
260
261
  Run the same setup command without `--global` only when you intentionally want repo-local guidance, rules, or hooks for a single Git project.
261
262
 
@@ -754,18 +754,22 @@ durable job, so it survives process restarts and can be inspected or cancelled.
754
754
 
755
755
  ```bash
756
756
  memorix media generate image --prompt "..." --json
757
+ memorix media generate image --prompt "..." --image ./reference.png --json
757
758
  memorix media generate video --prompt "..." --json
759
+ memorix media derive-pdf --asset <asset-id> --attach --json
758
760
  memorix media derive-audio --asset <asset-id> --provider groq --attach --json
759
761
  memorix media status --job <media-job-id> --json
760
762
  memorix media cancel --job <media-job-id> --json
761
763
  ```
762
764
 
763
765
  Set `MINIMAX_API_KEY` (or `MINIMAX_CN_API_KEY`) outside Git before using
764
- generation. `memorix_media` is the matching single MCP tool in `lite`, `team`,
765
- and `full` profiles. Its import/attach/list/show/status actions are available
766
- normally; generation requires `MEMORIX_MCP_MEDIA_GENERATION=1` because it can
767
- incur provider charges. Text-only embedding providers never produce a pretend
768
- image, audio, video, or document vector.
766
+ generation. Image-to-image passes the reference image through MiniMax
767
+ `subject_reference` for the image-01/image-01-live models. `memorix_media` is
768
+ the matching single MCP tool in every profile, including `micro`. Its
769
+ import/attach/list/show/derive-pdf/derive-audio/status/cancel actions are
770
+ available normally; generation requires `MEMORIX_MCP_MEDIA_GENERATION=1`
771
+ because it can incur provider charges. Text-only embedding providers never
772
+ produce a pretend image, audio, video, or document vector.
769
773
 
770
774
  Audio transcription is also explicit. `derive-audio` consumes an existing
771
775
  controlled audio asset and queues a durable transcript derivative. It supports
@@ -162,10 +162,10 @@ Provider values:
162
162
  - `transformers`
163
163
 
164
164
  If embedding is unavailable, Memorix falls back to BM25/full-text search.
165
- `transformers` is installed as an optional dependency. `fastembed` remains a
166
- supported local provider, but it is no longer installed by default; install it
167
- explicitly in the project or global prefix where Memorix runs if you choose that
168
- provider.
165
+ `transformers` is no longer installed by default; install
166
+ `@huggingface/transformers` explicitly in the project or global prefix where
167
+ Memorix runs if you choose that provider. `fastembed` remains a supported local
168
+ provider and is likewise not installed by default.
169
169
 
170
170
  OpenRouter embeddings can use the official OpenRouter environment variable:
171
171
 
@@ -214,6 +214,16 @@ The conservative source limit is 25 MiB. The CLI is enabled when a credential
214
214
  is present; MCP-originated transcription remains disabled unless
215
215
  `MEMORIX_MCP_MEDIA_TRANSCRIPTION=1` is set after reviewing provider billing.
216
216
 
217
+ ### Controlled PDF text derivation
218
+
219
+ PDF text extraction is a separate, opt-in derivative lane with no provider
220
+ credentials. `memorix media derive-pdf --asset <asset-id>` parses the managed
221
+ PDF locally (bundled PDF.js via `unpdf`, system fonts disabled) and stores a
222
+ bounded text derivative with page and character limits (`--maxPages`,
223
+ `--maxChars`). The MCP `memorix_media` tool accepts `derive-pdf` with the same
224
+ bounds, and the derived text only enters normal memory when explicitly
225
+ attached.
226
+
217
227
  ### `[memory]`
218
228
 
219
229
  Runtime memory behavior.
@@ -285,7 +295,7 @@ Server and dashboard behavior.
285
295
  Common keys:
286
296
 
287
297
  - `transport = "stdio"`
288
- - `port = 37850`
298
+ - `port = 3211`
289
299
  - `dashboard = true`
290
300
  - `dashboard_port = 3210`
291
301