@memorax/memorax-code 0.1.4 → 0.1.6
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 +8 -19
- package/bin/memorax-code-npm-preinstall.mjs +28 -39
- package/bin/memorax-code-plugin-postinstall.mjs +23 -1537
- package/bin/memorax-code-setup.mjs +1615 -0
- package/bin/memorax-code.mjs +289 -5
- package/docs/configuration.md +66 -17
- package/docs/troubleshooting.md +105 -7
- package/lib/memorax-code-adapter-common/src/config-utils.d.mts +5 -1
- package/lib/memorax-code-adapter-common/src/config-utils.mjs +36 -3
- package/lib/memorax-code-adapter-common/src/credentials/linux-secret-service.mjs +110 -0
- package/lib/memorax-code-adapter-common/src/credentials/macos-keychain.mjs +224 -0
- package/lib/memorax-code-adapter-common/src/credentials/secure-command.mjs +340 -0
- package/lib/memorax-code-adapter-common/src/credentials/trial-credential-record.d.mts +82 -0
- package/lib/memorax-code-adapter-common/src/credentials/trial-credential-record.mjs +183 -0
- package/lib/memorax-code-adapter-common/src/credentials/trial-credential-store.d.mts +82 -0
- package/lib/memorax-code-adapter-common/src/credentials/trial-credential-store.mjs +271 -0
- package/lib/memorax-code-adapter-common/src/credentials/windows-dpapi.mjs +440 -0
- package/lib/memorax-code-adapter-common/src/hooks/memory-skill-reminder-hook.mjs +7 -4
- package/lib/memorax-code-adapter-common/src/setup-completion.d.mts +81 -0
- package/lib/memorax-code-adapter-common/src/setup-completion.mjs +154 -0
- package/lib/memorax-code-backend/dist/clients/claude/memory-hook-runtime.js +21 -2
- package/lib/memorax-code-backend/dist/clients/codex/memory-hook-runtime.js +23 -3
- package/lib/memorax-code-backend/dist/clients/opencode/memory-hook-runtime.js +19 -1
- package/lib/memorax-code-backend/dist/entrypoints/backend-cli.js +17 -16
- package/lib/memorax-code-backend/dist/lifecycle/backend/process.js +21 -0
- package/lib/memorax-code-backend/dist/lifecycle/orchestrator.js +81 -22
- package/lib/memorax-code-backend/dist/memorax-cli.js +3 -0
- package/lib/memorax-code-backend/dist/memory/automatic-retrieval.js +8 -2
- package/lib/memorax-code-backend/dist/memory/automatic-writeback.js +13 -1
- package/lib/memorax-code-backend/dist/memory/cli.js +10 -0
- package/lib/memorax-code-backend/dist/memory/quota-notice.js +208 -0
- package/lib/memorax-code-backend/dist/memory/service.js +11 -0
- package/lib/memorax-code-backend/dist/provider/memorax/adapter.js +4 -2
- package/lib/memorax-code-backend/dist/provider/memorax/http.js +10 -3
- package/lib/memorax-code-backend/dist/provider/memorax/quota.js +26 -0
- package/lib/memorax-code-backend/package.json +2 -2
- 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/memory-turn.mjs +5 -3
- package/lib/memorax-code-claude-adapter/skills/memorax-code/references/memorax-add.md +2 -0
- package/lib/memorax-code-claude-adapter/skills/memorax-code/references/memorax-search.md +4 -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/memorax-code-adapter-common/src/config-utils.d.mts +5 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/config-utils.mjs +36 -3
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/credentials/linux-secret-service.mjs +110 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/credentials/macos-keychain.mjs +224 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/credentials/secure-command.mjs +340 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/credentials/trial-credential-record.d.mts +82 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/credentials/trial-credential-record.mjs +183 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/credentials/trial-credential-store.d.mts +82 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/credentials/trial-credential-store.mjs +271 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/credentials/windows-dpapi.mjs +440 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/hooks/memory-skill-reminder-hook.mjs +7 -4
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/setup-completion.d.mts +81 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/memorax-code-adapter-common/src/setup-completion.mjs +154 -0
- 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/memory-turn.mjs +5 -3
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/memorax-add.md +2 -0
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/memorax-search.md +4 -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/runtime-hooks/memory-skill-reminder.mjs +2 -0
- package/lib/memorax-code-codex-adapter/skills/memorax-code/references/memorax-add.md +2 -0
- package/lib/memorax-code-codex-adapter/skills/memorax-code/references/memorax-search.md +4 -2
- package/lib/memorax-code-dsh-adapter/hooks/repo-memory-job.mjs +5 -2
- package/lib/memorax-code-dsh-adapter/package.json +1 -1
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/memorax-add.md +2 -0
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/memorax-search.md +4 -2
- package/lib/memorax-code-dsh-adapter/src/profile-lifecycle.mjs +158 -7
- package/lib/memorax-code-dsh-adapter/src/runtime-state.mjs +21 -0
- package/lib/memorax-code-opencode-adapter/package.json +1 -1
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/memorax-add.md +2 -0
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/memorax-search.md +4 -2
- package/lib/memorax-code-opencode-adapter/src/plugin.mjs +20 -0
- package/lib/node-version.mjs +1 -1
- package/lib/package-transition.mjs +311 -0
- package/lib/resolve-codex-command.mjs +32 -6
- package/lib/setup-memory-preferences.mjs +113 -0
- package/lib/setup-reconcile.mjs +128 -0
- package/lib/trial-plugin-mark.mjs +171 -0
- package/lib/trial-provision-client.mjs +307 -0
- package/lib/trial-provision-flow.mjs +215 -0
- package/lib/trial-setup.mjs +53 -0
- package/package.json +2 -2
|
@@ -23,10 +23,11 @@ export async function runMemorySkillReminderHook(options, hookInput) {
|
|
|
23
23
|
const result = await evaluateMemorySkillReminder(options, input);
|
|
24
24
|
if (!result) return;
|
|
25
25
|
process.stdout.write(`${JSON.stringify({
|
|
26
|
-
|
|
26
|
+
...(result.systemMessage ? { systemMessage: result.systemMessage } : {}),
|
|
27
|
+
...(result.additionalContext ? { hookSpecificOutput: {
|
|
27
28
|
hookEventName: "UserPromptSubmit",
|
|
28
29
|
additionalContext: result.additionalContext,
|
|
29
|
-
},
|
|
30
|
+
} } : {}),
|
|
30
31
|
})}\n`);
|
|
31
32
|
if (result.reminder) await notifyReminder(options, result.reminder);
|
|
32
33
|
} catch (error) {
|
|
@@ -80,7 +81,8 @@ export async function evaluateMemorySkillReminder(options, input) {
|
|
|
80
81
|
const { memoryReminderDue, supplementalReminderDue } = update;
|
|
81
82
|
|
|
82
83
|
const baseAdditionalContext = stringOption(options.baseAdditionalContext);
|
|
83
|
-
|
|
84
|
+
const systemMessage = stringOption(options.systemMessage);
|
|
85
|
+
if (!baseAdditionalContext && !memoryReminderDue && !supplementalReminderDue && !systemMessage) return undefined;
|
|
84
86
|
const cadenceReminderContext = memoryReminderDue
|
|
85
87
|
? await buildCadenceReminderContext(options, input)
|
|
86
88
|
: undefined;
|
|
@@ -97,7 +99,8 @@ export async function evaluateMemorySkillReminder(options, input) {
|
|
|
97
99
|
...(supplementalReminderDue ? ["post_compaction"] : []),
|
|
98
100
|
];
|
|
99
101
|
return {
|
|
100
|
-
|
|
102
|
+
...(systemMessage ? { systemMessage } : {}),
|
|
103
|
+
...(additionalContext ? { additionalContext } : {}),
|
|
101
104
|
...(reminderContext ? {
|
|
102
105
|
reminder: {
|
|
103
106
|
sessionId,
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { JsonFileLockOptions } from "./config-utils.mjs";
|
|
2
|
+
import {
|
|
3
|
+
RuntimeRecordError,
|
|
4
|
+
type RuntimeRecordWriteResult,
|
|
5
|
+
type RuntimeRecordWriteRuntime,
|
|
6
|
+
} from "./runtime-record.mjs";
|
|
7
|
+
|
|
8
|
+
export type SetupCompletionRecord = Readonly<{
|
|
9
|
+
version: 1;
|
|
10
|
+
state: "complete";
|
|
11
|
+
completedAt: string;
|
|
12
|
+
completedByVersion: string;
|
|
13
|
+
}>;
|
|
14
|
+
|
|
15
|
+
export type SetupCompletionRecordInvalidReason =
|
|
16
|
+
| "unreadable"
|
|
17
|
+
| "malformed_json"
|
|
18
|
+
| "invalid_record"
|
|
19
|
+
| "invalid_version"
|
|
20
|
+
| "unknown_fields"
|
|
21
|
+
| "invalid_state"
|
|
22
|
+
| "invalid_completed_at"
|
|
23
|
+
| "invalid_completed_by_version";
|
|
24
|
+
|
|
25
|
+
export type SetupCompletionRecordState =
|
|
26
|
+
| Readonly<{ status: "absent" }>
|
|
27
|
+
| Readonly<{ status: "valid"; record: SetupCompletionRecord }>
|
|
28
|
+
| Readonly<{ status: "invalid"; reason: SetupCompletionRecordInvalidReason }>
|
|
29
|
+
| Readonly<{ status: "unsupported"; version: number }>;
|
|
30
|
+
|
|
31
|
+
export type WritableSetupCompletionRecordState = Extract<
|
|
32
|
+
SetupCompletionRecordState,
|
|
33
|
+
{ status: "absent" | "valid" }
|
|
34
|
+
>;
|
|
35
|
+
|
|
36
|
+
export type SetupCompletionClearResult = Readonly<{
|
|
37
|
+
path: string;
|
|
38
|
+
removed: boolean;
|
|
39
|
+
}>;
|
|
40
|
+
|
|
41
|
+
export type SetupCompletionLockMutation = Readonly<{
|
|
42
|
+
clear(): SetupCompletionClearResult;
|
|
43
|
+
}>;
|
|
44
|
+
|
|
45
|
+
export const SETUP_COMPLETION_RECORD_VERSION: 1;
|
|
46
|
+
|
|
47
|
+
export class SetupCompletionRecordError extends RuntimeRecordError {
|
|
48
|
+
constructor(
|
|
49
|
+
state: Extract<SetupCompletionRecordState, { status: "invalid" | "unsupported" }>,
|
|
50
|
+
path: string,
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function setupCompletionPath(memoraxCodeHome?: string): string;
|
|
55
|
+
|
|
56
|
+
export function readSetupCompletionRecord(
|
|
57
|
+
memoraxCodeHome?: string,
|
|
58
|
+
): SetupCompletionRecordState;
|
|
59
|
+
|
|
60
|
+
export function writeSetupCompletionRecord(
|
|
61
|
+
options: {
|
|
62
|
+
memoraxCodeHome?: string;
|
|
63
|
+
completedAt: string;
|
|
64
|
+
completedByVersion: string;
|
|
65
|
+
},
|
|
66
|
+
runtime?: RuntimeRecordWriteRuntime,
|
|
67
|
+
): RuntimeRecordWriteResult<SetupCompletionRecord>;
|
|
68
|
+
|
|
69
|
+
export function clearSetupCompletionRecord(
|
|
70
|
+
memoraxCodeHome?: string,
|
|
71
|
+
options?: JsonFileLockOptions,
|
|
72
|
+
): Promise<SetupCompletionClearResult>;
|
|
73
|
+
|
|
74
|
+
export function withSetupCompletionLock<T>(
|
|
75
|
+
memoraxCodeHome: string,
|
|
76
|
+
operation: (
|
|
77
|
+
state: WritableSetupCompletionRecordState,
|
|
78
|
+
mutation: SetupCompletionLockMutation,
|
|
79
|
+
) => T | Promise<T>,
|
|
80
|
+
options?: JsonFileLockOptions,
|
|
81
|
+
): Promise<T>;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { unlinkSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { withJsonFileLockAsync } from "./config-utils.mjs";
|
|
5
|
+
import {
|
|
6
|
+
readJsonRuntimeRecord,
|
|
7
|
+
RuntimeRecordError,
|
|
8
|
+
writePrivateJsonRecord,
|
|
9
|
+
} from "./runtime-record.mjs";
|
|
10
|
+
|
|
11
|
+
export const SETUP_COMPLETION_RECORD_VERSION = 1;
|
|
12
|
+
|
|
13
|
+
const SETUP_COMPLETION_RECORD_KEYS = new Set([
|
|
14
|
+
"version",
|
|
15
|
+
"state",
|
|
16
|
+
"completedAt",
|
|
17
|
+
"completedByVersion",
|
|
18
|
+
]);
|
|
19
|
+
const ISO_TIMESTAMP_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
20
|
+
|
|
21
|
+
export class SetupCompletionRecordError extends RuntimeRecordError {
|
|
22
|
+
constructor(state, path) {
|
|
23
|
+
super({
|
|
24
|
+
name: "Setup completion record",
|
|
25
|
+
path,
|
|
26
|
+
state,
|
|
27
|
+
codePrefix: "SETUP_COMPLETION_RECORD",
|
|
28
|
+
recovery: state.status === "unsupported"
|
|
29
|
+
? "upgrade MemoraX Code or restore a supported setup completion record"
|
|
30
|
+
: "inspect the setup completion record before replacing it",
|
|
31
|
+
});
|
|
32
|
+
this.name = "SetupCompletionRecordError";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function setupCompletionPath(memoraxCodeHome = defaultMemoraxCodeHome()) {
|
|
37
|
+
return join(memoraxCodeHome, "runtime", "setup", "setup-completion.json");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function readSetupCompletionRecord(memoraxCodeHome = defaultMemoraxCodeHome()) {
|
|
41
|
+
const path = setupCompletionPath(memoraxCodeHome);
|
|
42
|
+
const state = readJsonRuntimeRecord(path);
|
|
43
|
+
if (state.status !== "present") return state;
|
|
44
|
+
const value = state.value;
|
|
45
|
+
if (value.version !== SETUP_COMPLETION_RECORD_VERSION) {
|
|
46
|
+
if (Number.isSafeInteger(value.version) && value.version > 0) {
|
|
47
|
+
return { status: "unsupported", version: value.version };
|
|
48
|
+
}
|
|
49
|
+
return { status: "invalid", reason: "invalid_version" };
|
|
50
|
+
}
|
|
51
|
+
if (Object.keys(value).some((key) => !SETUP_COMPLETION_RECORD_KEYS.has(key))) {
|
|
52
|
+
return { status: "invalid", reason: "unknown_fields" };
|
|
53
|
+
}
|
|
54
|
+
if (value.state !== "complete") {
|
|
55
|
+
return { status: "invalid", reason: "invalid_state" };
|
|
56
|
+
}
|
|
57
|
+
const completedAt = isoTimestamp(value.completedAt);
|
|
58
|
+
if (!completedAt) return { status: "invalid", reason: "invalid_completed_at" };
|
|
59
|
+
const completedByVersion = nonEmptyString(value.completedByVersion);
|
|
60
|
+
if (!completedByVersion) {
|
|
61
|
+
return { status: "invalid", reason: "invalid_completed_by_version" };
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
status: "valid",
|
|
65
|
+
record: {
|
|
66
|
+
version: SETUP_COMPLETION_RECORD_VERSION,
|
|
67
|
+
state: "complete",
|
|
68
|
+
completedAt,
|
|
69
|
+
completedByVersion,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function writeSetupCompletionRecord(options, runtime) {
|
|
75
|
+
const memoraxCodeHome = nonEmptyString(options?.memoraxCodeHome) ?? defaultMemoraxCodeHome();
|
|
76
|
+
const completedAt = isoTimestamp(options?.completedAt);
|
|
77
|
+
if (!completedAt) {
|
|
78
|
+
throw new TypeError("Setup completion record requires a valid ISO completedAt timestamp");
|
|
79
|
+
}
|
|
80
|
+
const completedByVersion = nonEmptyString(options?.completedByVersion);
|
|
81
|
+
if (!completedByVersion) {
|
|
82
|
+
throw new TypeError("Setup completion record requires a non-empty completedByVersion");
|
|
83
|
+
}
|
|
84
|
+
const path = setupCompletionPath(memoraxCodeHome);
|
|
85
|
+
const existing = readSetupCompletionRecord(memoraxCodeHome);
|
|
86
|
+
if (existing.status === "invalid" || existing.status === "unsupported") {
|
|
87
|
+
throw new SetupCompletionRecordError(existing, path);
|
|
88
|
+
}
|
|
89
|
+
return writePrivateJsonRecord(path, {
|
|
90
|
+
version: SETUP_COMPLETION_RECORD_VERSION,
|
|
91
|
+
state: "complete",
|
|
92
|
+
completedAt,
|
|
93
|
+
completedByVersion,
|
|
94
|
+
}, {
|
|
95
|
+
...runtime,
|
|
96
|
+
durableBoundary: memoraxCodeHome,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export async function clearSetupCompletionRecord(
|
|
101
|
+
memoraxCodeHome = defaultMemoraxCodeHome(),
|
|
102
|
+
options,
|
|
103
|
+
) {
|
|
104
|
+
const home = nonEmptyString(memoraxCodeHome) ?? defaultMemoraxCodeHome();
|
|
105
|
+
return await withSetupCompletionLock(
|
|
106
|
+
home,
|
|
107
|
+
(_state, mutation) => mutation.clear(),
|
|
108
|
+
options,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export async function withSetupCompletionLock(
|
|
113
|
+
memoraxCodeHome,
|
|
114
|
+
operation,
|
|
115
|
+
options,
|
|
116
|
+
) {
|
|
117
|
+
const home = nonEmptyString(memoraxCodeHome);
|
|
118
|
+
if (!home) throw new TypeError("Setup completion lock requires a MemoraX Code home");
|
|
119
|
+
if (typeof operation !== "function") {
|
|
120
|
+
throw new TypeError("Setup completion lock requires an operation");
|
|
121
|
+
}
|
|
122
|
+
const path = setupCompletionPath(home);
|
|
123
|
+
return await withJsonFileLockAsync(path, async () => {
|
|
124
|
+
let state = readSetupCompletionRecord(home);
|
|
125
|
+
if (state.status === "invalid" || state.status === "unsupported") {
|
|
126
|
+
throw new SetupCompletionRecordError(state, path);
|
|
127
|
+
}
|
|
128
|
+
return await operation(state, {
|
|
129
|
+
clear() {
|
|
130
|
+
if (state.status === "absent") return { path, removed: false };
|
|
131
|
+
unlinkSync(path);
|
|
132
|
+
state = { status: "absent" };
|
|
133
|
+
return { path, removed: true };
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
}, options);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function defaultMemoraxCodeHome() {
|
|
140
|
+
return join(homedir(), ".memorax-code");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function nonEmptyString(value) {
|
|
144
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function isoTimestamp(value) {
|
|
148
|
+
const candidate = nonEmptyString(value);
|
|
149
|
+
return candidate
|
|
150
|
+
&& ISO_TIMESTAMP_PATTERN.test(candidate)
|
|
151
|
+
&& Number.isFinite(Date.parse(candidate))
|
|
152
|
+
? candidate
|
|
153
|
+
: undefined;
|
|
154
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readClaudeInterruptedTranscriptTurn, readClaudeTranscriptTurn, } from "./transcript-turn.js";
|
|
2
2
|
import { retrieveAutomaticMemoryContext } from "../../memory/automatic-retrieval.js";
|
|
3
|
+
import { claimQuotaNotice, createPendingQuotaNoticeRuntime, } from "../../memory/quota-notice.js";
|
|
3
4
|
import { createAutomaticMemoryWritebackRuntime, } from "../../memory/automatic-writeback.js";
|
|
4
5
|
import { createMemoryTurnCoordinator, } from "../../memory/turn-coordinator.js";
|
|
5
6
|
import { createRepositoryMemorySessionRuntime, resolvedRepoMemoryWorktree, } from "../../memory/repository-session.js";
|
|
@@ -10,11 +11,20 @@ const DEFAULT_TRANSCRIPT_READ_ATTEMPTS = 6;
|
|
|
10
11
|
const DEFAULT_TRANSCRIPT_RETRY_DELAY_MS = 100;
|
|
11
12
|
export function createClaudeMemoryHookRuntime(options = {}) {
|
|
12
13
|
const now = options.now ?? (() => Date.now());
|
|
14
|
+
const pendingQuotaNotice = options.pendingQuotaNotice ?? createPendingQuotaNoticeRuntime({
|
|
15
|
+
claimQuotaNotice: options.claimQuotaNotice,
|
|
16
|
+
diagnosticLogger: options.diagnosticLogger,
|
|
17
|
+
env: options.env,
|
|
18
|
+
});
|
|
19
|
+
const ownsPendingQuotaNotice = options.pendingQuotaNotice === undefined;
|
|
13
20
|
const automaticWritebackRuntime = options.turnCoordinator
|
|
14
21
|
? undefined
|
|
15
22
|
: options.automaticWriteback
|
|
16
23
|
? { enqueue: options.automaticWriteback }
|
|
17
|
-
: createAutomaticMemoryWritebackRuntime({
|
|
24
|
+
: createAutomaticMemoryWritebackRuntime({
|
|
25
|
+
diagnosticLogger: options.diagnosticLogger,
|
|
26
|
+
queueQuotaNotice: pendingQuotaNotice.queue,
|
|
27
|
+
});
|
|
18
28
|
const turnCoordinator = options.turnCoordinator ?? createMemoryTurnCoordinator({
|
|
19
29
|
automaticWriteback: automaticWritebackRuntime.enqueue,
|
|
20
30
|
now,
|
|
@@ -86,14 +96,19 @@ export function createClaudeMemoryHookRuntime(options = {}) {
|
|
|
86
96
|
env: options.env,
|
|
87
97
|
now: () => new Date(now()),
|
|
88
98
|
}), options.diagnosticLogger);
|
|
89
|
-
|
|
99
|
+
const processTurnStart = claimAutomaticRetrievalPrompt(automaticRetrievalPrompts, automaticRetrievalPromptLimit, turn.sessionId, turn.promptId);
|
|
100
|
+
if (!processTurnStart) {
|
|
90
101
|
return {
|
|
91
102
|
ok: true,
|
|
92
103
|
...(repoMemoryWorktree ? { repoMemoryWorktree } : {}),
|
|
93
104
|
};
|
|
94
105
|
}
|
|
106
|
+
const pendingUserNotice = repositoryMemory.ok
|
|
107
|
+
? await pendingQuotaNotice.claim(repositoryMemory.memory.config)
|
|
108
|
+
: undefined;
|
|
95
109
|
const retrieval = await retrieveAutomaticMemoryContext({
|
|
96
110
|
diagnosticLogger: options.diagnosticLogger,
|
|
111
|
+
claimQuotaNotice: options.claimQuotaNotice ?? claimQuotaNotice,
|
|
97
112
|
env: options.env ?? process.env,
|
|
98
113
|
fetchImpl: options.fetchImpl,
|
|
99
114
|
memoryObservability: options.memoryObservability,
|
|
@@ -103,10 +118,12 @@ export function createClaudeMemoryHookRuntime(options = {}) {
|
|
|
103
118
|
sessionKey: turn.sessionId,
|
|
104
119
|
traceContext: turn.traceContext,
|
|
105
120
|
});
|
|
121
|
+
const userNotice = [pendingUserNotice, retrieval.userNotice].filter(Boolean).join("\n");
|
|
106
122
|
return {
|
|
107
123
|
ok: true,
|
|
108
124
|
...(repoMemoryWorktree ? { repoMemoryWorktree } : {}),
|
|
109
125
|
...(retrieval.context ? { additionalContext: retrieval.context } : {}),
|
|
126
|
+
...(userNotice ? { userNotice } : {}),
|
|
110
127
|
};
|
|
111
128
|
},
|
|
112
129
|
async writeback(command) {
|
|
@@ -195,6 +212,8 @@ export function createClaudeMemoryHookRuntime(options = {}) {
|
|
|
195
212
|
if (ownsRepositoryMemorySession)
|
|
196
213
|
repositoryMemorySession.close();
|
|
197
214
|
automaticWritebackRuntime?.close?.();
|
|
215
|
+
if (ownsPendingQuotaNotice)
|
|
216
|
+
pendingQuotaNotice.close();
|
|
198
217
|
},
|
|
199
218
|
};
|
|
200
219
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readCodexInterruptedRolloutTurn, readCodexRolloutTurn, } from "./rollout-turn.js";
|
|
2
2
|
import { createAutomaticMemoryWritebackRuntime, } from "../../memory/automatic-writeback.js";
|
|
3
3
|
import { retrieveAutomaticMemoryContext } from "../../memory/automatic-retrieval.js";
|
|
4
|
+
import { claimQuotaNotice, createPendingQuotaNoticeRuntime, } from "../../memory/quota-notice.js";
|
|
4
5
|
import { readCodexSessionTurnIndex } from "./session-turn-index.js";
|
|
5
6
|
import { resolveCodexWorkspaceRoot } from "./workspace-links.js";
|
|
6
7
|
import { createMemoryTurnCoordinator, } from "../../memory/turn-coordinator.js";
|
|
@@ -10,11 +11,20 @@ import { markCurrentCodexTurnOutcome, readCurrentCodexTurn, readOpenCodexTurn, r
|
|
|
10
11
|
const CODEX_MEMORY_TURN_CLIENT = "codex";
|
|
11
12
|
export function createCodexMemoryHookRuntime(options = {}) {
|
|
12
13
|
const now = options.now ?? (() => Date.now());
|
|
14
|
+
const pendingQuotaNotice = options.pendingQuotaNotice ?? createPendingQuotaNoticeRuntime({
|
|
15
|
+
claimQuotaNotice: options.claimQuotaNotice,
|
|
16
|
+
diagnosticLogger: options.diagnosticLogger,
|
|
17
|
+
env: options.env,
|
|
18
|
+
});
|
|
19
|
+
const ownsPendingQuotaNotice = options.pendingQuotaNotice === undefined;
|
|
13
20
|
const automaticWritebackRuntime = options.turnCoordinator
|
|
14
21
|
? undefined
|
|
15
22
|
: options.automaticWriteback
|
|
16
23
|
? { enqueue: options.automaticWriteback }
|
|
17
|
-
: createAutomaticMemoryWritebackRuntime({
|
|
24
|
+
: createAutomaticMemoryWritebackRuntime({
|
|
25
|
+
diagnosticLogger: options.diagnosticLogger,
|
|
26
|
+
queueQuotaNotice: pendingQuotaNotice.queue,
|
|
27
|
+
});
|
|
18
28
|
const turnCoordinator = options.turnCoordinator ?? createMemoryTurnCoordinator({
|
|
19
29
|
automaticWriteback: automaticWritebackRuntime.enqueue,
|
|
20
30
|
now,
|
|
@@ -91,15 +101,21 @@ export function createCodexMemoryHookRuntime(options = {}) {
|
|
|
91
101
|
env: options.env,
|
|
92
102
|
now: () => new Date(now()),
|
|
93
103
|
}), options.diagnosticLogger);
|
|
94
|
-
|
|
95
|
-
|
|
104
|
+
const processTurnStart = turn.turnId
|
|
105
|
+
? claimAutomaticRetrievalTurn(automaticRetrievalTurns, automaticRetrievalTurnLimit, turn.sessionId, turn.turnId)
|
|
106
|
+
: false;
|
|
107
|
+
if (!processTurnStart) {
|
|
96
108
|
return {
|
|
97
109
|
ok: true,
|
|
98
110
|
...(repoMemoryWorktree ? { repoMemoryWorktree } : {}),
|
|
99
111
|
};
|
|
100
112
|
}
|
|
113
|
+
const pendingUserNotice = repositoryMemory.ok
|
|
114
|
+
? await pendingQuotaNotice.claim(repositoryMemory.memory.config)
|
|
115
|
+
: undefined;
|
|
101
116
|
const retrieval = await retrieveAutomaticMemoryContext({
|
|
102
117
|
diagnosticLogger: options.diagnosticLogger,
|
|
118
|
+
claimQuotaNotice: options.claimQuotaNotice ?? claimQuotaNotice,
|
|
103
119
|
env: options.env ?? process.env,
|
|
104
120
|
fetchImpl: options.fetchImpl,
|
|
105
121
|
memoryObservability: options.memoryObservability,
|
|
@@ -109,10 +125,12 @@ export function createCodexMemoryHookRuntime(options = {}) {
|
|
|
109
125
|
sessionKey: turn.sessionId,
|
|
110
126
|
traceContext: turn.traceContext,
|
|
111
127
|
});
|
|
128
|
+
const userNotice = [pendingUserNotice, retrieval.userNotice].filter(Boolean).join("\n");
|
|
112
129
|
return {
|
|
113
130
|
ok: true,
|
|
114
131
|
...(repoMemoryWorktree ? { repoMemoryWorktree } : {}),
|
|
115
132
|
...(retrieval.context ? { additionalContext: retrieval.context } : {}),
|
|
133
|
+
...(userNotice ? { userNotice } : {}),
|
|
116
134
|
};
|
|
117
135
|
},
|
|
118
136
|
async writeback(command) {
|
|
@@ -222,6 +240,8 @@ export function createCodexMemoryHookRuntime(options = {}) {
|
|
|
222
240
|
if (ownsRepositoryMemorySession)
|
|
223
241
|
repositoryMemorySession.close();
|
|
224
242
|
automaticWritebackRuntime?.close?.();
|
|
243
|
+
if (ownsPendingQuotaNotice)
|
|
244
|
+
pendingQuotaNotice.close();
|
|
225
245
|
},
|
|
226
246
|
};
|
|
227
247
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createAutomaticMemoryWritebackRuntime, } from "../../memory/automatic-writeback.js";
|
|
2
2
|
import { retrieveAutomaticMemoryContext } from "../../memory/automatic-retrieval.js";
|
|
3
|
+
import { claimQuotaNotice, createPendingQuotaNoticeRuntime, } from "../../memory/quota-notice.js";
|
|
3
4
|
import { createMemoryTurnCoordinator, } from "../../memory/turn-coordinator.js";
|
|
4
5
|
import { createRepositoryMemorySessionRuntime, resolvedRepoMemoryWorktree, } from "../../memory/repository-session.js";
|
|
5
6
|
import { traceContextFromOpenCodeHookBody } from "../../trace/context.js";
|
|
@@ -8,11 +9,20 @@ import { openCodeMessageTurn, } from "./message-turn.js";
|
|
|
8
9
|
const OPENCODE_MEMORY_TURN_CLIENT = "opencode";
|
|
9
10
|
export function createOpenCodeMemoryHookRuntime(options = {}) {
|
|
10
11
|
const now = options.now ?? (() => Date.now());
|
|
12
|
+
const pendingQuotaNotice = options.pendingQuotaNotice ?? createPendingQuotaNoticeRuntime({
|
|
13
|
+
claimQuotaNotice: options.claimQuotaNotice,
|
|
14
|
+
diagnosticLogger: options.diagnosticLogger,
|
|
15
|
+
env: options.env,
|
|
16
|
+
});
|
|
17
|
+
const ownsPendingQuotaNotice = options.pendingQuotaNotice === undefined;
|
|
11
18
|
const automaticWritebackRuntime = options.turnCoordinator
|
|
12
19
|
? undefined
|
|
13
20
|
: options.automaticWriteback
|
|
14
21
|
? { enqueue: options.automaticWriteback }
|
|
15
|
-
: createAutomaticMemoryWritebackRuntime({
|
|
22
|
+
: createAutomaticMemoryWritebackRuntime({
|
|
23
|
+
diagnosticLogger: options.diagnosticLogger,
|
|
24
|
+
queueQuotaNotice: pendingQuotaNotice.queue,
|
|
25
|
+
});
|
|
16
26
|
const turnCoordinator = options.turnCoordinator ?? createMemoryTurnCoordinator({
|
|
17
27
|
automaticWriteback: automaticWritebackRuntime.enqueue,
|
|
18
28
|
now,
|
|
@@ -85,8 +95,12 @@ export function createOpenCodeMemoryHookRuntime(options = {}) {
|
|
|
85
95
|
break;
|
|
86
96
|
retrievalTurns.delete(oldest);
|
|
87
97
|
}
|
|
98
|
+
const pendingUserNotice = repositoryMemory.ok
|
|
99
|
+
? await pendingQuotaNotice.claim(repositoryMemory.memory.config)
|
|
100
|
+
: undefined;
|
|
88
101
|
const retrieval = await retrieveAutomaticMemoryContext({
|
|
89
102
|
diagnosticLogger: options.diagnosticLogger,
|
|
103
|
+
claimQuotaNotice: options.claimQuotaNotice ?? claimQuotaNotice,
|
|
90
104
|
env: options.env ?? process.env,
|
|
91
105
|
fetchImpl: options.fetchImpl,
|
|
92
106
|
memoryObservability: options.memoryObservability,
|
|
@@ -96,10 +110,12 @@ export function createOpenCodeMemoryHookRuntime(options = {}) {
|
|
|
96
110
|
sessionKey: command.sessionId,
|
|
97
111
|
traceContext,
|
|
98
112
|
});
|
|
113
|
+
const userNotice = [pendingUserNotice, retrieval.userNotice].filter(Boolean).join("\n");
|
|
99
114
|
return {
|
|
100
115
|
ok: true,
|
|
101
116
|
...(repoMemoryWorktree ? { repoMemoryWorktree } : {}),
|
|
102
117
|
...(retrieval.context ? { additionalContext: retrieval.context } : {}),
|
|
118
|
+
...(userNotice ? { userNotice } : {}),
|
|
103
119
|
};
|
|
104
120
|
},
|
|
105
121
|
async writeback(command) {
|
|
@@ -229,6 +245,8 @@ export function createOpenCodeMemoryHookRuntime(options = {}) {
|
|
|
229
245
|
if (ownsRepositoryMemorySession)
|
|
230
246
|
repositoryMemorySession.close();
|
|
231
247
|
automaticWritebackRuntime?.close?.();
|
|
248
|
+
if (ownsPendingQuotaNotice)
|
|
249
|
+
pendingQuotaNotice.close();
|
|
232
250
|
},
|
|
233
251
|
};
|
|
234
252
|
}
|
|
@@ -471,7 +471,8 @@ function isRecord(value) {
|
|
|
471
471
|
}
|
|
472
472
|
function printMemoraxCodeStatus(report) {
|
|
473
473
|
const backend = report.backend;
|
|
474
|
-
|
|
474
|
+
const degraded = report.degraded === true;
|
|
475
|
+
backendLog(`MemoraX Code Backend status: ${report.ok ? blueBold(degraded ? "Enabled (degraded)" : "Enabled") : redBold("Unavailable")}`);
|
|
475
476
|
backendLog(report.ok
|
|
476
477
|
? green("MemoraX Code is ready for new client sessions.")
|
|
477
478
|
: red("MemoraX Code is not ready for new client sessions."));
|
|
@@ -567,7 +568,7 @@ export async function runBackendTokenCommand(serviceOptions, argv, recordWriteRu
|
|
|
567
568
|
}
|
|
568
569
|
}
|
|
569
570
|
function printLifecycleResult(report) {
|
|
570
|
-
const degraded = report.backend?.degraded === true;
|
|
571
|
+
const degraded = report.degraded === true || report.backend?.degraded === true;
|
|
571
572
|
backendLog(`${lifecycleActionLabel(report.action)}: ${report.ok ? green(degraded ? "ok (degraded)" : "ok") : red("needs attention")}`);
|
|
572
573
|
if (report.message)
|
|
573
574
|
backendLog(report.message);
|
|
@@ -651,29 +652,29 @@ function lifecycleGuidance(report) {
|
|
|
651
652
|
"Adapters were not changed for this command.",
|
|
652
653
|
];
|
|
653
654
|
}
|
|
654
|
-
const
|
|
655
|
+
const optionalDshUnavailable = isOptionalUnavailableDshAdapter(report.dshAdapter);
|
|
655
656
|
if ((!report.codexAdapter || isAdapterReady(report.codexAdapter))
|
|
656
657
|
&& (!report.claudeAdapter || isAdapterReady(report.claudeAdapter))
|
|
657
658
|
&& (!report.dshAdapter
|
|
658
659
|
|| isAdapterReady(report.dshAdapter)
|
|
659
|
-
||
|
|
660
|
+
|| optionalDshUnavailable)
|
|
660
661
|
&& (!report.opencodeAdapter || isAdapterReady(report.opencodeAdapter))) {
|
|
661
662
|
return [
|
|
662
|
-
green(
|
|
663
|
+
green(optionalDshUnavailable
|
|
663
664
|
&& !report.codexAdapter
|
|
664
665
|
&& !report.claudeAdapter
|
|
665
666
|
&& !report.opencodeAdapter
|
|
666
|
-
? "Backend is running; the optional DSH integration
|
|
667
|
+
? "Backend is running; the optional DSH integration is unavailable."
|
|
667
668
|
: "Backend is running and available client integrations are enabled."),
|
|
668
|
-
...(
|
|
669
|
-
? [`DSH integration
|
|
669
|
+
...(optionalDshUnavailable
|
|
670
|
+
? [`DSH integration is unavailable: ${report.dshAdapter?.reason ?? "not available"}.`]
|
|
670
671
|
: []),
|
|
671
672
|
...(report.codexAdapter || report.claudeAdapter || report.opencodeAdapter
|
|
672
673
|
? [
|
|
673
674
|
green("Existing sessions with the stable plugin shell select the active runtime on their next user prompt."),
|
|
674
675
|
"Restart or refresh a client only if its plugin shell changed or MemoraX Code is not active on the next prompt.",
|
|
675
676
|
]
|
|
676
|
-
:
|
|
677
|
+
: optionalDshUnavailable
|
|
677
678
|
? []
|
|
678
679
|
: [green("New DSH sessions can use MemoraX Code through the active Profile integration.")]),
|
|
679
680
|
];
|
|
@@ -741,15 +742,15 @@ function lifecycleGuidance(report) {
|
|
|
741
742
|
}
|
|
742
743
|
function statusGuidance(report) {
|
|
743
744
|
if (report.ok) {
|
|
744
|
-
const
|
|
745
|
+
const optionalDshUnavailable = isOptionalUnavailableDshAdapter(report.dshAdapter);
|
|
745
746
|
if (report.dshAdapter
|
|
746
747
|
&& !report.codexAdapter
|
|
747
748
|
&& !report.claudeAdapter
|
|
748
749
|
&& !report.opencodeAdapter) {
|
|
749
|
-
if (
|
|
750
|
+
if (optionalDshUnavailable) {
|
|
750
751
|
return [
|
|
751
|
-
green("Backend is running; the optional DSH integration
|
|
752
|
-
`DSH integration
|
|
752
|
+
green("Backend is running; the optional DSH integration is unavailable."),
|
|
753
|
+
`DSH integration is unavailable: ${report.dshAdapter.reason ?? "not available"}.`,
|
|
753
754
|
];
|
|
754
755
|
}
|
|
755
756
|
return [
|
|
@@ -759,8 +760,8 @@ function statusGuidance(report) {
|
|
|
759
760
|
}
|
|
760
761
|
return [
|
|
761
762
|
green("MemoraX Code is ready; sessions with the stable plugin shell use the active Hook runtime on their next user prompt."),
|
|
762
|
-
...(
|
|
763
|
-
? [`DSH integration
|
|
763
|
+
...(optionalDshUnavailable
|
|
764
|
+
? [`DSH integration is unavailable: ${report.dshAdapter?.reason ?? "not available"}.`]
|
|
764
765
|
: []),
|
|
765
766
|
"Restart or refresh a client only if its plugin shell was installed, changed, or newly enabled, or MemoraX Code is not active on the next prompt.",
|
|
766
767
|
];
|
|
@@ -877,7 +878,7 @@ function claudeAdapterStatusLine(report, codexAdapter) {
|
|
|
877
878
|
}
|
|
878
879
|
function dshAdapterStatusLine(report) {
|
|
879
880
|
if (isOptionalUnavailableDshAdapter(report)) {
|
|
880
|
-
return `
|
|
881
|
+
return `unavailable ${report.reason ?? "not-detected"}`;
|
|
881
882
|
}
|
|
882
883
|
const version = report.version ?? report.dshVersion;
|
|
883
884
|
const tested = version && report.dshVersionTested !== undefined
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
2
3
|
import { join } from "node:path";
|
|
3
4
|
const POSIX_PROCESS_PROBE_TIMEOUT_MS = 2_000;
|
|
4
5
|
const WINDOWS_PROCESS_PROBE_TIMEOUT_MS = 10_000;
|
|
@@ -48,6 +49,26 @@ export function probeProcessCommandLine(pid, runtime = {}) {
|
|
|
48
49
|
if (!Number.isSafeInteger(pid) || pid <= 0) {
|
|
49
50
|
return { status: "inconclusive", reason: "invalid_pid", timeoutMs };
|
|
50
51
|
}
|
|
52
|
+
if (platform === "linux") {
|
|
53
|
+
try {
|
|
54
|
+
const rawCommandLine = (runtime.readFileSync ?? readFileSync)(`/proc/${pid}/cmdline`);
|
|
55
|
+
const commandLine = rawCommandLine.toString("utf8").replaceAll("\0", " ").trim();
|
|
56
|
+
return commandLine
|
|
57
|
+
? { status: "ok", commandLine }
|
|
58
|
+
: { status: "not_found" };
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
const code = error instanceof Error
|
|
62
|
+
? error.code
|
|
63
|
+
: undefined;
|
|
64
|
+
return {
|
|
65
|
+
status: "inconclusive",
|
|
66
|
+
reason: "read_error",
|
|
67
|
+
timeoutMs,
|
|
68
|
+
...(code ? { code } : {}),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
51
72
|
const run = runtime.spawnSync ?? runProbeCommand;
|
|
52
73
|
let command;
|
|
53
74
|
let args;
|