@memorax/memorax-code 0.1.8 → 0.1.10
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 +10 -0
- package/bin/memorax-code-codebuddy.mjs +4 -0
- package/bin/memorax-code-setup.mjs +182 -65
- package/bin/memorax-code.mjs +74 -45
- package/docs/configuration.md +82 -22
- package/docs/troubleshooting.md +69 -5
- package/lib/automatic-update.mjs +233 -0
- package/lib/memorax-code-adapter-common/src/automatic-update-state.d.mts +24 -0
- package/lib/memorax-code-adapter-common/src/automatic-update-state.mjs +73 -0
- package/lib/memorax-code-adapter-common/src/clients/codebuddy-command.mjs +82 -0
- package/lib/memorax-code-adapter-common/src/config-utils.d.mts +2 -0
- package/lib/memorax-code-adapter-common/src/config-utils.mjs +11 -0
- package/lib/memorax-code-adapter-common/src/hooks/client-hook-launcher.mjs +3 -0
- package/lib/memorax-code-adapter-common/src/hooks/ensure-backend-runner.mjs +45 -10
- package/lib/memorax-code-adapter-common/src/repo-memory/repo-memory-job-worker.mjs +88 -3
- package/lib/memorax-code-adapter-common/src/windows-cli-invocation.mjs +11 -1
- package/lib/memorax-code-backend/dist/app/backend-server.js +2 -2
- package/lib/memorax-code-backend/dist/app/memory-observability.js +2 -2
- package/lib/memorax-code-backend/dist/clients/codebuddy/jsonl-history.js +208 -0
- package/lib/memorax-code-backend/dist/clients/codebuddy/lifecycle.js +44 -0
- package/lib/memorax-code-backend/dist/clients/codebuddy/memory-hook-runtime.js +250 -0
- package/lib/memorax-code-backend/dist/clients/codebuddy/turn-id.js +16 -0
- package/lib/memorax-code-backend/dist/clients/codex/plugin-install.js +129 -7
- package/lib/memorax-code-backend/dist/clients/codex/rollout-turn.js +52 -2
- package/lib/memorax-code-backend/dist/config/memorax-code.js +14 -1
- package/lib/memorax-code-backend/dist/entrypoints/backend-cli.js +43 -6
- package/lib/memorax-code-backend/dist/lifecycle/active-clients.js +3 -0
- package/lib/memorax-code-backend/dist/lifecycle/automatic-update-scheduler.js +133 -0
- package/lib/memorax-code-backend/dist/lifecycle/client-plugin-removal.js +14 -2
- package/lib/memorax-code-backend/dist/lifecycle/client-selection.js +6 -4
- package/lib/memorax-code-backend/dist/lifecycle/orchestrator.js +48 -9
- package/lib/memorax-code-backend/dist/memory/cli.js +4 -2
- package/lib/memorax-code-backend/dist/memory/hook-command.js +31 -1
- 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/shared/windows-cli-invocation.js +10 -1
- package/lib/memorax-code-backend/dist/trace/config.js +12 -0
- package/lib/memorax-code-backend/dist/trace/context.js +21 -1
- package/lib/memorax-code-backend/dist/trace/store.js +12 -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/runtime-hooks/ensure-backend.mjs +2 -0
- package/lib/memorax-code-claude-adapter/src/plugin-install.mjs +3 -0
- 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/memorax-code-adapter-common/src/automatic-update-state.d.mts +24 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/automatic-update-state.mjs +73 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/clients/codebuddy-command.mjs +82 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/config-utils.d.mts +2 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/config-utils.mjs +11 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/hooks/client-hook-launcher.mjs +3 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/hooks/ensure-backend-runner.mjs +45 -10
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/repo-memory/repo-memory-job-worker.mjs +88 -3
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/windows-cli-invocation.mjs +11 -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/runtime-hooks/ensure-backend.mjs +2 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/src/plugin-install.mjs +3 -0
- package/lib/memorax-code-codebuddy-adapter/.codebuddy-plugin/plugin.json +7 -0
- package/lib/memorax-code-codebuddy-adapter/hooks/common-runtime.mjs +13 -0
- package/lib/memorax-code-codebuddy-adapter/hooks/hooks.json +38 -0
- package/lib/memorax-code-codebuddy-adapter/hooks/repo-memory-job.mjs +40 -0
- package/lib/memorax-code-codebuddy-adapter/hooks/runtime-hook.mjs +279 -0
- package/lib/memorax-code-codebuddy-adapter/package.json +9 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/SKILL.md +85 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/agents/claude.yaml +10 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/agents/openai.yaml +7 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/defaults.json +12 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/memorax-add.md +88 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/memorax-search.md +93 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/personal-read.md +46 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/personal-write.md +120 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/repo-build.md +319 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/repo-read.md +103 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/repo-templates.md +390 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/references/repo-update.md +127 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/collect_all.py +579 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/detect_updates.py +919 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/git_commit_facets.py +222 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/github_resource_facets.py +512 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/gitlab_resource_facets.py +517 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/prepare_repo_memory.py +411 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/user_profile_memory.py +528 -0
- package/lib/memorax-code-codebuddy-adapter/skills/memorax-code/scripts/validate_memory.py +248 -0
- package/lib/memorax-code-codebuddy-adapter/src/cli.mjs +58 -0
- package/lib/memorax-code-codebuddy-adapter/src/config.mjs +277 -0
- package/lib/memorax-code-codebuddy-adapter/src/hook-manifest.mjs +47 -0
- package/lib/memorax-code-codebuddy-adapter/src/runtime-observation.mjs +65 -0
- 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/runtime-hooks/ensure-backend.mjs +4 -1
- package/lib/memorax-code-dsh-adapter/package.json +2 -1
- package/lib/memorax-code-dsh-adapter/src/profile-lifecycle.mjs +1 -0
- package/lib/memorax-code-opencode-adapter/package.json +1 -1
- package/lib/npm-invocation.mjs +51 -8
- package/lib/resolve-codebuddy-command.mjs +112 -0
- package/lib/run-entrypoint.mjs +25 -1
- package/lib/windows-cli-invocation.mjs +11 -1
- package/lib/windows-user-path.mjs +218 -0
- package/package.json +5 -3
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isRecord } from "../shared/record.js";
|
|
2
|
+
import { codeBuddyPromptDigest, parseCodeBuddyTurnId } from "../clients/codebuddy/turn-id.js";
|
|
2
3
|
export const MEMORY_HOOK_COMMAND_VERSION = 1;
|
|
3
4
|
export const INVALID_MEMORY_HOOK_COMMAND = "invalid memory Hook command";
|
|
4
5
|
const BASE_COMMAND_KEYS = [
|
|
@@ -13,6 +14,7 @@ const TURN_START_KEYS = {
|
|
|
13
14
|
"claude-code": new Set([...BASE_COMMAND_KEYS, "promptId", "prompt", "transcriptPath"]),
|
|
14
15
|
opencode: new Set([...BASE_COMMAND_KEYS, "userMessageId", "prompt"]),
|
|
15
16
|
dsh: new Set(["version", "client", "sessionId", "turn", "startSeq", "cwd", "prompt"]),
|
|
17
|
+
codebuddy: new Set([...BASE_COMMAND_KEYS, "turnId", "prompt", "transcriptPath"]),
|
|
16
18
|
};
|
|
17
19
|
const WRITEBACK_KEYS = {
|
|
18
20
|
codex: new Set([...BASE_COMMAND_KEYS, "turnId", "lastAssistantMessage", "transcriptPath"]),
|
|
@@ -39,12 +41,14 @@ const WRITEBACK_KEYS = {
|
|
|
39
41
|
"sessionHeader",
|
|
40
42
|
"events",
|
|
41
43
|
]),
|
|
44
|
+
codebuddy: new Set([...BASE_COMMAND_KEYS, "turnId", "transcriptPath"]),
|
|
42
45
|
};
|
|
43
46
|
const SKILL_REMINDER_KEYS = {
|
|
44
47
|
codex: new Set([...BASE_COMMAND_KEYS, "turnId", "transcriptPath", "content", "triggers"]),
|
|
45
48
|
"claude-code": new Set([...BASE_COMMAND_KEYS, "promptId", "transcriptPath", "content", "triggers"]),
|
|
46
49
|
dsh: new Set(["version", "client", "sessionId", "turn", "cwd", "content", "triggers"]),
|
|
47
50
|
opencode: new Set([...BASE_COMMAND_KEYS, "userMessageId", "content", "triggers"]),
|
|
51
|
+
codebuddy: new Set([...BASE_COMMAND_KEYS, "turnId", "transcriptPath", "content", "triggers"]),
|
|
48
52
|
};
|
|
49
53
|
export function parseTurnStartCommand(value) {
|
|
50
54
|
if (!isRecord(value))
|
|
@@ -102,6 +106,13 @@ export function parseTurnStartCommand(value) {
|
|
|
102
106
|
},
|
|
103
107
|
};
|
|
104
108
|
}
|
|
109
|
+
if (base.client === "codebuddy") {
|
|
110
|
+
const turnId = requiredStringField(value, "turnId");
|
|
111
|
+
const transcriptPath = requiredStringField(value, "transcriptPath");
|
|
112
|
+
if (!turnId || !transcriptPath || !validCodeBuddyTurnId(turnId, base.sessionId, prompt))
|
|
113
|
+
return invalidCommand();
|
|
114
|
+
return { ok: true, command: { ...base, client: "codebuddy", turnId, prompt, transcriptPath } };
|
|
115
|
+
}
|
|
105
116
|
const promptId = requiredStringField(value, "promptId");
|
|
106
117
|
const transcriptPath = requiredStringField(value, "transcriptPath");
|
|
107
118
|
if (!promptId || !transcriptPath)
|
|
@@ -166,6 +177,13 @@ export function parseWritebackCommand(value) {
|
|
|
166
177
|
},
|
|
167
178
|
};
|
|
168
179
|
}
|
|
180
|
+
if (base.client === "codebuddy") {
|
|
181
|
+
const turnId = requiredStringField(value, "turnId");
|
|
182
|
+
const transcriptPath = requiredStringField(value, "transcriptPath");
|
|
183
|
+
if (!turnId || !transcriptPath || !validCodeBuddyTurnId(turnId, base.sessionId))
|
|
184
|
+
return invalidCommand();
|
|
185
|
+
return { ok: true, command: { ...base, client: "codebuddy", turnId, transcriptPath } };
|
|
186
|
+
}
|
|
169
187
|
const lastAssistantMessage = requiredStringField(value, "lastAssistantMessage");
|
|
170
188
|
if (!lastAssistantMessage)
|
|
171
189
|
return invalidCommand();
|
|
@@ -241,6 +259,13 @@ export function parseSkillReminderCommand(value) {
|
|
|
241
259
|
},
|
|
242
260
|
};
|
|
243
261
|
}
|
|
262
|
+
if (base.client === "codebuddy") {
|
|
263
|
+
const turnId = requiredStringField(value, "turnId");
|
|
264
|
+
const transcriptPath = requiredStringField(value, "transcriptPath");
|
|
265
|
+
if (!turnId || !transcriptPath || !validCodeBuddyTurnId(turnId, base.sessionId))
|
|
266
|
+
return invalidCommand();
|
|
267
|
+
return { ok: true, command: { ...base, client: "codebuddy", turnId, transcriptPath, content, triggers } };
|
|
268
|
+
}
|
|
244
269
|
const transcriptPath = requiredStringField(value, "transcriptPath");
|
|
245
270
|
if (!transcriptPath)
|
|
246
271
|
return invalidCommand();
|
|
@@ -284,7 +309,8 @@ function parseCommandBase(value, allowedKeys) {
|
|
|
284
309
|
if (client !== "codex"
|
|
285
310
|
&& client !== "claude-code"
|
|
286
311
|
&& client !== "opencode"
|
|
287
|
-
&& client !== "dsh"
|
|
312
|
+
&& client !== "dsh"
|
|
313
|
+
&& client !== "codebuddy")
|
|
288
314
|
return undefined;
|
|
289
315
|
const clientKeys = allowedKeys[client];
|
|
290
316
|
if (!clientKeys || Object.keys(value).some((key) => !clientKeys.has(key)))
|
|
@@ -342,6 +368,10 @@ function optionalStringField(value, key) {
|
|
|
342
368
|
const field = requiredStringField(value, key);
|
|
343
369
|
return field ? { ok: true, value: field } : { ok: false };
|
|
344
370
|
}
|
|
371
|
+
function validCodeBuddyTurnId(turnId, sessionId, prompt) {
|
|
372
|
+
const identity = parseCodeBuddyTurnId({ sessionId, turnId });
|
|
373
|
+
return Boolean(identity && (prompt === undefined || identity.promptDigest === codeBuddyPromptDigest(prompt)));
|
|
374
|
+
}
|
|
345
375
|
function invalidCommand() {
|
|
346
376
|
return { ok: false, error: INVALID_MEMORY_HOOK_COMMAND };
|
|
347
377
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parseSkillReminderCommand, } from "./hook-command.js";
|
|
2
|
-
import { traceContextFromClaudeHookBody, traceContextFromDshSkillReminder, traceContextFromHookBody, traceContextFromOpenCodeHookBody, } from "../trace/context.js";
|
|
2
|
+
import { traceContextFromClaudeHookBody, traceContextFromDshSkillReminder, traceContextFromHookBody, traceContextFromOpenCodeHookBody, traceContextFromCodeBuddyHookBody, } from "../trace/context.js";
|
|
3
3
|
import { recordTraceEvent } from "../trace/store.js";
|
|
4
4
|
export function createMemoryReminderTraceRecorder(options = {}) {
|
|
5
5
|
return {
|
|
@@ -47,6 +47,8 @@ function traceContextForReminder(command) {
|
|
|
47
47
|
return traceContextFromClaudeHookBody(command);
|
|
48
48
|
if (command.client === "dsh")
|
|
49
49
|
return traceContextFromDshSkillReminder(command);
|
|
50
|
+
if (command.client === "codebuddy")
|
|
51
|
+
return traceContextFromCodeBuddyHookBody(command);
|
|
50
52
|
return traceContextFromOpenCodeHookBody(command);
|
|
51
53
|
}
|
|
52
54
|
function reminderSource(command) {
|
|
@@ -56,6 +58,8 @@ function reminderSource(command) {
|
|
|
56
58
|
return "claude-hook";
|
|
57
59
|
if (command.client === "dsh")
|
|
58
60
|
return "dsh-cordis";
|
|
61
|
+
if (command.client === "codebuddy")
|
|
62
|
+
return "codebuddy-hook";
|
|
59
63
|
return "opencode-plugin";
|
|
60
64
|
}
|
|
61
65
|
async function recordTraceBestEffort(label, promise, diagnosticLogger) {
|
|
@@ -3,6 +3,7 @@ import { createCodexMemoryHookRuntime, } from "../clients/codex/memory-hook-runt
|
|
|
3
3
|
import { createClaudeMemoryHookRuntime, } from "../clients/claude/memory-hook-runtime.js";
|
|
4
4
|
import { createDshMemoryHookRuntime, } from "../clients/dsh/memory-hook-runtime.js";
|
|
5
5
|
import { createOpenCodeMemoryHookRuntime, } from "../clients/opencode/memory-hook-runtime.js";
|
|
6
|
+
import { createCodeBuddyMemoryHookRuntime } from "../clients/codebuddy/memory-hook-runtime.js";
|
|
6
7
|
import { createMemoryTurnCoordinator } from "./turn-coordinator.js";
|
|
7
8
|
import { createRepositoryMemorySessionRuntime, } from "./repository-session.js";
|
|
8
9
|
import { createPendingQuotaNoticeRuntime } from "./quota-notice.js";
|
|
@@ -49,6 +50,12 @@ export function createMemoryService(options = {}) {
|
|
|
49
50
|
repositoryMemorySession,
|
|
50
51
|
turnCoordinator,
|
|
51
52
|
});
|
|
53
|
+
const codeBuddyHook = createCodeBuddyMemoryHookRuntime({
|
|
54
|
+
...options,
|
|
55
|
+
pendingQuotaNotice,
|
|
56
|
+
repositoryMemorySession,
|
|
57
|
+
turnCoordinator,
|
|
58
|
+
});
|
|
52
59
|
let closed = false;
|
|
53
60
|
return {
|
|
54
61
|
async recordTurnStart(command) {
|
|
@@ -61,6 +68,8 @@ export function createMemoryService(options = {}) {
|
|
|
61
68
|
return await openCodeHook.recordTurnStart(command);
|
|
62
69
|
case "dsh":
|
|
63
70
|
return await dshHook.recordTurnStart(command);
|
|
71
|
+
case "codebuddy":
|
|
72
|
+
return await codeBuddyHook.recordTurnStart(command);
|
|
64
73
|
}
|
|
65
74
|
return unsupportedMemoryHookCommand(command);
|
|
66
75
|
},
|
|
@@ -74,6 +83,8 @@ export function createMemoryService(options = {}) {
|
|
|
74
83
|
return await openCodeHook.writeback(command);
|
|
75
84
|
case "dsh":
|
|
76
85
|
return await dshHook.writeback(command);
|
|
86
|
+
case "codebuddy":
|
|
87
|
+
return await codeBuddyHook.writeback(command);
|
|
77
88
|
}
|
|
78
89
|
return unsupportedMemoryHookCommand(command);
|
|
79
90
|
},
|
|
@@ -88,6 +99,7 @@ export function createMemoryService(options = {}) {
|
|
|
88
99
|
claudeHook.close();
|
|
89
100
|
openCodeHook.close();
|
|
90
101
|
dshHook.close();
|
|
102
|
+
codeBuddyHook.close();
|
|
91
103
|
turnCoordinator.close();
|
|
92
104
|
repositoryMemorySession.close();
|
|
93
105
|
automaticWriteback.close();
|
|
@@ -25,6 +25,9 @@ export function resolveWindowsCliInvocation(command, args, options = {}) {
|
|
|
25
25
|
resolvedCommand ??= command;
|
|
26
26
|
if (/\.(?:exe|com)$/i.test(resolvedCommand))
|
|
27
27
|
return { command: resolvedCommand, args };
|
|
28
|
+
if (isBareCodeBuddyEntrypoint(resolvedCommand, pathApi) && fileExists(resolvedCommand)) {
|
|
29
|
+
return { command: options.nodePath ?? process.execPath, args: [resolvedCommand, ...args] };
|
|
30
|
+
}
|
|
28
31
|
if (!/\.(?:cmd|bat)$/i.test(resolvedCommand)) {
|
|
29
32
|
throw new Error(`refusing to execute unsupported Windows command shim: ${resolvedCommand}`);
|
|
30
33
|
}
|
|
@@ -87,12 +90,18 @@ export function selectWindowsCommandCandidate(command, output) {
|
|
|
87
90
|
.map((value) => value.trim())
|
|
88
91
|
.filter(Boolean);
|
|
89
92
|
const selected = candidates.find((value) => /\.(?:cmd|bat)$/i.test(value))
|
|
90
|
-
?? candidates.find((value) => /\.(?:exe|com)$/i.test(value))
|
|
93
|
+
?? candidates.find((value) => /\.(?:exe|com)$/i.test(value))
|
|
94
|
+
?? (path.win32.basename(command).toLowerCase() === "codebuddy"
|
|
95
|
+
? candidates.find((value) => isBareCodeBuddyEntrypoint(value, path.win32))
|
|
96
|
+
: undefined);
|
|
91
97
|
if (!selected) {
|
|
92
98
|
throw new Error(`where.exe did not return a safe executable or command shim for ${command}`);
|
|
93
99
|
}
|
|
94
100
|
return selected;
|
|
95
101
|
}
|
|
102
|
+
function isBareCodeBuddyEntrypoint(value, pathApi) {
|
|
103
|
+
return pathApi.basename(value).toLowerCase() === "codebuddy" && pathApi.extname(value) === "";
|
|
104
|
+
}
|
|
96
105
|
export function resolveWindowsNpmInvocation(args, env, options = {}) {
|
|
97
106
|
const platform = options.platform ?? process.platform;
|
|
98
107
|
if (platform !== "win32")
|
|
@@ -4,6 +4,7 @@ import { join } from "node:path";
|
|
|
4
4
|
import { loadMemoraxCodeConfig } from "../config/memorax-code.js";
|
|
5
5
|
import { isTraceClient } from "./context.js";
|
|
6
6
|
export const TRACE_CLIENTS = ["codex", "claude", "dsh", "opencode"];
|
|
7
|
+
export const TRACE_RUNTIME_CLIENTS = [...TRACE_CLIENTS, "codebuddy"];
|
|
7
8
|
export const CODEX_TRACE_DEFAULT_CONFIG = {
|
|
8
9
|
enabled: true,
|
|
9
10
|
captureContent: true,
|
|
@@ -32,17 +33,22 @@ export const OPENCODE_TRACE_DEFAULT_CONFIG = {
|
|
|
32
33
|
maxEventChars: 20_000,
|
|
33
34
|
maxFileBytes: 52_428_800,
|
|
34
35
|
};
|
|
36
|
+
export const CODEBUDDY_TRACE_DEFAULT_CONFIG = {
|
|
37
|
+
...OPENCODE_TRACE_DEFAULT_CONFIG,
|
|
38
|
+
};
|
|
35
39
|
const TRACE_DEFAULT_CONFIGS = {
|
|
36
40
|
codex: CODEX_TRACE_DEFAULT_CONFIG,
|
|
37
41
|
claude: CLAUDE_TRACE_DEFAULT_CONFIG,
|
|
38
42
|
dsh: DSH_TRACE_DEFAULT_CONFIG,
|
|
39
43
|
opencode: OPENCODE_TRACE_DEFAULT_CONFIG,
|
|
44
|
+
codebuddy: CODEBUDDY_TRACE_DEFAULT_CONFIG,
|
|
40
45
|
};
|
|
41
46
|
const TRACE_ENV_PREFIXES = {
|
|
42
47
|
codex: "MEMORAX_CODE_CODEX_TRACE",
|
|
43
48
|
claude: "MEMORAX_CODE_CLAUDE_TRACE",
|
|
44
49
|
dsh: "MEMORAX_CODE_DSH_TRACE",
|
|
45
50
|
opencode: "MEMORAX_CODE_OPENCODE_TRACE",
|
|
51
|
+
codebuddy: "MEMORAX_CODE_CODEBUDDY_TRACE",
|
|
46
52
|
};
|
|
47
53
|
export const TRACE_CLEANUP_DEBOUNCE_MS = 60 * 60 * 1000;
|
|
48
54
|
export const TRACE_CURRENT_TURN_TTL_MS = 30 * 60 * 1000;
|
|
@@ -62,6 +68,9 @@ export function dshTraceConfigFromEnv(env = process.env, fileConfig) {
|
|
|
62
68
|
export function openCodeTraceConfigFromEnv(env = process.env, fileConfig) {
|
|
63
69
|
return clientTraceConfigFromEnv("opencode", env, fileConfig);
|
|
64
70
|
}
|
|
71
|
+
export function codeBuddyTraceConfigFromEnv(env = process.env, fileConfig) {
|
|
72
|
+
return clientTraceConfigFromEnv("codebuddy", env, fileConfig);
|
|
73
|
+
}
|
|
65
74
|
export function clientTraceConfigFromEnv(client, env = process.env, fileConfig) {
|
|
66
75
|
assertTraceClient(client);
|
|
67
76
|
const config = fileConfig ?? loadMemoraxCodeConfig(memoraxCodeHomeForTrace(env), { warn: () => undefined });
|
|
@@ -91,6 +100,9 @@ export function dshTracePaths(memoraxCodeHome = memoraxCodeHomeForTrace(process.
|
|
|
91
100
|
export function openCodeTracePaths(memoraxCodeHome = memoraxCodeHomeForTrace(process.env)) {
|
|
92
101
|
return clientTracePaths("opencode", memoraxCodeHome);
|
|
93
102
|
}
|
|
103
|
+
export function codeBuddyTracePaths(memoraxCodeHome = memoraxCodeHomeForTrace(process.env)) {
|
|
104
|
+
return clientTracePaths("codebuddy", memoraxCodeHome);
|
|
105
|
+
}
|
|
94
106
|
export function clientTracePaths(client, memoraxCodeHome = memoraxCodeHomeForTrace(process.env)) {
|
|
95
107
|
assertTraceClient(client);
|
|
96
108
|
const root = join(memoraxCodeHome, "debug", "traces", client);
|
|
@@ -62,6 +62,26 @@ export function traceContextFromOpenCodeHookBody(body, capturedAt = new Date().t
|
|
|
62
62
|
capturedAt,
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
|
+
export function traceContextFromCodeBuddyHookBody(body, capturedAt = new Date().toISOString()) {
|
|
66
|
+
if (!isRecord(body))
|
|
67
|
+
return undefined;
|
|
68
|
+
const sessionId = stringField(body, "session_id") ?? stringField(body, "sessionId");
|
|
69
|
+
if (!sessionId)
|
|
70
|
+
return undefined;
|
|
71
|
+
const cwd = stringField(body, "cwd");
|
|
72
|
+
return pruneTraceContext({
|
|
73
|
+
schemaVersion: "1",
|
|
74
|
+
client: "codebuddy",
|
|
75
|
+
sessionId,
|
|
76
|
+
turnId: stringField(body, "turn_id") ?? stringField(body, "turnId"),
|
|
77
|
+
transcriptPath: stringField(body, "transcript_path") ?? stringField(body, "transcriptPath"),
|
|
78
|
+
cwd,
|
|
79
|
+
memoryProject: resolveMemoryProject(cwd),
|
|
80
|
+
workspaceKind: stringField(body, "workspace_kind") ?? stringField(body, "workspaceKind"),
|
|
81
|
+
contextOrigin: "codebuddy-hook-body",
|
|
82
|
+
capturedAt,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
65
85
|
export function traceContextFromDshTurnStart(body, capturedAt = new Date().toISOString()) {
|
|
66
86
|
return traceContextFromDshBody(body, "dsh-cordis-turn-start", capturedAt);
|
|
67
87
|
}
|
|
@@ -129,7 +149,7 @@ function pruneRecord(value) {
|
|
|
129
149
|
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined));
|
|
130
150
|
}
|
|
131
151
|
export function isTraceClient(value) {
|
|
132
|
-
return value === "codex" || value === "claude" || value === "dsh" || value === "opencode";
|
|
152
|
+
return value === "codex" || value === "claude" || value === "dsh" || value === "opencode" || value === "codebuddy";
|
|
133
153
|
}
|
|
134
154
|
function traceContextFromDshBody(body, contextOrigin, capturedAt) {
|
|
135
155
|
if (!isRecord(body))
|
|
@@ -60,6 +60,9 @@ export async function recordCodexTraceEvent(input) {
|
|
|
60
60
|
export async function recordClaudeTraceEvent(input) {
|
|
61
61
|
return recordTraceEventForClient("claude", input);
|
|
62
62
|
}
|
|
63
|
+
export async function recordCodeBuddyTraceEvent(input) {
|
|
64
|
+
return recordTraceEventForClient("codebuddy", input);
|
|
65
|
+
}
|
|
63
66
|
export function traceTurnEventId(traceContext, type) {
|
|
64
67
|
if (!traceContext?.sessionId || !traceContext.turnId)
|
|
65
68
|
return undefined;
|
|
@@ -168,6 +171,12 @@ export async function markCurrentCodexTurnOutcome(traceContext, outcome, options
|
|
|
168
171
|
export async function markCurrentClaudeTurnOutcome(traceContext, outcome, options = {}) {
|
|
169
172
|
return markCurrentTraceTurnOutcome(traceContext, outcome, { ...options, client: "claude" });
|
|
170
173
|
}
|
|
174
|
+
export async function writeCurrentCodeBuddyTurn(traceContext, options = {}) {
|
|
175
|
+
return writeCurrentTraceTurn(traceContext, { ...options, client: "codebuddy" });
|
|
176
|
+
}
|
|
177
|
+
export async function markCurrentCodeBuddyTurnOutcome(traceContext, outcome, options = {}) {
|
|
178
|
+
return markCurrentTraceTurnOutcome(traceContext, outcome, { ...options, client: "codebuddy" });
|
|
179
|
+
}
|
|
171
180
|
async function readCurrentTraceTurnRecord(options) {
|
|
172
181
|
const client = options.client;
|
|
173
182
|
if (!isTraceClient(client))
|
|
@@ -303,7 +312,9 @@ function buildTraceEvent(input, config, now, eventId) {
|
|
|
303
312
|
ok: input.ok,
|
|
304
313
|
outcome: input.outcome,
|
|
305
314
|
related_turns: input.relatedTurns?.map(relatedTurnJson),
|
|
306
|
-
activities: input.activities
|
|
315
|
+
activities: input.activities === undefined
|
|
316
|
+
? undefined
|
|
317
|
+
: sanitizeTraceValue(input.activities, config, captureContent),
|
|
307
318
|
usage: input.usage,
|
|
308
319
|
session_turn_index: input.sessionTurnIndex,
|
|
309
320
|
request: input.request === undefined ? undefined : sanitizeTraceValue(input.request, config, captureContent),
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { readClientHookPluginRoot } from "../../memorax-code-adapter-common/src/config-utils.mjs";
|
|
5
6
|
import {
|
|
6
7
|
runEnsureBackendHook,
|
|
7
8
|
stringValue,
|
|
@@ -31,6 +32,7 @@ process.exit(0);
|
|
|
31
32
|
function pluginRoot() {
|
|
32
33
|
return stringValue(process.env.CLAUDE_PLUGIN_ROOT)
|
|
33
34
|
?? stringValue(process.env.PLUGIN_ROOT)
|
|
35
|
+
?? readClientHookPluginRoot()
|
|
34
36
|
?? dirname(dirname(fileURLToPath(import.meta.url)));
|
|
35
37
|
}
|
|
36
38
|
|
|
@@ -32,6 +32,7 @@ const STABLE_SHELL_REQUIRED_FILES = Object.freeze([
|
|
|
32
32
|
"memorax-code-adapter-common/src/hooks/capture-cwd-hook.mjs",
|
|
33
33
|
"memorax-code-adapter-common/src/hooks/client-hook-launcher.mjs",
|
|
34
34
|
"memorax-code-adapter-common/src/config-utils.mjs",
|
|
35
|
+
"memorax-code-adapter-common/src/setup-completion.mjs",
|
|
35
36
|
"memorax-code-adapter-common/src/hooks/ensure-backend-runner.mjs",
|
|
36
37
|
"memorax-code-adapter-common/src/hooks/hook-runtime-generation.mjs",
|
|
37
38
|
"memorax-code-adapter-common/src/hooks/memory-skill-reminder-hook.mjs",
|
|
@@ -226,10 +227,12 @@ export function ensureClaudePluginInstalled(options = {}) {
|
|
|
226
227
|
}
|
|
227
228
|
|
|
228
229
|
function writeInstalledPluginMetadata(installPath, claudeCommand) {
|
|
230
|
+
const npmExecPath = stringOption(process.env.MEMORAX_CODE_NPM_EXEC_PATH);
|
|
229
231
|
atomicWriteJson(join(installPath, ".memorax-code-package.json"), {
|
|
230
232
|
version: 1,
|
|
231
233
|
memoraxCodeCommand: process.argv[1],
|
|
232
234
|
claudeCommand,
|
|
235
|
+
...(npmExecPath ? { npmExecPath } : {}),
|
|
233
236
|
writtenAt: new Date().toISOString(),
|
|
234
237
|
});
|
|
235
238
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type AutomaticUpdateRecord = Readonly<{
|
|
2
|
+
version: 1;
|
|
3
|
+
installedVersion: string;
|
|
4
|
+
nextCheckAt: string;
|
|
5
|
+
}>;
|
|
6
|
+
|
|
7
|
+
export type AutomaticUpdateState =
|
|
8
|
+
| Readonly<{ status: "absent" }>
|
|
9
|
+
| Readonly<{ status: "valid"; record: AutomaticUpdateRecord }>
|
|
10
|
+
| Readonly<{ status: "invalid"; reason: string }>
|
|
11
|
+
| Readonly<{ status: "unsupported"; version: number }>;
|
|
12
|
+
|
|
13
|
+
export const AUTOMATIC_UPDATE_RECORD_VERSION: 1;
|
|
14
|
+
export const AUTOMATIC_UPDATE_CHECK_INTERVAL_MS: number;
|
|
15
|
+
export const AUTOMATIC_UPDATE_RETRY_INTERVAL_MS: number;
|
|
16
|
+
|
|
17
|
+
export function automaticUpdateStatePath(memoraxCodeHome: string): string;
|
|
18
|
+
export function readAutomaticUpdateState(memoraxCodeHome: string): AutomaticUpdateState;
|
|
19
|
+
export function writeAutomaticUpdateState(options: {
|
|
20
|
+
memoraxCodeHome: string;
|
|
21
|
+
nowMs: number;
|
|
22
|
+
installedVersion: string;
|
|
23
|
+
retry: boolean;
|
|
24
|
+
}): AutomaticUpdateRecord;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { join, resolve } from "node:path";
|
|
2
|
+
import {
|
|
3
|
+
readJsonRuntimeRecord,
|
|
4
|
+
writePrivateJsonRecord,
|
|
5
|
+
} from "./runtime-record.mjs";
|
|
6
|
+
|
|
7
|
+
export const AUTOMATIC_UPDATE_RECORD_VERSION = 1;
|
|
8
|
+
export const AUTOMATIC_UPDATE_CHECK_INTERVAL_MS = 8 * 60 * 60 * 1_000;
|
|
9
|
+
export const AUTOMATIC_UPDATE_RETRY_INTERVAL_MS = 15 * 60 * 1_000;
|
|
10
|
+
|
|
11
|
+
const RECORD_KEYS = new Set(["version", "installedVersion", "nextCheckAt"]);
|
|
12
|
+
|
|
13
|
+
export function automaticUpdateStatePath(memoraxCodeHome) {
|
|
14
|
+
return join(resolve(memoraxCodeHome), "runtime", "install", "automatic-update.json");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function readAutomaticUpdateState(memoraxCodeHome) {
|
|
18
|
+
const state = readJsonRuntimeRecord(automaticUpdateStatePath(memoraxCodeHome));
|
|
19
|
+
if (state.status !== "present") return state;
|
|
20
|
+
const value = state.value;
|
|
21
|
+
if (value.version !== AUTOMATIC_UPDATE_RECORD_VERSION) {
|
|
22
|
+
return Number.isSafeInteger(value.version) && value.version > 0
|
|
23
|
+
? { status: "unsupported", version: value.version }
|
|
24
|
+
: { status: "invalid", reason: "invalid_version" };
|
|
25
|
+
}
|
|
26
|
+
if (Object.keys(value).length !== RECORD_KEYS.size
|
|
27
|
+
|| Object.keys(value).some((key) => !RECORD_KEYS.has(key))) {
|
|
28
|
+
return { status: "invalid", reason: "unknown_or_missing_fields" };
|
|
29
|
+
}
|
|
30
|
+
const installedVersion = nonEmptyString(value.installedVersion);
|
|
31
|
+
const nextCheckAt = timestamp(value.nextCheckAt);
|
|
32
|
+
if (!installedVersion || !nextCheckAt) {
|
|
33
|
+
return { status: "invalid", reason: "invalid_fields" };
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
status: "valid",
|
|
37
|
+
record: {
|
|
38
|
+
version: AUTOMATIC_UPDATE_RECORD_VERSION,
|
|
39
|
+
installedVersion,
|
|
40
|
+
nextCheckAt,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function writeAutomaticUpdateState({ memoraxCodeHome, nowMs, installedVersion, retry }) {
|
|
46
|
+
const timestampMs = Number(nowMs);
|
|
47
|
+
const version = nonEmptyString(installedVersion);
|
|
48
|
+
if (!Number.isFinite(timestampMs) || !version) {
|
|
49
|
+
throw new TypeError("automatic update state requires a timestamp and installed version");
|
|
50
|
+
}
|
|
51
|
+
const record = {
|
|
52
|
+
version: AUTOMATIC_UPDATE_RECORD_VERSION,
|
|
53
|
+
installedVersion: version,
|
|
54
|
+
nextCheckAt: new Date(
|
|
55
|
+
timestampMs + (retry ? AUTOMATIC_UPDATE_RETRY_INTERVAL_MS : AUTOMATIC_UPDATE_CHECK_INTERVAL_MS),
|
|
56
|
+
).toISOString(),
|
|
57
|
+
};
|
|
58
|
+
writePrivateJsonRecord(automaticUpdateStatePath(memoraxCodeHome), record, {
|
|
59
|
+
durableBoundary: memoraxCodeHome,
|
|
60
|
+
});
|
|
61
|
+
return record;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function nonEmptyString(value) {
|
|
65
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function timestamp(value) {
|
|
69
|
+
const candidate = nonEmptyString(value);
|
|
70
|
+
return candidate && Number.isFinite(Date.parse(candidate))
|
|
71
|
+
? new Date(Date.parse(candidate)).toISOString()
|
|
72
|
+
: undefined;
|
|
73
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { accessSync, constants, existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join, win32 } from "node:path";
|
|
4
|
+
|
|
5
|
+
const APP_NAMES = ["WorkBuddy.app", "CodeBuddy.app"];
|
|
6
|
+
const BUNDLED_SEGMENTS = ["Contents", "Resources", "app.asar.unpacked", "cli", "bin", "codebuddy"];
|
|
7
|
+
const WINDOWS_SEGMENTS = [
|
|
8
|
+
["resources", "app.asar.unpacked", "cli", "bin", "codebuddy"],
|
|
9
|
+
["resources", "app.asar.unpacked", "cli", "bin", "codebuddy.exe"],
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Resolve the CodeBuddy executable from the environment, installed adapter
|
|
14
|
+
* metadata, or the WorkBuddy/CodeBuddy application bundle. Hooks are often
|
|
15
|
+
* launched by a GUI process and therefore cannot rely on the user's shell
|
|
16
|
+
* PATH or on npm's environment setup.
|
|
17
|
+
*/
|
|
18
|
+
export function resolveHookCodeBuddyCommand({
|
|
19
|
+
env = process.env,
|
|
20
|
+
pluginRoot,
|
|
21
|
+
homeDir = homedir(),
|
|
22
|
+
platform = process.platform,
|
|
23
|
+
pathExists = commandPathExists,
|
|
24
|
+
} = {}) {
|
|
25
|
+
const configured = stringValue(env.MEMORAX_CODE_CODEBUDDY_COMMAND)
|
|
26
|
+
?? stringValue(env.CODEBUDDY_CLI_PATH)
|
|
27
|
+
?? stringValue(env.WORKBUDDY_CODEBUDDY_PATH);
|
|
28
|
+
if (configured) return configured;
|
|
29
|
+
|
|
30
|
+
const metadataCommand = readMetadataCommand(stringValue(pluginRoot) ?? stringValue(env.CODEBUDDY_PLUGIN_ROOT));
|
|
31
|
+
if (metadataCommand && pathExists(metadataCommand, platform)) return metadataCommand;
|
|
32
|
+
|
|
33
|
+
if (platform === "darwin") {
|
|
34
|
+
for (const root of [join(homeDir, "Applications"), "/Applications"]) {
|
|
35
|
+
for (const appName of APP_NAMES) {
|
|
36
|
+
const command = join(root, appName, ...BUNDLED_SEGMENTS);
|
|
37
|
+
if (pathExists(command, platform)) return command;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (platform === "win32") {
|
|
42
|
+
for (const root of [
|
|
43
|
+
env.LOCALAPPDATA && win32.join(env.LOCALAPPDATA, "Programs", "WorkBuddy"),
|
|
44
|
+
env.LOCALAPPDATA && win32.join(env.LOCALAPPDATA, "Programs", "CodeBuddy"),
|
|
45
|
+
env.LOCALAPPDATA && win32.join(env.LOCALAPPDATA, "WorkBuddy"),
|
|
46
|
+
env.LOCALAPPDATA && win32.join(env.LOCALAPPDATA, "CodeBuddy"),
|
|
47
|
+
env.ProgramFiles && win32.join(env.ProgramFiles, "WorkBuddy"),
|
|
48
|
+
env.ProgramFiles && win32.join(env.ProgramFiles, "CodeBuddy"),
|
|
49
|
+
].filter(Boolean)) {
|
|
50
|
+
for (const segments of WINDOWS_SEGMENTS) {
|
|
51
|
+
const command = win32.join(root, ...segments);
|
|
52
|
+
if (pathExists(command, platform)) return command;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return "codebuddy";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function readMetadataCommand(pluginRoot) {
|
|
60
|
+
if (!pluginRoot) return undefined;
|
|
61
|
+
try {
|
|
62
|
+
const metadata = JSON.parse(readFileSync(join(pluginRoot, ".memorax-code-package.json"), "utf8"));
|
|
63
|
+
return stringValue(metadata?.codeBuddyCommand);
|
|
64
|
+
} catch {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function commandPathExists(command, platform) {
|
|
70
|
+
if (!command.includes("/") && !command.includes("\\")) return true;
|
|
71
|
+
if (!existsSync(command)) return false;
|
|
72
|
+
try {
|
|
73
|
+
accessSync(command, platform === "win32" ? constants.F_OK : constants.X_OK);
|
|
74
|
+
return true;
|
|
75
|
+
} catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function stringValue(value) {
|
|
81
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
82
|
+
}
|
|
@@ -13,6 +13,8 @@ export function readJsonFile(path: string): any;
|
|
|
13
13
|
export function readJsonValue(path: string): any;
|
|
14
14
|
export function readStdinJson(): Promise<any>;
|
|
15
15
|
export function injectClientHookInput(input: Record<string, unknown>): void;
|
|
16
|
+
export function injectClientHookPluginRoot(pluginRoot: string): void;
|
|
17
|
+
export function readClientHookPluginRoot(): string | undefined;
|
|
16
18
|
export function sha256(value: string | NodeJS.ArrayBufferView): string;
|
|
17
19
|
export function stringOption(value: unknown): string | undefined;
|
|
18
20
|
export function atomicWriteJson(path: string, value: unknown): void;
|
|
@@ -24,6 +24,7 @@ const JSON_FILE_LOCK_RETRY_MS = 10;
|
|
|
24
24
|
const PROCESS_START_TOLERANCE_MS = 5000;
|
|
25
25
|
const LOCK_SLEEP_BUFFER = new Int32Array(new SharedArrayBuffer(4));
|
|
26
26
|
const HOOK_INPUT_SYMBOL = Symbol.for("memorax-code.client-hook.input.v1");
|
|
27
|
+
const HOOK_PLUGIN_ROOT_SYMBOL = Symbol.for("memorax-code.client-hook.plugin-root.v1");
|
|
27
28
|
|
|
28
29
|
export function readAdapterState(path) {
|
|
29
30
|
const state = readJsonFile(path);
|
|
@@ -64,6 +65,16 @@ export function injectClientHookInput(input) {
|
|
|
64
65
|
globalThis[HOOK_INPUT_SYMBOL] = input;
|
|
65
66
|
}
|
|
66
67
|
|
|
68
|
+
export function injectClientHookPluginRoot(pluginRoot) {
|
|
69
|
+
const root = stringOption(pluginRoot);
|
|
70
|
+
if (!root) throw new TypeError("client Hook plugin root must be a non-empty string");
|
|
71
|
+
globalThis[HOOK_PLUGIN_ROOT_SYMBOL] = root;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function readClientHookPluginRoot() {
|
|
75
|
+
return stringOption(globalThis[HOOK_PLUGIN_ROOT_SYMBOL]);
|
|
76
|
+
}
|
|
77
|
+
|
|
67
78
|
export function sha256(value) {
|
|
68
79
|
return createHash("sha256").update(value).digest("hex");
|
|
69
80
|
}
|
|
@@ -5,6 +5,7 @@ import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
6
|
import {
|
|
7
7
|
injectClientHookInput,
|
|
8
|
+
injectClientHookPluginRoot,
|
|
8
9
|
readStdinJson,
|
|
9
10
|
stringOption,
|
|
10
11
|
withJsonFileLock,
|
|
@@ -47,6 +48,8 @@ export async function runClientHookLauncher({
|
|
|
47
48
|
});
|
|
48
49
|
if (!selection) return;
|
|
49
50
|
injectClientHookInput(input);
|
|
51
|
+
const originalPluginRoot = stringOption(pluginRoot);
|
|
52
|
+
if (originalPluginRoot) injectClientHookPluginRoot(originalPluginRoot);
|
|
50
53
|
await import(pathToFileURL(selection.modulePath).href);
|
|
51
54
|
} catch (error) {
|
|
52
55
|
if (process.env[debugEnv] === "1") {
|