memax-cli 0.1.0-alpha.9 → 0.1.0

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 (197) hide show
  1. package/assets/skills/memax-memory/SKILL.md +173 -0
  2. package/dist/commands/agent-configs.d.ts +41 -0
  3. package/dist/commands/agent-configs.d.ts.map +1 -0
  4. package/dist/commands/agent-configs.js +1290 -0
  5. package/dist/commands/agent-configs.js.map +1 -0
  6. package/dist/commands/agent-configs.test.d.ts +2 -0
  7. package/dist/commands/agent-configs.test.d.ts.map +1 -0
  8. package/dist/commands/agent-configs.test.js +122 -0
  9. package/dist/commands/agent-configs.test.js.map +1 -0
  10. package/dist/commands/agent-sessions.d.ts +74 -0
  11. package/dist/commands/agent-sessions.d.ts.map +1 -0
  12. package/dist/commands/agent-sessions.js +1513 -0
  13. package/dist/commands/agent-sessions.js.map +1 -0
  14. package/dist/commands/agent-sessions.test.d.ts +2 -0
  15. package/dist/commands/agent-sessions.test.d.ts.map +1 -0
  16. package/dist/commands/agent-sessions.test.js +255 -0
  17. package/dist/commands/agent-sessions.test.js.map +1 -0
  18. package/dist/commands/agents.d.ts +3 -0
  19. package/dist/commands/agents.d.ts.map +1 -0
  20. package/dist/commands/agents.js +36 -0
  21. package/dist/commands/agents.js.map +1 -0
  22. package/dist/commands/ask.d.ts +15 -0
  23. package/dist/commands/ask.d.ts.map +1 -0
  24. package/dist/commands/ask.js +483 -0
  25. package/dist/commands/ask.js.map +1 -0
  26. package/dist/commands/auth.d.ts +7 -0
  27. package/dist/commands/auth.d.ts.map +1 -1
  28. package/dist/commands/auth.js +103 -8
  29. package/dist/commands/auth.js.map +1 -1
  30. package/dist/commands/capture.d.ts +19 -0
  31. package/dist/commands/capture.d.ts.map +1 -0
  32. package/dist/commands/capture.js +69 -0
  33. package/dist/commands/capture.js.map +1 -0
  34. package/dist/commands/config.d.ts +2 -0
  35. package/dist/commands/config.d.ts.map +1 -1
  36. package/dist/commands/config.js +13 -0
  37. package/dist/commands/config.js.map +1 -1
  38. package/dist/commands/delete.d.ts +2 -0
  39. package/dist/commands/delete.d.ts.map +1 -1
  40. package/dist/commands/delete.js +15 -18
  41. package/dist/commands/delete.js.map +1 -1
  42. package/dist/commands/dreams.d.ts +22 -0
  43. package/dist/commands/dreams.d.ts.map +1 -0
  44. package/dist/commands/dreams.js +251 -0
  45. package/dist/commands/dreams.js.map +1 -0
  46. package/dist/commands/dreams.test.d.ts +2 -0
  47. package/dist/commands/dreams.test.d.ts.map +1 -0
  48. package/dist/commands/dreams.test.js +39 -0
  49. package/dist/commands/dreams.test.js.map +1 -0
  50. package/dist/commands/hook.d.ts +2 -0
  51. package/dist/commands/hook.d.ts.map +1 -1
  52. package/dist/commands/hook.js +25 -103
  53. package/dist/commands/hook.js.map +1 -1
  54. package/dist/commands/hub.d.ts +37 -0
  55. package/dist/commands/hub.d.ts.map +1 -0
  56. package/dist/commands/hub.js +347 -0
  57. package/dist/commands/hub.js.map +1 -0
  58. package/dist/commands/hub.test.d.ts +2 -0
  59. package/dist/commands/hub.test.d.ts.map +1 -0
  60. package/dist/commands/hub.test.js +62 -0
  61. package/dist/commands/hub.test.js.map +1 -0
  62. package/dist/commands/import.d.ts +13 -0
  63. package/dist/commands/import.d.ts.map +1 -0
  64. package/dist/commands/import.js +257 -0
  65. package/dist/commands/import.js.map +1 -0
  66. package/dist/commands/import.test.d.ts +2 -0
  67. package/dist/commands/import.test.d.ts.map +1 -0
  68. package/dist/commands/import.test.js +11 -0
  69. package/dist/commands/import.test.js.map +1 -0
  70. package/dist/commands/list.d.ts +9 -2
  71. package/dist/commands/list.d.ts.map +1 -1
  72. package/dist/commands/list.js +118 -9
  73. package/dist/commands/list.js.map +1 -1
  74. package/dist/commands/list.test.d.ts +2 -0
  75. package/dist/commands/list.test.d.ts.map +1 -0
  76. package/dist/commands/list.test.js +20 -0
  77. package/dist/commands/list.test.js.map +1 -0
  78. package/dist/commands/login.d.ts +7 -1
  79. package/dist/commands/login.d.ts.map +1 -1
  80. package/dist/commands/login.js +81 -20
  81. package/dist/commands/login.js.map +1 -1
  82. package/dist/commands/mcp.d.ts.map +1 -1
  83. package/dist/commands/mcp.js +386 -65
  84. package/dist/commands/mcp.js.map +1 -1
  85. package/dist/commands/push.d.ts +6 -1
  86. package/dist/commands/push.d.ts.map +1 -1
  87. package/dist/commands/push.js +42 -8
  88. package/dist/commands/push.js.map +1 -1
  89. package/dist/commands/recall.d.ts +11 -1
  90. package/dist/commands/recall.d.ts.map +1 -1
  91. package/dist/commands/recall.js +228 -41
  92. package/dist/commands/recall.js.map +1 -1
  93. package/dist/commands/recall.test.d.ts +2 -0
  94. package/dist/commands/recall.test.d.ts.map +1 -0
  95. package/dist/commands/recall.test.js +31 -0
  96. package/dist/commands/recall.test.js.map +1 -0
  97. package/dist/commands/setup-hooks.d.ts +13 -0
  98. package/dist/commands/setup-hooks.d.ts.map +1 -0
  99. package/dist/commands/setup-hooks.js +193 -0
  100. package/dist/commands/setup-hooks.js.map +1 -0
  101. package/dist/commands/setup-instructions.d.ts +21 -0
  102. package/dist/commands/setup-instructions.d.ts.map +1 -0
  103. package/dist/commands/setup-instructions.js +172 -0
  104. package/dist/commands/setup-instructions.js.map +1 -0
  105. package/dist/commands/setup-mcp.d.ts +40 -0
  106. package/dist/commands/setup-mcp.d.ts.map +1 -0
  107. package/dist/commands/setup-mcp.js +414 -0
  108. package/dist/commands/setup-mcp.js.map +1 -0
  109. package/dist/commands/setup-types.d.ts +33 -0
  110. package/dist/commands/setup-types.d.ts.map +1 -0
  111. package/dist/commands/setup-types.js +60 -0
  112. package/dist/commands/setup-types.js.map +1 -0
  113. package/dist/commands/setup.d.ts +10 -1
  114. package/dist/commands/setup.d.ts.map +1 -1
  115. package/dist/commands/setup.js +216 -534
  116. package/dist/commands/setup.js.map +1 -1
  117. package/dist/commands/show.d.ts +5 -1
  118. package/dist/commands/show.d.ts.map +1 -1
  119. package/dist/commands/show.js +36 -14
  120. package/dist/commands/show.js.map +1 -1
  121. package/dist/commands/topic.d.ts +32 -0
  122. package/dist/commands/topic.d.ts.map +1 -0
  123. package/dist/commands/topic.js +265 -0
  124. package/dist/commands/topic.js.map +1 -0
  125. package/dist/commands/topic.test.d.ts +2 -0
  126. package/dist/commands/topic.test.d.ts.map +1 -0
  127. package/dist/commands/topic.test.js +114 -0
  128. package/dist/commands/topic.test.js.map +1 -0
  129. package/dist/index.js +35 -144
  130. package/dist/index.js.map +1 -1
  131. package/dist/lib/client.d.ts +10 -0
  132. package/dist/lib/client.d.ts.map +1 -0
  133. package/dist/lib/client.js +104 -0
  134. package/dist/lib/client.js.map +1 -0
  135. package/dist/lib/client.test.d.ts +2 -0
  136. package/dist/lib/client.test.d.ts.map +1 -0
  137. package/dist/lib/client.test.js +44 -0
  138. package/dist/lib/client.test.js.map +1 -0
  139. package/dist/lib/config.d.ts +43 -0
  140. package/dist/lib/config.d.ts.map +1 -1
  141. package/dist/lib/config.js +72 -1
  142. package/dist/lib/config.js.map +1 -1
  143. package/dist/lib/credentials.d.ts +3 -0
  144. package/dist/lib/credentials.d.ts.map +1 -1
  145. package/dist/lib/credentials.js +24 -2
  146. package/dist/lib/credentials.js.map +1 -1
  147. package/dist/lib/hubs.d.ts +7 -0
  148. package/dist/lib/hubs.d.ts.map +1 -0
  149. package/dist/lib/hubs.js +33 -0
  150. package/dist/lib/hubs.js.map +1 -0
  151. package/dist/lib/hubs.test.d.ts +2 -0
  152. package/dist/lib/hubs.test.d.ts.map +1 -0
  153. package/dist/lib/hubs.test.js +58 -0
  154. package/dist/lib/hubs.test.js.map +1 -0
  155. package/dist/lib/project-context.d.ts +56 -0
  156. package/dist/lib/project-context.d.ts.map +1 -0
  157. package/dist/lib/project-context.js +225 -0
  158. package/dist/lib/project-context.js.map +1 -0
  159. package/dist/lib/project-context.test.d.ts +2 -0
  160. package/dist/lib/project-context.test.d.ts.map +1 -0
  161. package/dist/lib/project-context.test.js +75 -0
  162. package/dist/lib/project-context.test.js.map +1 -0
  163. package/dist/lib/prompt.d.ts +7 -0
  164. package/dist/lib/prompt.d.ts.map +1 -0
  165. package/dist/lib/prompt.js +41 -0
  166. package/dist/lib/prompt.js.map +1 -0
  167. package/dist/lib/trash.d.ts +6 -0
  168. package/dist/lib/trash.d.ts.map +1 -0
  169. package/dist/lib/trash.js +28 -0
  170. package/dist/lib/trash.js.map +1 -0
  171. package/package.json +17 -13
  172. package/.vscode/mcp.json +0 -8
  173. package/dist/commands/sync.d.ts +0 -12
  174. package/dist/commands/sync.d.ts.map +0 -1
  175. package/dist/commands/sync.js +0 -414
  176. package/dist/commands/sync.js.map +0 -1
  177. package/dist/lib/api.d.ts +0 -4
  178. package/dist/lib/api.d.ts.map +0 -1
  179. package/dist/lib/api.js +0 -95
  180. package/dist/lib/api.js.map +0 -1
  181. package/src/commands/auth.ts +0 -92
  182. package/src/commands/config.ts +0 -27
  183. package/src/commands/delete.ts +0 -58
  184. package/src/commands/hook.ts +0 -243
  185. package/src/commands/list.ts +0 -38
  186. package/src/commands/login.ts +0 -164
  187. package/src/commands/mcp.ts +0 -405
  188. package/src/commands/push.ts +0 -137
  189. package/src/commands/recall.ts +0 -163
  190. package/src/commands/setup.ts +0 -1077
  191. package/src/commands/show.ts +0 -35
  192. package/src/commands/sync.ts +0 -506
  193. package/src/index.ts +0 -213
  194. package/src/lib/api.ts +0 -110
  195. package/src/lib/config.ts +0 -61
  196. package/src/lib/credentials.ts +0 -42
  197. package/tsconfig.json +0 -9
@@ -1,13 +1,29 @@
1
1
  import chalk from "chalk";
2
- import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync, } from "node:fs";
3
- import { join, dirname } from "node:path";
4
- import { homedir, platform } from "node:os";
2
+ import { existsSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { homedir } from "node:os";
5
5
  import { execSync } from "node:child_process";
6
- import { apiPost } from "../lib/api.js";
7
- import { loadConfig } from "../lib/config.js";
6
+ import { createInterface } from "node:readline";
7
+ import { commandExists, resolveMemaxBin, } from "./setup-types.js";
8
+ import { ensureApiKey, ensureLocalAgentKey, setupMcpRemote, setupMcpOAuth, setupMcp, printMcpConfigs, removeMcpJson, removeMcpToml, } from "./setup-mcp.js";
9
+ import { setupHooks, removeHooks } from "./setup-hooks.js";
10
+ import { injectInstructions, removeInstructions, installSkills, removeSkills, } from "./setup-instructions.js";
11
+ // --- Agent definitions ---
8
12
  function getAgents() {
9
13
  const home = homedir();
10
14
  const cwd = process.cwd();
15
+ // Helper: standard { type: "url", url, headers? } shape used by Cursor, Windsurf, OpenClaw
16
+ const stdUrlEntry = (url, headers) => ({
17
+ type: "url",
18
+ url,
19
+ ...(headers ? { headers } : {}),
20
+ });
21
+ // Helper: { type: "http", url, headers? } shape used by VS Code, Copilot CLI
22
+ const httpEntry = (url, headers) => ({
23
+ type: "http",
24
+ url,
25
+ ...(headers ? { headers } : {}),
26
+ });
11
27
  return [
12
28
  {
13
29
  name: "Claude Code",
@@ -18,6 +34,8 @@ function getAgents() {
18
34
  hasHooks: true,
19
35
  globalInstructionFile: join(home, ".claude", "CLAUDE.md"),
20
36
  detect: () => existsSync(join(home, ".claude")) || commandExists("claude"),
37
+ // Claude Code uses `claude mcp add` CLI, not JSON config — this is a fallback
38
+ remoteEntry: stdUrlEntry,
21
39
  },
22
40
  {
23
41
  name: "Cursor",
@@ -26,8 +44,9 @@ function getAgents() {
26
44
  format: "json-mcpServers",
27
45
  mcpKey: "mcpServers",
28
46
  hasHooks: false,
29
- globalInstructionFile: null, // project-level .cursorrules only
47
+ globalInstructionFile: null,
30
48
  detect: () => existsSync(join(home, ".cursor")) || commandExists("cursor"),
49
+ remoteEntry: stdUrlEntry,
31
50
  },
32
51
  {
33
52
  name: "Windsurf",
@@ -36,9 +55,10 @@ function getAgents() {
36
55
  format: "json-mcpServers",
37
56
  mcpKey: "mcpServers",
38
57
  hasHooks: false,
39
- globalInstructionFile: null, // project-level .windsurfrules only
58
+ globalInstructionFile: null,
40
59
  detect: () => existsSync(join(home, ".codeium", "windsurf")) ||
41
60
  commandExists("windsurf"),
61
+ remoteEntry: stdUrlEntry,
42
62
  },
43
63
  {
44
64
  name: "Gemini CLI",
@@ -49,6 +69,11 @@ function getAgents() {
49
69
  hasHooks: true,
50
70
  globalInstructionFile: join(home, ".gemini", "GEMINI.md"),
51
71
  detect: () => existsSync(join(home, ".gemini")) || commandExists("gemini"),
72
+ // Gemini CLI uses httpUrl for streamable HTTP; url is its SSE field
73
+ remoteEntry: (url, headers) => ({
74
+ httpUrl: url,
75
+ ...(headers ? { headers } : {}),
76
+ }),
52
77
  },
53
78
  {
54
79
  name: "GitHub Copilot CLI",
@@ -57,8 +82,20 @@ function getAgents() {
57
82
  format: "json-mcpServers",
58
83
  mcpKey: "mcpServers",
59
84
  hasHooks: false,
60
- globalInstructionFile: null, // uses .github/copilot-instructions.md (project-level)
85
+ globalInstructionFile: null,
61
86
  detect: () => existsSync(join(home, ".copilot")) || commandExists("gh copilot"),
87
+ // Copilot CLI requires type + url + tools for both remote and local servers
88
+ remoteEntry: (url, headers) => ({
89
+ type: "http",
90
+ url,
91
+ tools: [{ type: "function" }],
92
+ ...(headers ? { headers } : {}),
93
+ }),
94
+ localEntry: (command, args) => ({
95
+ command,
96
+ args,
97
+ tools: [{ type: "function" }],
98
+ }),
62
99
  },
63
100
  {
64
101
  name: "Copilot (VS Code)",
@@ -69,6 +106,8 @@ function getAgents() {
69
106
  hasHooks: false,
70
107
  globalInstructionFile: null,
71
108
  detect: () => existsSync(".vscode") || commandExists("code"),
109
+ // VS Code uses type: "http" for remote MCP servers
110
+ remoteEntry: httpEntry,
72
111
  },
73
112
  {
74
113
  name: "Codex CLI",
@@ -79,6 +118,8 @@ function getAgents() {
79
118
  hasHooks: false,
80
119
  globalInstructionFile: join(home, ".codex", "AGENTS.md"),
81
120
  detect: () => existsSync(join(home, ".codex")) || commandExists("codex"),
121
+ // Codex TOML is handled separately; this is for JSON fallback reference
122
+ remoteEntry: stdUrlEntry,
82
123
  },
83
124
  {
84
125
  name: "OpenClaw",
@@ -87,8 +128,9 @@ function getAgents() {
87
128
  format: "json-mcpServers",
88
129
  mcpKey: "mcp.servers",
89
130
  hasHooks: false,
90
- globalInstructionFile: null, // OpenClaw has its own memory system
131
+ globalInstructionFile: null,
91
132
  detect: () => existsSync(join(home, ".openclaw")) || commandExists("openclaw"),
133
+ remoteEntry: stdUrlEntry,
92
134
  },
93
135
  {
94
136
  name: "OpenCode",
@@ -97,8 +139,19 @@ function getAgents() {
97
139
  format: "json-mcpServers",
98
140
  mcpKey: "mcp",
99
141
  hasHooks: false,
100
- globalInstructionFile: null, // project-level only
142
+ globalInstructionFile: null,
101
143
  detect: () => existsSync(join(cwd, ".opencode")) || commandExists("opencode"),
144
+ // OpenCode uses type: "remote" for remote, type: "local" for local
145
+ remoteEntry: (url, headers) => ({
146
+ type: "remote",
147
+ url,
148
+ ...(headers ? { headers } : {}),
149
+ }),
150
+ localEntry: (command, args) => ({
151
+ type: "local",
152
+ command,
153
+ args,
154
+ }),
102
155
  },
103
156
  ];
104
157
  }
@@ -110,22 +163,50 @@ export async function setupCommand(options) {
110
163
  printUsage();
111
164
  return;
112
165
  }
166
+ if (options.hub && options.agentSync) {
167
+ console.error(chalk.red("\n --agent-sync cannot be combined with --hub because hub-scoped MCP keys are restricted to that hub only.\n"));
168
+ process.exit(1);
169
+ }
170
+ // Hub scoping requires API key mode — OAuth grants are configured during
171
+ // the consent screen, not at setup time.
172
+ if (options.hub && !options.apiKey) {
173
+ console.error(chalk.red("\n --hub requires --api-key because hub scoping is configured per API key.\n Use: memax setup --mcp --api-key --hub <id>\n"));
174
+ process.exit(1);
175
+ }
176
+ // Permission flags only apply to remote API key mode — reject in OAuth and local mode
177
+ const permissionFlags = [
178
+ options.readOnly && "--read-only",
179
+ options.allowDelete && "--allow-delete",
180
+ options.allowOrganize && "--allow-organize",
181
+ options.agentSync && "--agent-sync",
182
+ ].filter(Boolean);
183
+ if (permissionFlags.length > 0 && (!options.apiKey || options.local)) {
184
+ console.error(chalk.red(`\n ${permissionFlags.join(", ")} only apply to remote API key mode.\n Use: memax setup --mcp --api-key ${permissionFlags.join(" ")}\n`));
185
+ process.exit(1);
186
+ }
187
+ // --api-key is meaningless with --local
188
+ if (options.apiKey && options.local) {
189
+ console.error(chalk.red("\n --api-key and --local are mutually exclusive.\n Use --api-key for remote API key mode, or --local for local CLI mode.\n"));
190
+ process.exit(1);
191
+ }
113
192
  // --print: just output config JSON for manual copy/paste
114
193
  if (options.print) {
115
- await printMcpConfigs(options.local ?? false);
194
+ await printMcpConfigs({
195
+ local: options.local ?? false,
196
+ apiKey: options.apiKey ?? false,
197
+ hub: options.hub,
198
+ readOnly: options.readOnly,
199
+ allowDelete: options.allowDelete,
200
+ allowOrganize: options.allowOrganize,
201
+ agentSync: options.agentSync,
202
+ });
116
203
  return;
117
204
  }
118
- // Remote mode (default): need API key for auth
205
+ // Remote mode (default): OAuth auto-discovery (no API key in config)
206
+ // --api-key: use per-agent API keys (legacy mode, for CI/CD or agents without OAuth)
207
+ // --local: use local CLI binary (memax mcp serve)
119
208
  const useRemote = !options.local;
120
- let apiKey;
121
- if (useRemote && enableMcp) {
122
- apiKey = await ensureApiKey();
123
- if (!apiKey) {
124
- console.error(chalk.red("\n Could not create API key. Log in first: memax login\n" +
125
- " Or use --local for local MCP server.\n"));
126
- process.exit(1);
127
- }
128
- }
209
+ const useApiKey = options.apiKey ?? false;
129
210
  // Local mode: need memax binary
130
211
  let memaxBin = null;
131
212
  if (!useRemote || enableHooks) {
@@ -160,8 +241,11 @@ export async function setupCommand(options) {
160
241
  return;
161
242
  }
162
243
  console.log(chalk.bold("\n Memax Setup\n"));
163
- if (useRemote) {
164
- console.log(chalk.gray(" Mode: remote server (recommended)\n"));
244
+ if (useRemote && useApiKey) {
245
+ console.log(chalk.gray(" Mode: remote server (API key)\n"));
246
+ }
247
+ else if (useRemote) {
248
+ console.log(chalk.gray(" Mode: remote server (OAuth)\n"));
165
249
  }
166
250
  else {
167
251
  console.log(chalk.gray(" Mode: local CLI\n"));
@@ -169,16 +253,38 @@ export async function setupCommand(options) {
169
253
  const results = [];
170
254
  for (const agent of agents) {
171
255
  const changes = [];
172
- // MCP setup
256
+ // MCP setup — OAuth (default), API key (--api-key), or local (--local)
173
257
  if (enableMcp) {
174
258
  try {
175
- if (useRemote) {
176
- setupMcpRemote(agent, apiKey);
259
+ if (useRemote && useApiKey) {
260
+ // Legacy API key mode — creates per-agent key with agent_name
261
+ const agentKey = await ensureApiKey(options.hub, agent.id, {
262
+ readOnly: options.readOnly,
263
+ allowDelete: options.allowDelete,
264
+ allowOrganize: options.allowOrganize,
265
+ agentSync: options.agentSync,
266
+ });
267
+ if (!agentKey) {
268
+ console.error(chalk.red(` ✗ ${agent.name}: Could not create API key. Run: memax login`));
269
+ continue;
270
+ }
271
+ setupMcpRemote(agent, agentKey);
272
+ changes.push("MCP server (API key)");
273
+ }
274
+ else if (useRemote) {
275
+ // OAuth mode (default) — no API key in config, agent auto-discovers auth
276
+ setupMcpOAuth(agent);
277
+ changes.push("MCP server (OAuth)");
177
278
  }
178
279
  else {
280
+ const localAgentKey = await ensureLocalAgentKey(agent.id);
281
+ if (!localAgentKey) {
282
+ console.error(chalk.red(` ✗ ${agent.name}: Could not provision local agent key. Run: memax login`));
283
+ continue;
284
+ }
179
285
  setupMcp(agent, memaxBin);
286
+ changes.push("MCP server (local agent auth)");
180
287
  }
181
- changes.push(useRemote ? "MCP server (remote)" : "MCP server (local)");
182
288
  }
183
289
  catch (err) {
184
290
  console.log(chalk.red(` ✗ ${agent.name}: MCP setup failed — ${err.message}`));
@@ -203,6 +309,16 @@ export async function setupCommand(options) {
203
309
  catch (err) {
204
310
  console.log(chalk.red(` ✗ ${agent.name}: Instruction injection failed — ${err.message}`));
205
311
  }
312
+ // Install memax skills for agents that support skill directories
313
+ try {
314
+ const skillCount = await installSkills(agent);
315
+ if (skillCount > 0) {
316
+ changes.push(`${skillCount} skill${skillCount > 1 ? "s" : ""} installed`);
317
+ }
318
+ }
319
+ catch (err) {
320
+ console.log(chalk.red(` ✗ ${agent.name}: Skill install failed — ${err.message}`));
321
+ }
206
322
  }
207
323
  if (changes.length > 0) {
208
324
  results.push({ agent: agent.name, changes });
@@ -223,8 +339,8 @@ export async function setupCommand(options) {
223
339
  console.log(chalk.gray("\n MCP tools available to all configured agents:"));
224
340
  console.log(chalk.gray(" • memax_recall — semantic search your knowledge"));
225
341
  console.log(chalk.gray(" • memax_push — save knowledge from sessions"));
226
- console.log(chalk.gray(" • memax_get — read full note by ID"));
227
- console.log(chalk.gray(" • memax_search — browse notes by category"));
342
+ console.log(chalk.gray(" • memax_get — read full memory by ID"));
343
+ console.log(chalk.gray(" • memax_list — browse memories"));
228
344
  if (enableHooks) {
229
345
  const hookAgents = results.filter((r) => r.changes.includes("Context injection hook"));
230
346
  if (hookAgents.length > 0) {
@@ -232,8 +348,32 @@ export async function setupCommand(options) {
232
348
  console.log(chalk.gray(" Every prompt gets relevant context injected automatically."));
233
349
  }
234
350
  }
235
- console.log(chalk.gray("\n Restart your agents for changes to take effect.\n"));
351
+ console.log(chalk.gray("\n Restart your agents for changes to take effect."));
352
+ // Offer to restore configs from cloud if this looks like a new device
353
+ if (enableInstructions || options.all) {
354
+ try {
355
+ const { syncAgentMemoryCommand } = await import("./agent-configs.js");
356
+ const rl = createInterface({
357
+ input: process.stdin,
358
+ output: process.stdout,
359
+ });
360
+ const restore = await new Promise((resolve) => {
361
+ rl.question(chalk.gray("\n Restore agent configs from Memax cloud? [Y/n] "), (answer) => {
362
+ rl.close();
363
+ resolve(answer.trim().toLowerCase() !== "n");
364
+ });
365
+ });
366
+ if (restore) {
367
+ await syncAgentMemoryCommand({ skipConflicts: true });
368
+ }
369
+ }
370
+ catch {
371
+ // Sync not available (not logged in, etc.) — skip silently
372
+ }
373
+ }
374
+ console.log();
236
375
  }
376
+ // --- Teardown command ---
237
377
  export async function teardownCommand(options) {
238
378
  const allAgents = getAgents();
239
379
  const onlySet = options.only
@@ -248,13 +388,19 @@ export async function teardownCommand(options) {
248
388
  // Claude Code uses its own CLI
249
389
  if (agent.id === "claude-code") {
250
390
  if (commandExists("claude")) {
251
- try {
252
- execSync("claude mcp remove memax", { stdio: "pipe" });
253
- console.log(chalk.gray(` Removed MCP from ${agent.name}`));
254
- removed = true;
255
- }
256
- catch {
257
- // Not installed
391
+ // Remove from both user and project scope to clean up old
392
+ // (pre-scope) and new (user-scoped) installs
393
+ for (const scope of ["--scope user", ""]) {
394
+ try {
395
+ execSync(`claude mcp remove memax ${scope}`.trim(), {
396
+ stdio: "pipe",
397
+ });
398
+ console.log(chalk.gray(` Removed MCP from ${agent.name}${scope ? " (user scope)" : " (project scope)"}`));
399
+ removed = true;
400
+ }
401
+ catch {
402
+ // Not installed in this scope
403
+ }
258
404
  }
259
405
  }
260
406
  if (agent.hasHooks && existsSync(agent.configPath)) {
@@ -285,6 +431,10 @@ export async function teardownCommand(options) {
285
431
  console.log(chalk.gray(` Removed instructions from ${agent.name}`));
286
432
  removed = true;
287
433
  }
434
+ if (removeSkills(agent)) {
435
+ console.log(chalk.gray(` Removed skills from ${agent.name}`));
436
+ removed = true;
437
+ }
288
438
  }
289
439
  catch {
290
440
  // Skip agents we can't clean up
@@ -296,482 +446,7 @@ export async function teardownCommand(options) {
296
446
  }
297
447
  console.log(chalk.green("\n Memax integrations removed.\n Restart your agents for changes to take effect.\n"));
298
448
  }
299
- // --- Remote MCP setup ---
300
- async function ensureApiKey() {
301
- try {
302
- const result = await apiPost("/v1/auth/api-keys", {
303
- name: "mcp-setup",
304
- expires_in_days: 0, // no expiry
305
- });
306
- return result.key;
307
- }
308
- catch {
309
- return undefined;
310
- }
311
- }
312
- function getApiUrl() {
313
- return loadConfig().api_url;
314
- }
315
- function setupMcpRemote(agent, apiKey) {
316
- const mcpUrl = `${getApiUrl()}/mcp`;
317
- // Claude Code uses its own CLI
318
- if (agent.id === "claude-code") {
319
- if (!commandExists("claude")) {
320
- throw new Error("claude CLI not found in PATH");
321
- }
322
- try {
323
- execSync("claude mcp remove memax", { stdio: "pipe" });
324
- }
325
- catch {
326
- // Not installed yet
327
- }
328
- // Claude Code HTTP transport
329
- execSync(`claude mcp add memax --transport http ${mcpUrl} --header "Authorization: Bearer ${apiKey}"`, { stdio: "pipe" });
330
- return;
331
- }
332
- // Codex TOML
333
- if (agent.format === "toml") {
334
- mkdirSync(dirname(agent.configPath), { recursive: true });
335
- let content = "";
336
- if (existsSync(agent.configPath)) {
337
- content = readFileSync(agent.configPath, "utf-8");
338
- }
339
- content = content.replace(/\[mcp_servers\.memax\][\s\S]*?(?=\n\[|$)/, "");
340
- content = content.trim();
341
- if (content)
342
- content += "\n\n";
343
- content += `[mcp_servers.memax]\ntype = "url"\nurl = "${mcpUrl}"\n\n[mcp_servers.memax.headers]\nAuthorization = "Bearer ${apiKey}"\n`;
344
- writeFileSync(agent.configPath, content);
345
- return;
346
- }
347
- // JSON-based agents
348
- mkdirSync(dirname(agent.configPath), { recursive: true });
349
- let config = {};
350
- if (existsSync(agent.configPath)) {
351
- try {
352
- config = JSON.parse(readFileSync(agent.configPath, "utf-8"));
353
- }
354
- catch {
355
- // Start fresh
356
- }
357
- }
358
- const servers = (getNestedKey(config, agent.mcpKey) ?? {});
359
- // Copilot CLI uses "http", others use "url" or no type field
360
- const mcpType = agent.id === "copilot" ? "http" : "url";
361
- servers.memax = {
362
- type: mcpType,
363
- url: mcpUrl,
364
- headers: {
365
- Authorization: `Bearer ${apiKey}`,
366
- },
367
- };
368
- setNestedKey(config, agent.mcpKey, servers);
369
- writeFileSync(agent.configPath, JSON.stringify(config, null, 2) + "\n");
370
- }
371
- async function printMcpConfigs(local) {
372
- const apiUrl = getApiUrl();
373
- console.log(chalk.bold("\n Memax MCP Configuration\n"));
374
- if (local) {
375
- const bin = resolveMemaxBin();
376
- const cmd = bin ? bin.command : "memax";
377
- const args = bin ? [...bin.args, "mcp", "serve"] : ["mcp", "serve"];
378
- console.log(chalk.gray(" Mode: local (stdio)\n"));
379
- console.log(chalk.white(" For most agents (Claude Code, Cursor, Gemini, etc.):\n"));
380
- console.log(JSON.stringify({
381
- mcpServers: {
382
- memax: { command: cmd, args },
383
- },
384
- }, null, 2)
385
- .split("\n")
386
- .map((l) => " " + l)
387
- .join("\n"));
388
- }
389
- else {
390
- let apiKey;
391
- try {
392
- apiKey = await ensureApiKey();
393
- }
394
- catch {
395
- // Not logged in
396
- }
397
- const keyDisplay = apiKey ?? "mxk_your_api_key_here";
398
- const mcpUrl = `${apiUrl}/mcp`;
399
- console.log(chalk.gray(" Mode: remote server (recommended)\n"));
400
- console.log(chalk.white(" For Claude Code:\n"));
401
- console.log(chalk.gray(` claude mcp add memax --transport http ${mcpUrl} --header "Authorization: Bearer ${keyDisplay}"`));
402
- console.log(chalk.white("\n For Cursor, Copilot, Gemini, Windsurf:\n"));
403
- console.log(JSON.stringify({
404
- mcpServers: {
405
- memax: {
406
- type: "url",
407
- url: mcpUrl,
408
- headers: {
409
- Authorization: `Bearer ${keyDisplay}`,
410
- },
411
- },
412
- },
413
- }, null, 2)
414
- .split("\n")
415
- .map((l) => " " + l)
416
- .join("\n"));
417
- console.log(chalk.white("\n For Codex CLI (~/.codex/config.toml):\n"));
418
- console.log(chalk.gray(` [mcp_servers.memax]`));
419
- console.log(chalk.gray(` type = "url"`));
420
- console.log(chalk.gray(` url = "${mcpUrl}"`));
421
- console.log(chalk.gray(`\n [mcp_servers.memax.headers]`));
422
- console.log(chalk.gray(` Authorization = "Bearer ${keyDisplay}"`));
423
- if (apiKey) {
424
- console.log(chalk.yellow("\n API key created: mcp-setup"));
425
- console.log(chalk.gray(" Manage keys: memax auth list-keys"));
426
- }
427
- else {
428
- console.log(chalk.yellow("\n Not logged in — replace mxk_your_api_key_here with a real key."));
429
- console.log(chalk.gray(" Run: memax login && memax auth create-key --name mcp"));
430
- }
431
- }
432
- console.log();
433
- }
434
- // --- Local MCP setup per agent ---
435
- function setupMcp(agent, bin) {
436
- // Claude Code has its own CLI for MCP management
437
- if (agent.id === "claude-code") {
438
- setupMcpClaudeCode(bin);
439
- return;
440
- }
441
- mkdirSync(dirname(agent.configPath), { recursive: true });
442
- if (agent.format === "toml") {
443
- setupMcpToml(agent, bin);
444
- return;
445
- }
446
- // JSON-based agents
447
- let config = {};
448
- if (existsSync(agent.configPath)) {
449
- try {
450
- config = JSON.parse(readFileSync(agent.configPath, "utf-8"));
451
- }
452
- catch {
453
- // Start fresh
454
- }
455
- }
456
- const servers = (getNestedKey(config, agent.mcpKey) ?? {});
457
- servers.memax = {
458
- command: bin.command,
459
- args: [...bin.args, "mcp", "serve"],
460
- };
461
- setNestedKey(config, agent.mcpKey, servers);
462
- writeFileSync(agent.configPath, JSON.stringify(config, null, 2) + "\n");
463
- }
464
- function setupMcpClaudeCode(bin) {
465
- // Claude Code uses its own CLI for MCP — settings.json mcpServers is ignored
466
- if (!commandExists("claude")) {
467
- throw new Error("claude CLI not found in PATH");
468
- }
469
- // Remove existing first (idempotent)
470
- try {
471
- execSync("claude mcp remove memax", { stdio: "pipe" });
472
- }
473
- catch {
474
- // Not installed yet — fine
475
- }
476
- // claude mcp add <name> -- <command> [args...]
477
- const allArgs = [...bin.args, "mcp", "serve"];
478
- const cmd = `claude mcp add memax -- ${bin.command} ${allArgs.join(" ")}`;
479
- try {
480
- execSync(cmd, { stdio: "pipe" });
481
- }
482
- catch (err) {
483
- throw new Error(`claude mcp add failed: ${err.message}`);
484
- }
485
- }
486
- function setupMcpToml(agent, bin) {
487
- // Codex uses TOML — append or update the memax section
488
- let content = "";
489
- if (existsSync(agent.configPath)) {
490
- content = readFileSync(agent.configPath, "utf-8");
491
- }
492
- // Remove existing memax section if present
493
- content = content.replace(/\[mcp_servers\.memax\][\s\S]*?(?=\n\[|$)/, "");
494
- const args = [...bin.args, "mcp", "serve"].map((a) => `"${a}"`).join(", ");
495
- content = content.trim();
496
- if (content)
497
- content += "\n\n";
498
- content += `[mcp_servers.memax]\ncommand = "${bin.command}"\nargs = [${args}]\n`;
499
- writeFileSync(agent.configPath, content);
500
- }
501
- // --- Hook setup ---
502
- function setupHooks(agent, bin) {
503
- if (agent.id === "claude-code") {
504
- setupClaudeCodeHooks(agent, bin);
505
- }
506
- else if (agent.id === "gemini") {
507
- setupGeminiHooks(agent, bin);
508
- }
509
- }
510
- function setupClaudeCodeHooks(agent, bin) {
511
- const hookScript = writeHookScript(bin);
512
- let config = {};
513
- if (existsSync(agent.configPath)) {
514
- try {
515
- config = JSON.parse(readFileSync(agent.configPath, "utf-8"));
516
- }
517
- catch {
518
- // Start fresh
519
- }
520
- }
521
- const hooks = (config.hooks ?? {});
522
- // Remove existing memax hooks
523
- if (hooks["UserPromptSubmit"]) {
524
- hooks["UserPromptSubmit"] = hooks["UserPromptSubmit"].filter((h) => !h.hooks?.some((hh) => hh.command?.includes("memax")));
525
- }
526
- hooks["UserPromptSubmit"] = [
527
- ...(hooks["UserPromptSubmit"] ?? []),
528
- {
529
- matcher: "",
530
- hooks: [{ type: "command", command: hookScript, timeout: 30 }],
531
- },
532
- ];
533
- config.hooks = hooks;
534
- writeFileSync(agent.configPath, JSON.stringify(config, null, 2) + "\n");
535
- }
536
- function setupGeminiHooks(agent, bin) {
537
- const hookScript = writeHookScript(bin);
538
- let config = {};
539
- if (existsSync(agent.configPath)) {
540
- try {
541
- config = JSON.parse(readFileSync(agent.configPath, "utf-8"));
542
- }
543
- catch {
544
- // Start fresh
545
- }
546
- }
547
- const hooks = (config.hooks ?? {});
548
- // Remove existing memax hooks from both old ("Startup") and correct event
549
- for (const event of ["Startup", "BeforeAgent"]) {
550
- if (hooks[event]) {
551
- hooks[event] = hooks[event].filter((h) => !h.hooks?.some((hh) => hh.command?.includes("memax")));
552
- if (hooks[event].length === 0)
553
- delete hooks[event];
554
- }
555
- }
556
- // BeforeAgent fires after user submits a prompt — equivalent to Claude Code's PrePromptSubmit
557
- hooks["BeforeAgent"] = [
558
- ...(hooks["BeforeAgent"] ?? []),
559
- {
560
- matcher: "",
561
- hooks: [{ type: "command", command: hookScript, timeout: 30 }],
562
- },
563
- ];
564
- config.hooks = hooks;
565
- writeFileSync(agent.configPath, JSON.stringify(config, null, 2) + "\n");
566
- }
567
- // --- Teardown helpers ---
568
- function removeMcpJson(agent) {
569
- if (!existsSync(agent.configPath))
570
- return false;
571
- try {
572
- const config = JSON.parse(readFileSync(agent.configPath, "utf-8"));
573
- const servers = getNestedKey(config, agent.mcpKey);
574
- if (!servers?.memax)
575
- return false;
576
- delete servers.memax;
577
- if (Object.keys(servers).length === 0)
578
- deleteNestedKey(config, agent.mcpKey);
579
- writeFileSync(agent.configPath, JSON.stringify(config, null, 2) + "\n");
580
- console.log(chalk.gray(` Removed MCP from ${agent.name}`));
581
- return true;
582
- }
583
- catch {
584
- return false;
585
- }
586
- }
587
- function removeMcpToml(agent) {
588
- if (!existsSync(agent.configPath))
589
- return false;
590
- let content = readFileSync(agent.configPath, "utf-8");
591
- const before = content;
592
- content = content.replace(/\[mcp_servers\.memax\][\s\S]*?(?=\n\[|$)/, "");
593
- if (content === before)
594
- return false;
595
- writeFileSync(agent.configPath, content.trim() + "\n");
596
- console.log(chalk.gray(` Removed MCP from ${agent.name}`));
597
- return true;
598
- }
599
- function removeHooks(agent) {
600
- if (!existsSync(agent.configPath))
601
- return false;
602
- try {
603
- const config = JSON.parse(readFileSync(agent.configPath, "utf-8"));
604
- const hooks = config.hooks;
605
- if (!hooks)
606
- return false;
607
- let removed = false;
608
- for (const event of Object.keys(hooks)) {
609
- const before = hooks[event].length;
610
- hooks[event] = hooks[event].filter((h) => !h.command?.includes("memax") &&
611
- !h.hooks?.some((hh) => hh.command?.includes("memax")));
612
- if (hooks[event].length < before)
613
- removed = true;
614
- if (hooks[event].length === 0)
615
- delete hooks[event];
616
- }
617
- if (Object.keys(hooks).length === 0)
618
- delete config.hooks;
619
- if (removed) {
620
- writeFileSync(agent.configPath, JSON.stringify(config, null, 2) + "\n");
621
- console.log(chalk.gray(` Removed hooks from ${agent.name}`));
622
- }
623
- return removed;
624
- }
625
- catch {
626
- return false;
627
- }
628
- }
629
- function resolveMemaxBin() {
630
- // 1. Global install — use absolute path so agents find it without shell PATH
631
- if (commandExists("memax")) {
632
- try {
633
- const which = platform() === "win32" ? "where memax" : "which memax";
634
- const absPath = execSync(which, { encoding: "utf-8", stdio: "pipe" })
635
- .trim()
636
- .split("\n")[0];
637
- if (absPath) {
638
- return { command: absPath, args: [], shell: absPath };
639
- }
640
- }
641
- catch {
642
- // fall through
643
- }
644
- return { command: "memax", args: [], shell: "memax" };
645
- }
646
- // 2. Local repo build (faster than npx, always up-to-date during dev)
647
- const localBuild = join(process.cwd(), "packages", "cli", "dist", "index.js");
648
- if (existsSync(localBuild)) {
649
- return {
650
- command: "node",
651
- args: [localBuild],
652
- shell: `node ${localBuild}`,
653
- };
654
- }
655
- // 3. npx as last resort (slow startup — agents may timeout on first run)
656
- try {
657
- execSync("npx --yes memax-cli --version", {
658
- encoding: "utf-8",
659
- timeout: 15000,
660
- stdio: "pipe",
661
- });
662
- return {
663
- command: "npx",
664
- args: ["-y", "memax-cli"],
665
- shell: "npx -y memax-cli",
666
- };
667
- }
668
- catch {
669
- // npx failed
670
- }
671
- return null;
672
- }
673
- function commandExists(cmd) {
674
- try {
675
- const which = platform() === "win32" ? "where" : "which";
676
- execSync(`${which} ${cmd}`, { stdio: "pipe" });
677
- return true;
678
- }
679
- catch {
680
- return false;
681
- }
682
- }
683
- // Nested key helpers for configs like openclaw's "mcp.servers"
684
- function getNestedKey(obj, key) {
685
- const parts = key.split(".");
686
- let current = obj;
687
- for (const part of parts) {
688
- if (current == null || typeof current !== "object")
689
- return undefined;
690
- current = current[part];
691
- }
692
- return current;
693
- }
694
- function setNestedKey(obj, key, value) {
695
- const parts = key.split(".");
696
- let current = obj;
697
- for (let i = 0; i < parts.length - 1; i++) {
698
- if (!(parts[i] in current) || typeof current[parts[i]] !== "object") {
699
- current[parts[i]] = {};
700
- }
701
- current = current[parts[i]];
702
- }
703
- current[parts[parts.length - 1]] = value;
704
- }
705
- function deleteNestedKey(obj, key) {
706
- const parts = key.split(".");
707
- let current = obj;
708
- for (let i = 0; i < parts.length - 1; i++) {
709
- if (!(parts[i] in current) || typeof current[parts[i]] !== "object")
710
- return;
711
- current = current[parts[i]];
712
- }
713
- delete current[parts[parts.length - 1]];
714
- }
715
- // --- Instruction injection ---
716
- const MEMAX_INSTRUCTION_BLOCK = `
717
- <!-- memax:start -->
718
- ## Memax — Persistent Memory
719
-
720
- You have access to Memax, a persistent cloud knowledge hub shared across all your AI agents.
721
- Use it proactively — don't wait for the user to ask.
722
-
723
- **At session start:** Use memax_recall to check for relevant context about the current project or task.
724
- **During work:** When you discover important decisions, architecture details, debugging solutions,
725
- or useful context — use memax_push to save them for future sessions.
726
- **At session end:** Summarize key decisions, learnings, or context worth remembering and push them.
727
-
728
- **What to remember:** Architecture decisions, API conventions, deployment processes, debugging
729
- solutions, team preferences, project-specific knowledge. If you'd want to know it in a future
730
- session, push it now.
731
-
732
- **What NOT to remember:** Ephemeral task details, file contents (they're in git), obvious things.
733
-
734
- Available tools: memax_recall (search), memax_push (save), memax_get (read full note),
735
- memax_search (browse), memax_forget (delete outdated memories).
736
- <!-- memax:end -->
737
- `.trim();
738
- function injectInstructions(filePath) {
739
- mkdirSync(dirname(filePath), { recursive: true });
740
- let content = "";
741
- if (existsSync(filePath)) {
742
- content = readFileSync(filePath, "utf-8");
743
- }
744
- // Remove existing memax block (idempotent)
745
- content = content.replace(/\n?<!-- memax:start -->[\s\S]*?<!-- memax:end -->\n?/, "");
746
- // Append the block
747
- content = content.trimEnd() + "\n\n" + MEMAX_INSTRUCTION_BLOCK + "\n";
748
- writeFileSync(filePath, content);
749
- }
750
- function removeInstructions(filePath) {
751
- if (!existsSync(filePath))
752
- return false;
753
- const content = readFileSync(filePath, "utf-8");
754
- const cleaned = content.replace(/\n?<!-- memax:start -->[\s\S]*?<!-- memax:end -->\n?/, "");
755
- if (cleaned === content)
756
- return false;
757
- writeFileSync(filePath, cleaned.trimEnd() + "\n");
758
- return true;
759
- }
760
- function writeHookScript(bin) {
761
- const hooksDir = join(homedir(), ".memax", "hooks");
762
- mkdirSync(hooksDir, { recursive: true });
763
- const isWindows = platform() === "win32";
764
- const scriptName = isWindows ? "context-inject.cmd" : "context-inject.sh";
765
- const scriptPath = join(hooksDir, scriptName);
766
- if (isWindows) {
767
- writeFileSync(scriptPath, WIN_HOOK.replace(/\$MEMAX/g, bin.shell));
768
- }
769
- else {
770
- writeFileSync(scriptPath, UNIX_HOOK.replace(/\$MEMAX/g, bin.shell));
771
- chmodSync(scriptPath, 0o755);
772
- }
773
- return scriptPath;
774
- }
449
+ // --- Usage ---
775
450
  function printUsage() {
776
451
  const agents = getAgents();
777
452
  const detected = agents.filter((a) => a.detect());
@@ -789,8 +464,11 @@ function printUsage() {
789
464
  console.log(chalk.gray(" memax setup --instructions Inject memax usage instructions into agent configs"));
790
465
  console.log(chalk.gray(" memax setup --all MCP + hooks + instructions"));
791
466
  console.log(chalk.gray(" memax setup --mcp --local Use local CLI instead of remote server"));
467
+ console.log(chalk.gray(" memax setup --mcp --api-key Use API keys instead of OAuth (CI/CD)"));
792
468
  console.log(chalk.gray(" memax setup --print Print MCP config to copy/paste"));
793
469
  console.log(chalk.gray(" memax setup --mcp --only claude-code,cursor"));
470
+ console.log(chalk.gray(" memax setup --mcp --read-only"));
471
+ console.log(chalk.gray(" memax setup --mcp --hub memax-team --allow-organize"));
794
472
  console.log(chalk.gray(" memax teardown Remove all integrations\n"));
795
473
  console.log(chalk.gray(" Supported agents:"));
796
474
  for (const a of agents) {
@@ -801,25 +479,29 @@ function printUsage() {
801
479
  }
802
480
  console.log();
803
481
  }
804
- const UNIX_HOOK = `#!/bin/bash
805
- # Memax context injection — installed by: memax setup --hooks
806
- set -e
807
- INPUT=$(cat)
808
- PROMPT=$(echo "$INPUT" | jq -r '.prompt // empty')
809
- CWD=$(echo "$INPUT" | jq -r '.cwd // empty')
810
- if [ -z "$PROMPT" ] || [ \${#PROMPT} -lt 10 ]; then exit 0; fi
811
- case "$PROMPT" in [Yy]|[Yy]es|[Nn]|[Nn]o|ok|OK|sure|Sure|thanks|Thanks|y|n) exit 0 ;; esac
812
- if [ -n "$CWD" ]; then cd "$CWD" 2>/dev/null || true; fi
813
- CONTEXT=$($MEMAX recall "$PROMPT" --hook --limit 5 --max-tokens 3000 2>/dev/null) || exit 0
814
- if [ -n "$CONTEXT" ] && [ "$CONTEXT" != "<memax-context>" ]; then echo "$CONTEXT"; fi
815
- exit 0
816
- `;
817
- const WIN_HOOK = `@echo off
818
- REM Memax context injection installed by: memax setup --hooks
819
- set /p INPUT=
820
- for /f "tokens=*" %%a in ('echo %INPUT% ^| jq -r ".prompt // empty"') do set PROMPT=%%a
821
- if "%PROMPT%"=="" exit /b 0
822
- $MEMAX recall "%PROMPT%" --hook --limit 5 --max-tokens 3000 2>nul
823
- exit /b 0
824
- `;
482
+ export function registerSetupCommands(program) {
483
+ program
484
+ .command("setup")
485
+ .description("Set up AI agent integrations (auto-detects installed agents)")
486
+ .option("--mcp", "Enable MCP server (agent tools)")
487
+ .option("--hooks", "Enable context injection hooks")
488
+ .option("--instructions", "Inject memax instructions into agent config files")
489
+ .option("--all", "Enable MCP + hooks + instructions")
490
+ .option("--local", "Use local stdio MCP instead of remote server")
491
+ .option("--api-key", "Use per-agent API keys instead of OAuth (for CI/CD or agents without OAuth support)")
492
+ .option("--print", "Print MCP config JSON to copy/paste (no changes made)")
493
+ .option("--only <agents>", "Only configure these agents (comma-separated)")
494
+ .option("--skip <agents>", "Skip these agents (comma-separated)")
495
+ .option("--hub <id>", "Scope MCP key to a specific hub")
496
+ .option("--read-only", "Create remote MCP keys without write access")
497
+ .option("--allow-delete", "Allow remote MCP keys to delete memories")
498
+ .option("--allow-organize", "Allow remote MCP keys to organize topics and run dreams")
499
+ .option("--agent-sync", "Allow remote MCP keys to sync agent configs and sessions")
500
+ .action(setupCommand);
501
+ program
502
+ .command("teardown")
503
+ .description("Remove Memax integrations from agents")
504
+ .option("--only <agents>", "Only remove from these agents (comma-separated)")
505
+ .action(teardownCommand);
506
+ }
825
507
  //# sourceMappingURL=setup.js.map