@memorax/memorax-code 0.1.11 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -4
- package/bin/memorax-code-setup.mjs +136 -34
- package/bin/memorax-code-trae.mjs +4 -0
- package/docs/configuration.md +106 -52
- package/docs/troubleshooting.md +45 -6
- package/lib/memorax-code-backend/dist/clients/claude/transcript-turn.js +2 -2
- package/lib/memorax-code-backend/dist/clients/codex/rollout-turn.js +1 -1
- package/lib/memorax-code-backend/dist/clients/trae/lifecycle.js +53 -0
- package/lib/memorax-code-backend/dist/clients/trae/memory-hook-runtime.js +302 -0
- package/lib/memorax-code-backend/dist/clients/trae/turn-id.js +16 -0
- package/lib/memorax-code-backend/dist/config/memorax-code.js +14 -1
- package/lib/memorax-code-backend/dist/entrypoints/backend-cli.js +22 -4
- package/lib/memorax-code-backend/dist/lifecycle/active-clients.js +3 -0
- package/lib/memorax-code-backend/dist/lifecycle/client-plugin-removal.js +14 -2
- package/lib/memorax-code-backend/dist/lifecycle/client-selection.js +5 -3
- package/lib/memorax-code-backend/dist/lifecycle/orchestrator.js +62 -9
- package/lib/memorax-code-backend/dist/memory/hook-command.js +34 -2
- package/lib/memorax-code-backend/dist/memory/reminder-trace-recorder.js +5 -1
- package/lib/memorax-code-backend/dist/memory/service.js +12 -0
- package/lib/memorax-code-backend/dist/trace/config.js +12 -1
- package/lib/memorax-code-backend/dist/trace/context.js +26 -1
- package/lib/memorax-code-backend/package.json +1 -1
- package/lib/memorax-code-claude-adapter/.claude-plugin/plugin.json +1 -1
- package/lib/memorax-code-claude-adapter/hooks/runtime-shell.json +1 -1
- package/lib/memorax-code-claude-adapter/package.json +1 -1
- package/lib/memorax-code-claude-adapter/skills/memorax-code/SKILL.md +3 -1
- package/lib/memorax-code-claude-adapter/skills/memorax-code/references/memorax-add.md +16 -3
- package/lib/memorax-code-claude-adapter/skills/memorax-code/references/memorax-search.md +15 -2
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/.claude-plugin/plugin.json +1 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/hooks/runtime-shell.json +1 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/package.json +1 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/SKILL.md +3 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/memorax-add.md +16 -3
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/memorax-search.md +15 -2
- package/lib/memorax-code-codebuddy-adapter/.codebuddy-plugin/plugin.json +1 -1
- package/lib/memorax-code-codebuddy-adapter/package.json +1 -1
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/SKILL.md +3 -1
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/memorax-add.md +16 -3
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/memorax-search.md +15 -2
- package/lib/memorax-code-codex-adapter/.codex-plugin/plugin.json +1 -1
- package/lib/memorax-code-codex-adapter/hooks/runtime-shell.json +1 -1
- package/lib/memorax-code-codex-adapter/package.json +1 -1
- package/lib/memorax-code-codex-adapter/skills/memorax-code/SKILL.md +3 -1
- package/lib/memorax-code-codex-adapter/skills/memorax-code/references/memorax-add.md +16 -3
- package/lib/memorax-code-codex-adapter/skills/memorax-code/references/memorax-search.md +15 -2
- package/lib/memorax-code-dsh-adapter/package.json +1 -1
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/SKILL.md +3 -1
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/memorax-add.md +16 -3
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/memorax-search.md +15 -2
- package/lib/memorax-code-opencode-adapter/package.json +1 -1
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/SKILL.md +3 -1
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/memorax-add.md +16 -3
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/memorax-search.md +15 -2
- package/lib/memorax-code-trae-adapter/hooks/runtime-hook.mjs +340 -0
- package/lib/memorax-code-trae-adapter/package.json +9 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/SKILL.md +87 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/agents/claude.yaml +10 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/agents/openai.yaml +7 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/defaults.json +12 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/references/memorax-add.md +101 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/references/memorax-search.md +106 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/references/personal-read.md +46 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/references/personal-write.md +120 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/references/repo-build.md +319 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/references/repo-read.md +103 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/references/repo-templates.md +390 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/references/repo-update.md +127 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/scripts/collect_all.py +579 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/scripts/detect_updates.py +919 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/scripts/git_commit_facets.py +222 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/scripts/github_resource_facets.py +512 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/scripts/gitlab_resource_facets.py +517 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/scripts/prepare_repo_memory.py +411 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/scripts/user_profile_memory.py +528 -0
- package/lib/memorax-code-trae-adapter/skills/memorax-code/scripts/validate_memory.py +248 -0
- package/lib/memorax-code-trae-adapter/src/adapter-paths.mjs +69 -0
- package/lib/memorax-code-trae-adapter/src/cli.mjs +59 -0
- package/lib/memorax-code-trae-adapter/src/config.mjs +630 -0
- package/lib/memorax-code-trae-adapter/src/runtime-observation.mjs +55 -0
- package/lib/run-entrypoint.mjs +6 -0
- package/package.json +5 -3
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
|
+
import { writeTraeRuntimeObservation } from "../src/runtime-observation.mjs";
|
|
8
|
+
|
|
9
|
+
const runtimeRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
10
|
+
const commonRoot = join(runtimeRoot, "memorax-code-adapter-common", "src");
|
|
11
|
+
const { buildRepoProcedureMemoryContext } = await import(pathToFileURL(join(commonRoot, "repo-memory", "repo-procedure-memory-context.mjs")).href);
|
|
12
|
+
const { buildRepoUserProfilePreferencesContext } = await import(pathToFileURL(join(commonRoot, "repo-memory", "repo-user-profile-context.mjs")).href);
|
|
13
|
+
const { resolveBackendConnection } = await import(pathToFileURL(join(commonRoot, "backend-connection.mjs")).href);
|
|
14
|
+
const {
|
|
15
|
+
atomicWriteJson,
|
|
16
|
+
readJsonFile,
|
|
17
|
+
withJsonFileLock,
|
|
18
|
+
} = await import(pathToFileURL(join(commonRoot, "config-utils.mjs")).href);
|
|
19
|
+
const { ensureBackendAvailable, stringValue: commonStringValue } = await import(pathToFileURL(join(commonRoot, "hooks", "ensure-backend-runner.mjs")).href);
|
|
20
|
+
const {
|
|
21
|
+
evaluateMemorySkillReminder,
|
|
22
|
+
markSupplementalReminderAfterCompact,
|
|
23
|
+
personalMemoryReminderContext,
|
|
24
|
+
} = await import(pathToFileURL(join(commonRoot, "hooks", "memory-skill-reminder-hook.mjs")).href);
|
|
25
|
+
const { isRepoMemoryJobWorker } = await import(pathToFileURL(join(commonRoot, "repo-memory", "repo-memory-job-context.mjs")).href);
|
|
26
|
+
|
|
27
|
+
if (isRepoMemoryJobWorker()) process.exit(0);
|
|
28
|
+
|
|
29
|
+
const MEMORY_SKILL_INVOCATION = "the `memorax-code` skill";
|
|
30
|
+
const REMINDER_TRACE_TIMEOUT_MS = 1000;
|
|
31
|
+
const input = await readJsonStdin();
|
|
32
|
+
const event = stringValue(input?.hook_event_name) ?? stringValue(input?.hookEventName);
|
|
33
|
+
const sessionId = stringValue(input?.session_id) ?? stringValue(input?.sessionId);
|
|
34
|
+
if (!event || !sessionId || !["SessionStart", "UserPromptSubmit", "Stop"].includes(event)) process.exit(0);
|
|
35
|
+
|
|
36
|
+
const packageMetadata = await readRecord(join(runtimeRoot, ".memorax-code-package.json"));
|
|
37
|
+
const home = commonStringValue(process.env.MEMORAX_CODE_HOME)
|
|
38
|
+
?? commonStringValue(packageMetadata.memoraxCodeHome)
|
|
39
|
+
?? join(homedir(), ".memorax-code");
|
|
40
|
+
const traeHome = commonStringValue(process.env.TRAE_CN_HOME)
|
|
41
|
+
?? commonStringValue(process.env.TRAE_HOME)
|
|
42
|
+
?? commonStringValue(packageMetadata.traeHome)
|
|
43
|
+
?? join(homedir(), ".trae-cn");
|
|
44
|
+
const runtimeDigest = commonStringValue(packageMetadata.runtimeDigest);
|
|
45
|
+
const debugEnabled = process.env.MEMORAX_CODE_TRAE_HOOK_DEBUG === "1";
|
|
46
|
+
if (runtimeDigest) {
|
|
47
|
+
try {
|
|
48
|
+
await writeTraeRuntimeObservation({ memoraxCodeHome: home, traeHome, runtimeDigest });
|
|
49
|
+
} catch (error) {
|
|
50
|
+
debug(error);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const reminderOptions = {
|
|
55
|
+
adapterDir: "trae",
|
|
56
|
+
debugEnv: "MEMORAX_CODE_TRAE_HOOK_DEBUG",
|
|
57
|
+
memoraxCodeHome: home,
|
|
58
|
+
runtime: "trae",
|
|
59
|
+
supplementalReminderAfterCompact: true,
|
|
60
|
+
};
|
|
61
|
+
const personalMemoryContextOptions = {
|
|
62
|
+
adapterDir: "trae",
|
|
63
|
+
debugEnv: "MEMORAX_CODE_TRAE_HOOK_DEBUG",
|
|
64
|
+
sessionKeyPrefix: "trae",
|
|
65
|
+
};
|
|
66
|
+
const activeTurnsPath = join(home, "adapters", "trae", "active-turns.json");
|
|
67
|
+
|
|
68
|
+
await ensureBackendAvailable({
|
|
69
|
+
ensureBackendValue: process.env.MEMORAX_CODE_TRAE_ENSURE_BACKEND
|
|
70
|
+
?? process.env.MEMORAX_CODE_TRAE_HOOK_ENSURE_BACKEND,
|
|
71
|
+
healthTimeoutValue: process.env.MEMORAX_CODE_TRAE_ENSURE_TIMEOUT_MS,
|
|
72
|
+
startTimeoutValue: process.env.MEMORAX_CODE_TRAE_START_TIMEOUT_MS,
|
|
73
|
+
memoraxCodeCommand: commonStringValue(process.env.MEMORAX_CODE_TRAE_LIFECYCLE_COMMAND)
|
|
74
|
+
?? commonStringValue(process.env.MEMORAX_CODE_COMMAND),
|
|
75
|
+
pluginRoot: runtimeRoot,
|
|
76
|
+
resolveHomes: () => ({ memoraxCodeHome: home, traeHome }),
|
|
77
|
+
buildStartArgs: (homes, recoveryArguments) => [
|
|
78
|
+
"start",
|
|
79
|
+
"--home", homes.memoraxCodeHome,
|
|
80
|
+
"--clients", "trae",
|
|
81
|
+
"--trae-home", homes.traeHome,
|
|
82
|
+
...recoveryArguments,
|
|
83
|
+
],
|
|
84
|
+
debug,
|
|
85
|
+
}, input);
|
|
86
|
+
|
|
87
|
+
if (event === "SessionStart") {
|
|
88
|
+
markSupplementalReminderAfterCompact(reminderOptions, input);
|
|
89
|
+
} else if (event === "UserPromptSubmit") {
|
|
90
|
+
const prompt = contentValue(input.prompt);
|
|
91
|
+
if (!prompt) process.exit(0);
|
|
92
|
+
const cwd = stringValue(input.cwd);
|
|
93
|
+
const workspaceKind = stringValue(input.workspace_kind) ?? stringValue(input.workspaceKind);
|
|
94
|
+
const activeTurnPlan = prepareActiveTurn({ sessionId, prompt, cwd, workspaceKind });
|
|
95
|
+
const activeTurn = activeTurnPlan.record;
|
|
96
|
+
const response = await post("/memory/turn-start", {
|
|
97
|
+
version: 1,
|
|
98
|
+
client: "trae",
|
|
99
|
+
sessionId,
|
|
100
|
+
turnId: activeTurn.turnId,
|
|
101
|
+
prompt,
|
|
102
|
+
cwd,
|
|
103
|
+
workspaceKind,
|
|
104
|
+
});
|
|
105
|
+
if (response?.ok !== true || !commitActiveTurn(activeTurnPlan)) process.exit(0);
|
|
106
|
+
const repoMemoryWorktree = stringValue(response?.repoMemoryWorktree);
|
|
107
|
+
const reminderResult = await evaluateMemorySkillReminder({
|
|
108
|
+
...reminderOptions,
|
|
109
|
+
additionalReminderContext: personalMemoryReminderContext(MEMORY_SKILL_INVOCATION),
|
|
110
|
+
memorySkillInvocation: MEMORY_SKILL_INVOCATION,
|
|
111
|
+
remindOnFirstTurn: true,
|
|
112
|
+
requireTranscriptPath: false,
|
|
113
|
+
...(repoMemoryWorktree ? {
|
|
114
|
+
buildCadenceReminderContext: (hookInput) => buildRepoProcedureMemoryContext({
|
|
115
|
+
...hookInput,
|
|
116
|
+
cwd: repoMemoryWorktree,
|
|
117
|
+
}, personalMemoryContextOptions),
|
|
118
|
+
buildPersonalMemoryContext: (hookInput) => buildRepoUserProfilePreferencesContext({
|
|
119
|
+
...hookInput,
|
|
120
|
+
cwd: repoMemoryWorktree,
|
|
121
|
+
}, personalMemoryContextOptions),
|
|
122
|
+
} : {}),
|
|
123
|
+
}, { ...input, turnId: activeTurn.turnId, workspaceKind });
|
|
124
|
+
const context = [
|
|
125
|
+
stringValue(response?.additionalContext),
|
|
126
|
+
stringValue(reminderResult?.additionalContext),
|
|
127
|
+
].filter(Boolean).join("\n\n");
|
|
128
|
+
const systemMessage = stringValue(response?.userNotice);
|
|
129
|
+
if (context || systemMessage) {
|
|
130
|
+
process.stdout.write(`${JSON.stringify({
|
|
131
|
+
...(systemMessage ? { systemMessage } : {}),
|
|
132
|
+
...(context ? { hookSpecificOutput: { hookEventName: "UserPromptSubmit", additionalContext: context } } : {}),
|
|
133
|
+
})}\n`);
|
|
134
|
+
}
|
|
135
|
+
if (response !== undefined && reminderResult?.reminder) await recordReminder(reminderResult.reminder);
|
|
136
|
+
} else {
|
|
137
|
+
const lastAssistantMessage = assistantMessage(input);
|
|
138
|
+
if (!lastAssistantMessage) process.exit(0);
|
|
139
|
+
const activeTurn = readActiveTurn(sessionId);
|
|
140
|
+
if (!activeTurn) process.exit(0);
|
|
141
|
+
const response = await post("/memory/writeback", {
|
|
142
|
+
version: 1,
|
|
143
|
+
client: "trae",
|
|
144
|
+
sessionId,
|
|
145
|
+
turnId: activeTurn.turnId,
|
|
146
|
+
prompt: activeTurn.prompt,
|
|
147
|
+
lastAssistantMessage,
|
|
148
|
+
cwd: activeTurn.cwd ?? stringValue(input.cwd),
|
|
149
|
+
workspaceKind: activeTurn.workspaceKind,
|
|
150
|
+
});
|
|
151
|
+
if (response?.ok === true && response?.scheduled === true) removeActiveTurn(sessionId, activeTurn.turnId);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function prepareActiveTurn({ sessionId, prompt, cwd, workspaceKind }) {
|
|
155
|
+
return withJsonFileLock(activeTurnsPath, () => {
|
|
156
|
+
const state = activeTurnState();
|
|
157
|
+
pruneActiveTurns(state);
|
|
158
|
+
const existing = validActiveTurn(state.sessions?.[sessionId], sessionId);
|
|
159
|
+
const now = Date.now();
|
|
160
|
+
const record = existing
|
|
161
|
+
&& existing.prompt === prompt
|
|
162
|
+
&& existing.cwd === cwd
|
|
163
|
+
&& existing.workspaceKind === workspaceKind
|
|
164
|
+
? { ...existing, updatedAt: now }
|
|
165
|
+
: {
|
|
166
|
+
version: 1,
|
|
167
|
+
sessionId,
|
|
168
|
+
turnId: createTraeTurnId(sessionId, now, prompt),
|
|
169
|
+
prompt,
|
|
170
|
+
...(cwd ? { cwd } : {}),
|
|
171
|
+
...(workspaceKind ? { workspaceKind } : {}),
|
|
172
|
+
createdAt: now,
|
|
173
|
+
updatedAt: now,
|
|
174
|
+
};
|
|
175
|
+
return { record, expectedTurnId: existing?.turnId };
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function commitActiveTurn({ record, expectedTurnId }) {
|
|
180
|
+
return withJsonFileLock(activeTurnsPath, () => {
|
|
181
|
+
const state = activeTurnState();
|
|
182
|
+
pruneActiveTurns(state);
|
|
183
|
+
const current = validActiveTurn(state.sessions?.[record.sessionId], record.sessionId);
|
|
184
|
+
if (current?.turnId !== expectedTurnId && current?.turnId !== record.turnId) return false;
|
|
185
|
+
state.sessions[record.sessionId] = record;
|
|
186
|
+
const now = Date.now();
|
|
187
|
+
state.updatedAt = new Date(now).toISOString();
|
|
188
|
+
pruneActiveTurns(state);
|
|
189
|
+
atomicWriteJson(activeTurnsPath, state);
|
|
190
|
+
return true;
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function readActiveTurn(sessionId) {
|
|
195
|
+
return withJsonFileLock(activeTurnsPath, () => {
|
|
196
|
+
const state = activeTurnState();
|
|
197
|
+
pruneActiveTurns(state);
|
|
198
|
+
atomicWriteJson(activeTurnsPath, state);
|
|
199
|
+
return validActiveTurn(state.sessions[sessionId], sessionId);
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function removeActiveTurn(sessionId, turnId) {
|
|
204
|
+
withJsonFileLock(activeTurnsPath, () => {
|
|
205
|
+
const state = activeTurnState();
|
|
206
|
+
if (state.sessions?.[sessionId]?.turnId === turnId) delete state.sessions[sessionId];
|
|
207
|
+
state.updatedAt = new Date().toISOString();
|
|
208
|
+
atomicWriteJson(activeTurnsPath, state);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function activeTurnState() {
|
|
213
|
+
const value = readJsonFile(activeTurnsPath);
|
|
214
|
+
if (value?.unreadable) return { version: 1, runtime: "trae", sessions: {} };
|
|
215
|
+
const state = value?.value;
|
|
216
|
+
if (!isRecord(state) || state.version !== 1 || state.runtime !== "trae" || !isRecord(state.sessions)) {
|
|
217
|
+
return { version: 1, runtime: "trae", sessions: {} };
|
|
218
|
+
}
|
|
219
|
+
return state;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function pruneActiveTurns(state) {
|
|
223
|
+
const now = Date.now();
|
|
224
|
+
for (const [id, record] of Object.entries(state.sessions)) {
|
|
225
|
+
const valid = validActiveTurn(record, id);
|
|
226
|
+
if (!valid || now - valid.updatedAt > 24 * 60 * 60 * 1000) delete state.sessions[id];
|
|
227
|
+
}
|
|
228
|
+
const ordered = Object.entries(state.sessions)
|
|
229
|
+
.sort(([, left], [, right]) => Number(left.updatedAt ?? 0) - Number(right.updatedAt ?? 0));
|
|
230
|
+
while (ordered.length > 200) {
|
|
231
|
+
const [id] = ordered.shift();
|
|
232
|
+
delete state.sessions[id];
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function validActiveTurn(value, sessionId) {
|
|
237
|
+
if (!isRecord(value)
|
|
238
|
+
|| value.version !== 1
|
|
239
|
+
|| value.sessionId !== sessionId
|
|
240
|
+
|| !validTraeTurnId(sessionId, value.turnId, value.prompt)
|
|
241
|
+
|| !contentValue(value.prompt)
|
|
242
|
+
|| !Number.isSafeInteger(value.createdAt)
|
|
243
|
+
|| !Number.isSafeInteger(value.updatedAt)) return undefined;
|
|
244
|
+
return value;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function createTraeTurnId(sessionId, createdAt, prompt) {
|
|
248
|
+
const digest = createHash("sha256").update(prompt.trim()).digest("hex");
|
|
249
|
+
return `${sessionId}:${createdAt}:${digest}`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function validTraeTurnId(sessionId, turnId, prompt) {
|
|
253
|
+
if (typeof turnId !== "string" || !turnId.startsWith(`${sessionId}:`)) return false;
|
|
254
|
+
const match = /^([1-9]\d*):([a-f0-9]{64})$/.exec(turnId.slice(sessionId.length + 1));
|
|
255
|
+
return Boolean(match
|
|
256
|
+
&& Number.isSafeInteger(Number(match[1]))
|
|
257
|
+
&& match[2] === createHash("sha256").update(String(prompt).trim()).digest("hex"));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async function recordReminder(reminder) {
|
|
261
|
+
if (!reminder.turnId) return;
|
|
262
|
+
await post("/memory/skill-reminder", {
|
|
263
|
+
version: 1,
|
|
264
|
+
client: "trae",
|
|
265
|
+
sessionId: reminder.sessionId,
|
|
266
|
+
turnId: reminder.turnId,
|
|
267
|
+
cwd: reminder.cwd,
|
|
268
|
+
workspaceKind: reminder.workspaceKind,
|
|
269
|
+
content: reminder.content,
|
|
270
|
+
triggers: reminder.triggers,
|
|
271
|
+
}, REMINDER_TRACE_TIMEOUT_MS);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async function post(path, body, timeoutMs = 12_000) {
|
|
275
|
+
let connection;
|
|
276
|
+
try {
|
|
277
|
+
connection = resolveBackendConnection({ memoraxCodeHome: home });
|
|
278
|
+
} catch (error) {
|
|
279
|
+
debug(error);
|
|
280
|
+
return undefined;
|
|
281
|
+
}
|
|
282
|
+
const headers = { "content-type": "application/json", connection: "close" };
|
|
283
|
+
if (connection.token) headers["x-memorax-code-backend-token"] = connection.token;
|
|
284
|
+
try {
|
|
285
|
+
const response = await fetch(new URL(path, connection.url), {
|
|
286
|
+
method: "POST",
|
|
287
|
+
headers,
|
|
288
|
+
body: JSON.stringify(body),
|
|
289
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
290
|
+
});
|
|
291
|
+
return response.ok ? await response.json().catch(() => undefined) : undefined;
|
|
292
|
+
} catch {
|
|
293
|
+
return undefined;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function assistantMessage(value) {
|
|
298
|
+
const last = contentValue(value.last_assistant_message) ?? contentValue(value.lastAssistantMessage);
|
|
299
|
+
const text = contentValue(value.text_content) ?? contentValue(value.textContent);
|
|
300
|
+
if (last && text && last !== text) {
|
|
301
|
+
debug(new Error("Trae Stop payload assistant fields do not match"));
|
|
302
|
+
return undefined;
|
|
303
|
+
}
|
|
304
|
+
return last ?? text;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async function readJsonStdin() {
|
|
308
|
+
try {
|
|
309
|
+
let text = "";
|
|
310
|
+
for await (const chunk of process.stdin) text += chunk;
|
|
311
|
+
return JSON.parse(text);
|
|
312
|
+
} catch {
|
|
313
|
+
return {};
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
async function readRecord(path) {
|
|
318
|
+
try {
|
|
319
|
+
const value = JSON.parse(await readFile(path, "utf8"));
|
|
320
|
+
return isRecord(value) ? value : {};
|
|
321
|
+
} catch {
|
|
322
|
+
return {};
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function contentValue(value) {
|
|
327
|
+
return typeof value === "string" && value.trim() ? value : undefined;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function stringValue(value) {
|
|
331
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function isRecord(value) {
|
|
335
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function debug(error) {
|
|
339
|
+
if (debugEnabled) console.error(error instanceof Error ? error.message : String(error));
|
|
340
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@memorax-code/trae-adapter",
|
|
3
|
+
"version": "0.1.12",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Trae Hook adapter for MemoraX Code memory services.",
|
|
7
|
+
"bin": { "memorax-code-trae": "src/cli.mjs" },
|
|
8
|
+
"scripts": { "test": "node --test test/*.test.mjs" }
|
|
9
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memorax-code
|
|
3
|
+
description: >-
|
|
4
|
+
Use this skill as the single router for persistent coding and repository-local
|
|
5
|
+
memory. Invoke it whenever a request may involve prior-work knowledge,
|
|
6
|
+
repository memory, reusable procedures or rules, durable profile or
|
|
7
|
+
interaction preferences, or information worth retaining beyond the current
|
|
8
|
+
task. This applies without memory wording, including habits, preferences,
|
|
9
|
+
checklists, action sequences, prerequisites, gates, exceptions, validation
|
|
10
|
+
rules, communication style, preferred language, or result presentation.
|
|
11
|
+
Classify the request as coding memory, repository memory, personal procedure
|
|
12
|
+
memory, personal profile memory, or no persistent memory, then route it to the
|
|
13
|
+
matching operation. Invoking this router does not require coding-memory
|
|
14
|
+
search. Reuse a relevant coding-memory result already retrieved in this
|
|
15
|
+
conversation; otherwise let the matching operation decide on search. Prefer
|
|
16
|
+
this router over underlying memory workflows. Ask one focused question only when
|
|
17
|
+
memory authority remains ambiguous.
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# MemoraX Code
|
|
21
|
+
|
|
22
|
+
Classify the requested memory authority first, then its operation. Load only the matching reference unless the request genuinely spans authorities or operations.
|
|
23
|
+
|
|
24
|
+
After selecting an operation reference, read it completely in a standalone
|
|
25
|
+
tool call and wait for the full result before constructing or executing that
|
|
26
|
+
operation. Never combine reading a required reference with the command or
|
|
27
|
+
action it governs in the same shell command or tool call.
|
|
28
|
+
|
|
29
|
+
## Authority Router
|
|
30
|
+
|
|
31
|
+
### MemoraX Code Coding Memory
|
|
32
|
+
|
|
33
|
+
Use MemoraX Code coding memory for reusable engineering knowledge learned across coding work: prior fixes, failed approaches, coding conventions, implementation pitfalls, validation patterns, and design rationale.
|
|
34
|
+
|
|
35
|
+
- Read [references/memorax-search.md](references/memorax-search.md) to recall or search coding memory.
|
|
36
|
+
- Read [references/memorax-add.md](references/memorax-add.md) to save a grounded reusable coding lesson.
|
|
37
|
+
|
|
38
|
+
### Repo Memory
|
|
39
|
+
|
|
40
|
+
Use repo memory for repository identity, architecture maps, module routing, local commit history, and GitHub or GitLab PR, MR, and issue evidence stored under `.repo_memory/PROFILE.md`, `.repo_memory/resources/`, and `.repo_memory/raw/`.
|
|
41
|
+
|
|
42
|
+
- Read [references/repo-read.md](references/repo-read.md) to inspect existing repo memory.
|
|
43
|
+
- Read [references/repo-build.md](references/repo-build.md) for first-time creation, full rebuilds, or full refreshes.
|
|
44
|
+
- Read [references/repo-update.md](references/repo-update.md) for incremental updates to an existing bundle.
|
|
45
|
+
- Read [references/repo-templates.md](references/repo-templates.md) only when the build or update operation needs to author repo memory files.
|
|
46
|
+
|
|
47
|
+
### Personal Memory
|
|
48
|
+
|
|
49
|
+
Use personal memory for user-owned repository procedures and durable profile or interaction preferences stored under `.repo_memory/procedure-memory/` and `.repo_memory/user-profile/`.
|
|
50
|
+
|
|
51
|
+
- Read [references/personal-read.md](references/personal-read.md) to list, recall, or apply personal memory.
|
|
52
|
+
- Read [references/personal-write.md](references/personal-write.md) to save, update, forget, or delete personal memory.
|
|
53
|
+
|
|
54
|
+
## Tie Breakers
|
|
55
|
+
|
|
56
|
+
- Route ordered actions, checklists, prerequisites, gates, exceptions, and validation rules to personal procedure memory, even when phrased as "I prefer", "I like", "我的习惯", or "我喜欢".
|
|
57
|
+
- Route preferred name, answer language, tone, verbosity, explanation style, and result presentation to personal profile memory.
|
|
58
|
+
- Route task-learned repairs, coding pitfalls, project engineering conventions, and reusable design lessons to MemoraX Code coding memory.
|
|
59
|
+
- Route prior project discussions, experiment conclusions, saved engineering findings, earlier fixes, and reusable project lessons to MemoraX Code coding memory. Do not route them to repo memory merely because they concern a project. Use repo memory for repository identity, architecture, module maps, commits, PRs, MRs, and issues.
|
|
60
|
+
- Route repository architecture, module maps, commit history, PRs, MRs, and issues to repo memory. Verify claims about current behavior against live code.
|
|
61
|
+
- Use both repo memory and MemoraX Code coding memory only when a request genuinely needs distinct repository evidence and reusable engineering lessons. This can apply to implementation, debugging, refactoring, migration planning, or validation when the answer may depend on repository module maps, commit/PR/issue evidence, and prior fixes, pitfalls, conventions, validation patterns, or design rationale. Do not use both authorities just because a request mentions a repository, file, module, or "previous".
|
|
62
|
+
- Route current-task instructions and temporary plans to the current task only; do not persist them.
|
|
63
|
+
- Current-task-only applies only when completing the request does not depend on prior project state. Do not select it merely because the requested action happens in the current turn. When implementation, debugging, review, experiment continuation, or validation depends on earlier project decisions, results, fixes, constraints, or plans that the user has not explicitly and completely supplied, route to MemoraX Code coding memory.
|
|
64
|
+
- Do not infer an authority from verbs such as "remember", "recall", "refresh", or "update" alone. Ask one focused question when the target remains ambiguous.
|
|
65
|
+
|
|
66
|
+
Examples:
|
|
67
|
+
|
|
68
|
+
- "先测试再提 PR,帮我记住" routes to personal procedure write.
|
|
69
|
+
- "我喜欢中文简短回答" routes to personal profile write.
|
|
70
|
+
- "之前这个 bug 怎么修的?" routes to MemoraX Code coding memory search unless the user asks for commit or PR evidence.
|
|
71
|
+
- "这个仓库的架构是什么?" routes to repo memory read.
|
|
72
|
+
- "重新生成仓库 memory" routes to repo memory build.
|
|
73
|
+
- "更新一下 memory" requires clarification when no authority is identifiable.
|
|
74
|
+
|
|
75
|
+
## Shared Rules
|
|
76
|
+
|
|
77
|
+
For MemoraX Code coding memory, run the platform command from the active task workspace. In Windows PowerShell, use `memorax-cli.cmd`; on macOS and Linux, use `memorax-cli`. Never invoke `memorax-cli.ps1`. Never run `Set-ExecutionPolicy` or otherwise change PowerShell execution policy for MemoraX commands. If an unqualified Windows invocation is blocked before the CLI starts with `UnauthorizedAccess` or `PSSecurityException`, retry the same command once with `memorax-cli.cmd`, preserving all arguments, the active workspace, and environment variables.
|
|
78
|
+
|
|
79
|
+
The installed Hook and session binding supply the authoritative workspace root; do not run Git commands to discover or replace it. The Backend resolves repository scope from that trusted workspace and read-only filesystem Git metadata.
|
|
80
|
+
|
|
81
|
+
Repo memory and personal memory remain local `.repo_memory` authorities. Resolve their repository root exactly as described by the selected reference, including its Git requirements.
|
|
82
|
+
|
|
83
|
+
Apply instructions in this order: system and developer instructions, `AGENTS.md`, the current user request, then stored memory. Memory is guidance or historical context, not proof of current repository behavior.
|
|
84
|
+
|
|
85
|
+
For MemoraX Code coding memory, use `memorax-cli` exactly as described by the selected reference. Invoke this skill as `$memorax-code` in Codex or `/memorax-code` in Claude Code. In OpenCode, ask the agent to use the `memorax-code` skill by name. These invocation forms are not shell commands. `memorax-code` is the lifecycle CLI and must not be used for memory search or add. Do not call MemoraX HTTP endpoints directly.
|
|
86
|
+
|
|
87
|
+
Never store secrets, credentials, `.env` content, sensitive personal data, raw transcripts, hidden tests, exact patches, temporary target commits, or unsafe destructive commands. Do not announce internal routing or reference loading.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "MemoraX Code"
|
|
3
|
+
short_description: "Route coding, repo, and personal memory"
|
|
4
|
+
default_prompt: "Use /memorax-code-claude-adapter:memorax-code to route a coding-memory, repo-memory, or personal-memory request to the correct operation."
|
|
5
|
+
|
|
6
|
+
policy:
|
|
7
|
+
allow_implicit_invocation: true
|
|
8
|
+
install_targets:
|
|
9
|
+
- "~/.claude/skills/memorax-code"
|
|
10
|
+
- ".claude/skills/memorax-code"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "MemoraX Code"
|
|
3
|
+
short_description: "Route coding, repo, and personal memory"
|
|
4
|
+
default_prompt: "Use $memorax-code to route a coding-memory, repo-memory, or personal-memory request to the correct operation."
|
|
5
|
+
|
|
6
|
+
policy:
|
|
7
|
+
allow_implicit_invocation: true
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# MemoraX Code Coding Memory Add
|
|
2
|
+
|
|
3
|
+
Use these instructions only to add reusable coding knowledge through `memorax-cli`. Invoke the skill as `$memorax-code` in Codex or `/memorax-code` in Claude Code. In OpenCode, ask the agent to use the `memorax-code` skill by name. Do not route memory operations through the lifecycle-only `memorax-code` CLI. Do not use this authority for personal procedures, interaction preferences, generated repository facts, or one-off task details.
|
|
4
|
+
|
|
5
|
+
## Eligible Knowledge
|
|
6
|
+
|
|
7
|
+
Add a coding memory only when the task yields stable, grounded, reusable engineering knowledge, such as:
|
|
8
|
+
|
|
9
|
+
- a verified repair invariant or validation pattern;
|
|
10
|
+
- a reusable failed-attempt lesson;
|
|
11
|
+
- a confirmed coding convention, lifecycle boundary, or implementation pitfall;
|
|
12
|
+
- durable design rationale that will help future coding work.
|
|
13
|
+
|
|
14
|
+
Route user-owned ordered actions, checklists, gates, and work rules to personal procedure memory. Route preferred language, tone, verbosity, name, and presentation to personal profile memory. Route commit, PR, issue, architecture-map, and repository-history facts to repo memory.
|
|
15
|
+
|
|
16
|
+
Do not add positive repair lessons based only on unverified edits or assistant self-report. Verification may come from a focused test, evaluator, CI check, accepted review, manual reproduction, or deployed behavior. A failed attempt may be saved as negative evidence when the failure itself is clear and reusable.
|
|
17
|
+
|
|
18
|
+
## Add Workflow
|
|
19
|
+
|
|
20
|
+
Select the executable before constructing any Add command. In Windows PowerShell, use `memorax-cli.cmd`; on macOS and Linux, use `memorax-cli`. Never invoke `memorax-cli.ps1`. Never run `Set-ExecutionPolicy` or otherwise change PowerShell execution policy for MemoraX commands. If an unqualified Windows invocation is blocked before the CLI starts with `UnauthorizedAccess` or `PSSecurityException`, retry that command once with `memorax-cli.cmd`, preserving all arguments, the active workspace, and environment variables.
|
|
21
|
+
|
|
22
|
+
For a proactive add, write all generated prose in `--memory`, `--reason`, and the confirmation in the language of the user's current request; preserve exact code, API, path, workflow, and project identifiers.
|
|
23
|
+
|
|
24
|
+
Run from the active task workspace. Pass the memory and reason directly. Put every dynamically generated `--memory` and `--reason` value in single quotes, never double quotes. Apply the escaping rule for the active shell:
|
|
25
|
+
|
|
26
|
+
- Windows PowerShell: single quotes keep `$HOME`, backticks, and `$(command)` literal. Replace each literal single quote in a value with two single quotes (`''`); for example, `don't` becomes `'don''t'`.
|
|
27
|
+
- macOS and Linux: Treat `$HOME`, backticks, and `$(command)` as literal text inside the quotes. Replace each literal single quote in a value with the exact POSIX sequence `'\''`.
|
|
28
|
+
|
|
29
|
+
Windows PowerShell:
|
|
30
|
+
|
|
31
|
+
```powershell
|
|
32
|
+
memorax-cli.cmd add --memory 'Concise reusable memory.' --type procedural --reason 'Capture reusable coding memory.'
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
macOS and Linux:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
memorax-cli add \
|
|
39
|
+
--memory 'Concise reusable memory.' \
|
|
40
|
+
--type procedural \
|
|
41
|
+
--reason 'Capture reusable coding memory.'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Use an appropriate supported type such as `core`, `semantic`, `procedural`, `episodic`, or `unclassified`. Use `preference` only for an engineering convention owned by MemoraX Code coding memory, not for a personal interaction preference.
|
|
45
|
+
|
|
46
|
+
For a complex verified repair or failed approach, use this compact card when it improves later retrieval:
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
CODE_AGENT_MEMORY
|
|
50
|
+
repo: <repository or product area>
|
|
51
|
+
scope: <module/path::symbol/API or lifecycle boundary>
|
|
52
|
+
status: <verified|failed_attempt|candidate>
|
|
53
|
+
signal: <test, CI, review, reproduction, deployment, failure, or unknown>
|
|
54
|
+
problem: <small behavioral symptom or engineering situation>
|
|
55
|
+
technical_context: <stable API, lifecycle, state owner, or data-shape detail>
|
|
56
|
+
surfaces: <observable producer/consumer or setup/runtime/cleanup boundaries>
|
|
57
|
+
failed_shape: <reusable wrong assumption or unsafe patch shape, or none>
|
|
58
|
+
validation: <small reusable check contract>
|
|
59
|
+
principle: <abstract invariant or decision rule>
|
|
60
|
+
anchors: <stable repository source, tests, or public docs>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Keep the card under 1,100 characters when practical. It must guide future investigation while still requiring live-code inspection.
|
|
64
|
+
|
|
65
|
+
Pass a completed multi-line card as one single-quoted `--memory` argument. On Windows PowerShell, the command must start with `memorax-cli.cmd add`; on macOS and Linux, use the form shown below.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
memorax-cli add \
|
|
69
|
+
--memory 'CODE_AGENT_MEMORY
|
|
70
|
+
repo: owner/name
|
|
71
|
+
scope: module/path::symbol
|
|
72
|
+
status: verified
|
|
73
|
+
signal: focused test passed
|
|
74
|
+
problem: concise reusable symptom
|
|
75
|
+
technical_context: stable implementation fact
|
|
76
|
+
surfaces: affected boundary
|
|
77
|
+
failed_shape: reusable pitfall or none
|
|
78
|
+
validation: smallest reusable check
|
|
79
|
+
principle: reusable invariant
|
|
80
|
+
anchors: stable/source/path' \
|
|
81
|
+
--type procedural \
|
|
82
|
+
--reason 'Capture verified reusable coding memory.'
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Except for the pre-start Windows shim correction above, if add fails, report the exact failure and do not retry automatically, bypass the CLI, or call MemoraX directly. Do not retry Add after the CLI may have started.
|
|
86
|
+
|
|
87
|
+
If a successful Add result reports `workspaceScopeFallbackReason: git_metadata_invalid`, malformed or incomplete metadata inside a direct `.git` directory was downgraded to the normalized local folder scope. Add has already been submitted with the reported `effectiveUserId`. Present its `userNotice` once without pausing the current task or asking the user to repair Git first, then continue the current task. After the repository or `.git` metadata is repaired, later Search, Add, and automatic writeback in the same client session automatically use the restored Git repository scope.
|
|
88
|
+
|
|
89
|
+
If `memorax-cli add` reports `workspace_scope_mismatch` or `workspace_scope_unavailable`, do not bypass the scope. Do not change the CLI working directory and retry. Tell the user that the memory was not submitted and no request was sent to MemoraX, then present the CLI's `userAction` in natural language. Continue the current task using only live code and documentation.
|
|
90
|
+
|
|
91
|
+
## Exclusions
|
|
92
|
+
|
|
93
|
+
Do not add secrets, credentials, private URLs, raw authorization headers, exact patches, target commits, hidden tests, target diffs, vulnerability details, exploit steps, copied source, long logs, stack traces, raw transcripts, temporary errors, or facts directly recoverable from current files and git history.
|
|
94
|
+
|
|
95
|
+
Do not add speculation, assistant-only praise, or a current instruction merely because it contains "remember". Return to `SKILL.md` when the content belongs to personal memory or repo memory.
|
|
96
|
+
|
|
97
|
+
## Output
|
|
98
|
+
|
|
99
|
+
If a successful Add returns `quotaNotice`, or prints it as a quota-reminder line in the default CLI output, present the complete reminder once and prominently before the normal result summary. Do not reduce it to only a percentage or omit its account URL or anonymous-account claim details. A guest reminder may already contain the local Mark ID; present it once as part of the reminder, but do not repeat or separately quote it. Never run `memorax-code account --show-mark-id` for the user or ask for its output. Treat the reminder as user-facing operational output, not coding memory content, and continue the current task.
|
|
100
|
+
|
|
101
|
+
After an add request is accepted, confirm briefly that it was submitted for processing and identify the reusable coding lesson at a high level. If add is disabled or fails, report the issue and continue without bypassing the CLI.
|