memorix 1.1.12 → 1.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.1.13] - 2026-07-17
8
+
9
+ ### Added
10
+ - **Codex installation proof** -- `memorix doctor agents --agent codex --scope global` now checks the local plugin bundle, Personal marketplace entry, five declared and trusted lifecycle hooks, and the installed/enabled state reported by `codex plugin list`.
11
+
12
+ ### Fixed
13
+ - **Codex plugin version drift** -- Global setup now stamps the copied Codex plugin manifest with the installed Memorix version, so Codex no longer reports the old template version after an upgrade. The source template is covered by a release regression test as well.
14
+ - **Workspace package publish trap** -- `@memorix/ai`, `@memorix/agent-core`, `@memorix/tui`, and `@memorix/memcode` are now explicitly internal workspaces. The root `memorix` package ships their bundled runtime, and the release workflow publishes only that supported public package.
15
+
7
16
  ## [1.1.12] - 2026-07-17
8
17
 
9
18
  ### Added
package/README.md CHANGED
@@ -473,3 +473,5 @@ Memorix draws from the MCP ecosystem and prior memory projects such as mcp-memor
473
473
  <h2 id="license"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/section-license.svg"><img src="assets/tags/section-license.svg" alt="License" height="32" /></picture></h2>
474
474
 
475
475
  [Apache 2.0](LICENSE)
476
+
477
+ [![Star History Chart](https://api.star-history.com/image?repos=AVIDS2/memorix&type=Date)](https://star-history.com/#AVIDS2/memorix&Date)
package/README.zh-CN.md CHANGED
@@ -471,3 +471,5 @@ Memorix 借鉴了 MCP 生态和 mcp-memory-service、MemCP、claude-mem、Mem0
471
471
  <h2 id="license"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/section-license.svg"><img src="assets/tags/section-license.svg" alt="License" height="32" /></picture></h2>
472
472
 
473
473
  [Apache 2.0](LICENSE)
474
+
475
+ [![Star History Chart](https://api.star-history.com/image?repos=AVIDS2/memorix&type=Date)](https://star-history.com/#AVIDS2/memorix&Date)
package/dist/cli/index.js CHANGED
@@ -3212,7 +3212,7 @@ ${import_picocolors.default.gray(m3)} ${s2}
3212
3212
 
3213
3213
  // src/cli/version.ts
3214
3214
  function getCliVersion() {
3215
- return true ? "1.1.12" : pkg.version;
3215
+ return true ? "1.1.13" : pkg.version;
3216
3216
  }
3217
3217
  var init_version = __esm({
3218
3218
  "src/cli/version.ts"() {
@@ -23285,7 +23285,8 @@ __export(setup_exports, {
23285
23285
  installOmpPackage: () => installOmpPackage,
23286
23286
  installOpenClawBundlePackage: () => installOpenClawBundlePackage,
23287
23287
  installPiPackage: () => installPiPackage,
23288
- installPluginPackage: () => installPluginPackage
23288
+ installPluginPackage: () => installPluginPackage,
23289
+ tryInstallCodexPlugin: () => tryInstallCodexPlugin
23289
23290
  });
23290
23291
  import { spawnSync } from "child_process";
23291
23292
  import { existsSync as existsSync9 } from "fs";
@@ -23383,6 +23384,16 @@ async function stripHookCaptureFromPlugin(pluginPath, agent) {
23383
23384
  } catch {
23384
23385
  }
23385
23386
  }
23387
+ async function stampCodexPluginVersion(pluginPath) {
23388
+ const manifestPath = path14.join(pluginPath, ".codex-plugin", "plugin.json");
23389
+ const manifest = JSON.parse(await readFile5(manifestPath, "utf-8"));
23390
+ if (manifest.name !== "memorix") {
23391
+ throw new Error(`Unexpected Codex plugin manifest at ${manifestPath}`);
23392
+ }
23393
+ manifest.version = getCliVersion();
23394
+ await writeFile5(manifestPath, `${JSON.stringify(manifest, null, 2)}
23395
+ `, "utf-8");
23396
+ }
23386
23397
  async function stripHookCaptureFromOpenClawBundle(bundlePath) {
23387
23398
  await rm(path14.join(bundlePath, "hooks"), { recursive: true, force: true });
23388
23399
  const manifestPath = path14.join(bundlePath, ".codex-plugin", "plugin.json");
@@ -23647,6 +23658,7 @@ async function installPluginPackage(options2) {
23647
23658
  const pluginPath2 = path14.join(home, ".codex", "plugins", "memorix");
23648
23659
  const marketplacePath2 = path14.join(home, ".agents", "plugins", "marketplace.json");
23649
23660
  await copyDir(source, pluginPath2);
23661
+ await stampCodexPluginVersion(pluginPath2);
23650
23662
  if (!includeHooks) await stripHookCaptureFromPlugin(pluginPath2, "codex");
23651
23663
  await writeOfficialSkills(path14.join(pluginPath2, "skills"));
23652
23664
  await upsertCodexMarketplace(marketplacePath2, pluginPath2);
@@ -63854,7 +63866,7 @@ The path should point to a directory containing a .git folder.`
63854
63866
  };
63855
63867
  const server = existingServer ?? new McpServer({
63856
63868
  name: "memorix",
63857
- version: true ? "1.1.12" : "1.0.1"
63869
+ version: true ? "1.1.13" : "1.0.1"
63858
63870
  });
63859
63871
  const originalRegisterTool = server.registerTool.bind(server);
63860
63872
  server.registerTool = ((name, ...args) => {
@@ -73908,8 +73920,10 @@ __export(agent_integrations_exports, {
73908
73920
  formatAgentIntegrationReport: () => formatAgentIntegrationReport,
73909
73921
  formatAgentRepairResult: () => formatAgentRepairResult,
73910
73922
  inspectAgentIntegrations: () => inspectAgentIntegrations,
73923
+ parseCodexPluginList: () => parseCodexPluginList,
73911
73924
  repairAgentIntegrations: () => repairAgentIntegrations
73912
73925
  });
73926
+ import { spawnSync as spawnSync2 } from "child_process";
73913
73927
  import { existsSync as existsSync23 } from "fs";
73914
73928
  import { mkdir as mkdir7, readFile as readFile7, writeFile as writeFile7 } from "fs/promises";
73915
73929
  import { basename as basename3, dirname as dirname7, resolve as resolve2 } from "path";
@@ -73987,6 +74001,275 @@ function aggregateGuidanceIssues(checks) {
73987
74001
  function asRecord2(value) {
73988
74002
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
73989
74003
  }
74004
+ function asRecordArray(value) {
74005
+ return Array.isArray(value) ? value.map(asRecord2).filter((entry) => entry !== null) : [];
74006
+ }
74007
+ function codexPluginPath() {
74008
+ return `${homedir32()}/.codex/plugins/${CODEX_PLUGIN_NAME}`;
74009
+ }
74010
+ function codexMarketplacePath() {
74011
+ return `${homedir32()}/.agents/plugins/marketplace.json`;
74012
+ }
74013
+ function codexConfigPath() {
74014
+ return `${homedir32()}/.codex/config.toml`;
74015
+ }
74016
+ function normalizeMarketplacePath(value) {
74017
+ return value.replace(/\\/g, "/").replace(/^\.\//, "");
74018
+ }
74019
+ function isMemorixCodexPlugin(value) {
74020
+ return value.pluginId === CODEX_PLUGIN_ID || value.name === CODEX_PLUGIN_NAME && value.marketplaceName === CODEX_PLUGIN_MARKETPLACE;
74021
+ }
74022
+ function parseCodexPluginList(output) {
74023
+ try {
74024
+ const parsed = asRecord2(JSON.parse(output));
74025
+ if (!parsed) return null;
74026
+ const entries = [...asRecordArray(parsed.installed), ...asRecordArray(parsed.available)];
74027
+ const plugin = entries.find(isMemorixCodexPlugin);
74028
+ if (!plugin) return { installed: false, enabled: false };
74029
+ return {
74030
+ installed: plugin.installed === true,
74031
+ enabled: plugin.enabled === true,
74032
+ ...typeof plugin.version === "string" ? { version: plugin.version } : {}
74033
+ };
74034
+ } catch {
74035
+ return null;
74036
+ }
74037
+ }
74038
+ async function inspectCodexPluginBundle() {
74039
+ const pluginPath = codexPluginPath();
74040
+ const manifestPath = `${pluginPath}/.codex-plugin/plugin.json`;
74041
+ const hooksPath = `${pluginPath}/hooks/hooks.json`;
74042
+ if (!existsSync23(pluginPath)) {
74043
+ return {
74044
+ scope: "global",
74045
+ kind: "bundle",
74046
+ path: pluginPath,
74047
+ exists: false,
74048
+ status: "missing",
74049
+ issues: ["codex-plugin-bundle-missing"]
74050
+ };
74051
+ }
74052
+ if (!existsSync23(manifestPath)) {
74053
+ return {
74054
+ scope: "global",
74055
+ kind: "bundle",
74056
+ path: manifestPath,
74057
+ exists: false,
74058
+ status: "repairable",
74059
+ issues: ["codex-plugin-manifest-missing"]
74060
+ };
74061
+ }
74062
+ let manifest = null;
74063
+ try {
74064
+ manifest = asRecord2(JSON.parse(await readFile7(manifestPath, "utf-8")));
74065
+ } catch {
74066
+ return {
74067
+ scope: "global",
74068
+ kind: "bundle",
74069
+ path: manifestPath,
74070
+ exists: true,
74071
+ status: "repairable",
74072
+ issues: ["codex-plugin-manifest-unreadable"]
74073
+ };
74074
+ }
74075
+ if (!manifest || manifest.name !== CODEX_PLUGIN_NAME) {
74076
+ return {
74077
+ scope: "global",
74078
+ kind: "bundle",
74079
+ path: manifestPath,
74080
+ exists: true,
74081
+ status: "repairable",
74082
+ issues: ["codex-plugin-manifest-invalid"]
74083
+ };
74084
+ }
74085
+ const version2 = typeof manifest.version === "string" ? manifest.version : void 0;
74086
+ const issues = [];
74087
+ if (version2 !== getCliVersion()) issues.push("codex-plugin-version-mismatch");
74088
+ if (manifest.hooks !== "./hooks/hooks.json") issues.push("codex-hook-manifest-missing");
74089
+ let declared = [];
74090
+ if (!existsSync23(hooksPath)) {
74091
+ issues.push("codex-hook-manifest-missing");
74092
+ } else {
74093
+ try {
74094
+ const hooksConfig = asRecord2(JSON.parse(await readFile7(hooksPath, "utf-8")));
74095
+ const hooks = asRecord2(hooksConfig?.hooks);
74096
+ declared = hooks ? Object.keys(hooks) : [];
74097
+ if (CODEX_HOOK_EVENTS.some((event) => !declared.includes(event))) {
74098
+ issues.push("codex-hook-events-missing");
74099
+ }
74100
+ } catch {
74101
+ issues.push("codex-hook-manifest-unreadable");
74102
+ }
74103
+ }
74104
+ return {
74105
+ scope: "global",
74106
+ kind: "bundle",
74107
+ path: pluginPath,
74108
+ exists: true,
74109
+ status: issues.length > 0 ? "repairable" : "ok",
74110
+ issues: unique(issues),
74111
+ ...version2 ? { version: version2 } : {},
74112
+ hooks: { declared, expected: [...CODEX_HOOK_EVENTS] }
74113
+ };
74114
+ }
74115
+ async function inspectCodexMarketplace() {
74116
+ const marketplacePath = codexMarketplacePath();
74117
+ if (!existsSync23(marketplacePath)) {
74118
+ return {
74119
+ scope: "global",
74120
+ kind: "marketplace",
74121
+ path: marketplacePath,
74122
+ exists: false,
74123
+ status: "missing",
74124
+ issues: ["codex-marketplace-missing"]
74125
+ };
74126
+ }
74127
+ let catalog = null;
74128
+ try {
74129
+ catalog = asRecord2(JSON.parse(await readFile7(marketplacePath, "utf-8")));
74130
+ } catch {
74131
+ return {
74132
+ scope: "global",
74133
+ kind: "marketplace",
74134
+ path: marketplacePath,
74135
+ exists: true,
74136
+ status: "repairable",
74137
+ issues: ["codex-marketplace-unreadable"]
74138
+ };
74139
+ }
74140
+ const entry = asRecordArray(catalog?.plugins).find((plugin) => plugin.name === CODEX_PLUGIN_NAME);
74141
+ if (!entry) {
74142
+ return {
74143
+ scope: "global",
74144
+ kind: "marketplace",
74145
+ path: marketplacePath,
74146
+ exists: true,
74147
+ status: "repairable",
74148
+ issues: ["codex-marketplace-entry-missing"]
74149
+ };
74150
+ }
74151
+ const source = asRecord2(entry.source);
74152
+ const sourcePath = typeof source?.path === "string" ? source.path : "";
74153
+ const issues = source?.source === "local" && normalizeMarketplacePath(sourcePath) === ".codex/plugins/memorix" ? [] : ["codex-marketplace-entry-stale"];
74154
+ return {
74155
+ scope: "global",
74156
+ kind: "marketplace",
74157
+ path: marketplacePath,
74158
+ exists: true,
74159
+ status: issues.length > 0 ? "repairable" : "ok",
74160
+ issues
74161
+ };
74162
+ }
74163
+ function inspectCodexPluginRuntime() {
74164
+ const command = "codex plugin list --marketplace personal --available --json";
74165
+ const result = spawnSync2("codex", ["plugin", "list", "--marketplace", CODEX_PLUGIN_MARKETPLACE, "--available", "--json"], {
74166
+ encoding: "utf-8",
74167
+ stdio: "pipe",
74168
+ shell: process.platform === "win32"
74169
+ });
74170
+ if (result.error || result.status !== 0) {
74171
+ return {
74172
+ scope: "global",
74173
+ kind: "runtime",
74174
+ path: command,
74175
+ exists: false,
74176
+ status: "skipped",
74177
+ issues: ["codex-plugin-runtime-unavailable"]
74178
+ };
74179
+ }
74180
+ const runtime = parseCodexPluginList(String(result.stdout ?? ""));
74181
+ if (!runtime) {
74182
+ return {
74183
+ scope: "global",
74184
+ kind: "runtime",
74185
+ path: command,
74186
+ exists: true,
74187
+ status: "skipped",
74188
+ issues: ["codex-plugin-runtime-unreadable"]
74189
+ };
74190
+ }
74191
+ const issues = [];
74192
+ if (!runtime.installed) issues.push("codex-plugin-not-installed");
74193
+ else if (!runtime.enabled) issues.push("codex-plugin-disabled");
74194
+ return {
74195
+ scope: "global",
74196
+ kind: "runtime",
74197
+ path: command,
74198
+ exists: true,
74199
+ status: issues.length > 0 ? "repairable" : "ok",
74200
+ issues,
74201
+ runtime
74202
+ };
74203
+ }
74204
+ async function inspectCodexHookTrust() {
74205
+ const configPath = codexConfigPath();
74206
+ if (!existsSync23(configPath)) {
74207
+ return {
74208
+ scope: "global",
74209
+ kind: "hook-trust",
74210
+ path: configPath,
74211
+ exists: false,
74212
+ status: "skipped",
74213
+ issues: ["codex-hook-trust-unavailable"]
74214
+ };
74215
+ }
74216
+ let config2 = "";
74217
+ try {
74218
+ config2 = await readFile7(configPath, "utf-8");
74219
+ } catch {
74220
+ return {
74221
+ scope: "global",
74222
+ kind: "hook-trust",
74223
+ path: configPath,
74224
+ exists: true,
74225
+ status: "skipped",
74226
+ issues: ["codex-hook-trust-unreadable"]
74227
+ };
74228
+ }
74229
+ const trusted = CODEX_HOOK_STATE_NAMES.filter(
74230
+ (event) => config2.includes(`[hooks.state."${CODEX_PLUGIN_ID}:hooks/hooks.json:${event}:`)
74231
+ );
74232
+ const issues = trusted.length === CODEX_HOOK_STATE_NAMES.length ? [] : ["codex-hook-trust-pending"];
74233
+ return {
74234
+ scope: "global",
74235
+ kind: "hook-trust",
74236
+ path: configPath,
74237
+ exists: true,
74238
+ status: issues.length > 0 ? "repairable" : "ok",
74239
+ issues,
74240
+ hookTrust: { trusted, expected: [...CODEX_HOOK_STATE_NAMES] }
74241
+ };
74242
+ }
74243
+ function aggregatePluginStatus(checks) {
74244
+ if (checks.length === 0) return "skipped";
74245
+ return worstStatus(checks.map((check2) => check2.status));
74246
+ }
74247
+ function aggregatePluginIssues(checks) {
74248
+ const status = aggregatePluginStatus(checks);
74249
+ if (status === "ok") {
74250
+ return unique(checks.filter((check2) => check2.status === "skipped").flatMap((check2) => check2.issues));
74251
+ }
74252
+ if (status === "repairable") {
74253
+ return unique(checks.filter((check2) => check2.status === "repairable" || check2.status === "missing").flatMap((check2) => check2.issues));
74254
+ }
74255
+ return unique(checks.filter((check2) => check2.status === status).flatMap((check2) => check2.issues));
74256
+ }
74257
+ async function inspectPlugin(agent, scope) {
74258
+ if (agent !== "codex" || scope === "local" || scope === "project") {
74259
+ return { status: "skipped", issues: [], checks: [] };
74260
+ }
74261
+ const checks = [
74262
+ await inspectCodexPluginBundle(),
74263
+ await inspectCodexMarketplace(),
74264
+ inspectCodexPluginRuntime(),
74265
+ await inspectCodexHookTrust()
74266
+ ];
74267
+ return {
74268
+ status: aggregatePluginStatus(checks),
74269
+ issues: aggregatePluginIssues(checks),
74270
+ checks
74271
+ };
74272
+ }
73990
74273
  function looksLikeStaleMemorixCommand(server) {
73991
74274
  const text = [server.command, ...server.args ?? []].join(" ");
73992
74275
  return /[\\/]\.worktrees[\\/]/i.test(text) || /[\\/]dist[\\/]cli[\\/]index\.js/i.test(text);
@@ -74255,10 +74538,11 @@ async function inspectAgentIntegrations(options2 = {}) {
74255
74538
  entries.push({
74256
74539
  agent,
74257
74540
  mcp: await inspectMcp(agent, projectRoot, scope),
74258
- guidance: await inspectGuidance(agent, projectRoot, scope)
74541
+ guidance: await inspectGuidance(agent, projectRoot, scope),
74542
+ plugin: await inspectPlugin(agent, scope)
74259
74543
  });
74260
74544
  }
74261
- const entryStatuses = entries.map((entry) => worstStatus([entry.mcp.status, entry.guidance.status]));
74545
+ const entryStatuses = entries.map((entry) => worstStatus([entry.mcp.status, entry.guidance.status, entry.plugin.status]));
74262
74546
  return {
74263
74547
  projectRoot,
74264
74548
  scope,
@@ -74280,10 +74564,11 @@ function formatAgentIntegrationReport(report) {
74280
74564
  ""
74281
74565
  ];
74282
74566
  for (const entry of report.entries) {
74283
- const status = worstStatus([entry.mcp.status, entry.guidance.status]);
74567
+ const status = worstStatus([entry.mcp.status, entry.guidance.status, entry.plugin.status]);
74284
74568
  lines.push(`${entry.agent}: ${status}`);
74285
74569
  if (entry.mcp.issues.length > 0) lines.push(` MCP: ${entry.mcp.issues.join(", ")}`);
74286
74570
  if (entry.guidance.issues.length > 0) lines.push(` Guidance: ${entry.guidance.issues.join(", ")}`);
74571
+ if (entry.plugin.issues.length > 0) lines.push(` Plugin: ${entry.plugin.issues.join(", ")}`);
74287
74572
  }
74288
74573
  lines.push("");
74289
74574
  lines.push(`Repair: ${report.repairCommand}`);
@@ -74336,6 +74621,39 @@ async function repairAgentIntegrations(options2 = {}) {
74336
74621
  } else {
74337
74622
  skipped.push(`${entry.agent}:guidance`);
74338
74623
  }
74624
+ if (entry.agent === "codex" && entry.plugin.status !== "ok" && entry.plugin.status !== "skipped") {
74625
+ const bundleOrMarketplaceNeedsRepair = entry.plugin.checks.some(
74626
+ (check2) => (check2.kind === "bundle" || check2.kind === "marketplace") && check2.status !== "ok"
74627
+ );
74628
+ const runtime = entry.plugin.checks.find((check2) => check2.kind === "runtime");
74629
+ const hookTrust = entry.plugin.checks.find((check2) => check2.kind === "hook-trust");
74630
+ const needsInstall = runtime?.runtime?.installed === false;
74631
+ const needsManualEnable = runtime?.runtime?.installed === true && runtime.runtime.enabled === false;
74632
+ const needsHookTrust = hookTrust?.status === "repairable";
74633
+ const missingPluginFiles = entry.plugin.checks.some(
74634
+ (check2) => (check2.kind === "bundle" || check2.kind === "marketplace") && check2.status === "missing"
74635
+ );
74636
+ if (needsManualEnable) {
74637
+ skipped.push("codex:plugin:global:enable-in-plugin-browser");
74638
+ }
74639
+ if (needsHookTrust) {
74640
+ skipped.push("codex:plugin:global:review-hooks");
74641
+ }
74642
+ if (bundleOrMarketplaceNeedsRepair || needsInstall) {
74643
+ if ((missingPluginFiles || needsInstall) && !canInstallMissing) {
74644
+ skipped.push("codex:plugin:global:missing");
74645
+ } else {
74646
+ if (!options2.dry) {
74647
+ await installPluginPackage({ agent: "codex" });
74648
+ if (needsInstall) {
74649
+ const install = tryInstallCodexPlugin();
74650
+ if (!install.ok) skipped.push("codex:plugin:global:install-pending");
74651
+ }
74652
+ }
74653
+ changed.push("codex:plugin:global");
74654
+ }
74655
+ }
74656
+ }
74339
74657
  }
74340
74658
  return {
74341
74659
  projectRoot,
@@ -74366,13 +74684,14 @@ function formatAgentRepairResult(result) {
74366
74684
  }
74367
74685
  return lines.join("\n");
74368
74686
  }
74369
- var GUIDANCE_AGENTS;
74687
+ var GUIDANCE_AGENTS, CODEX_PLUGIN_NAME, CODEX_PLUGIN_MARKETPLACE, CODEX_PLUGIN_ID, CODEX_HOOK_EVENTS, CODEX_HOOK_STATE_NAMES;
74370
74688
  var init_agent_integrations = __esm({
74371
74689
  "src/cli/commands/agent-integrations.ts"() {
74372
74690
  "use strict";
74373
74691
  init_esm_shims();
74374
74692
  init_installers();
74375
74693
  init_setup();
74694
+ init_version();
74376
74695
  GUIDANCE_AGENTS = /* @__PURE__ */ new Set([
74377
74696
  "claude",
74378
74697
  "codex",
@@ -74385,6 +74704,11 @@ var init_agent_integrations = __esm({
74385
74704
  "opencode",
74386
74705
  "trae"
74387
74706
  ]);
74707
+ CODEX_PLUGIN_NAME = "memorix";
74708
+ CODEX_PLUGIN_MARKETPLACE = "personal";
74709
+ CODEX_PLUGIN_ID = `${CODEX_PLUGIN_NAME}@${CODEX_PLUGIN_MARKETPLACE}`;
74710
+ CODEX_HOOK_EVENTS = ["SessionStart", "UserPromptSubmit", "PostToolUse", "PreCompact", "Stop"];
74711
+ CODEX_HOOK_STATE_NAMES = ["session_start", "user_prompt_submit", "post_tool_use", "pre_compact", "stop"];
74388
74712
  }
74389
74713
  });
74390
74714