@nxuss/lemma 1.33.0 → 1.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/bin/brain-ingest.js +28 -0
- package/bin/checkpoint.js +6 -0
- package/dashboard/README.md +28 -332
- package/dashboard/dist/assets/{index-Dh-whqJ7.js → index-euG1IvQ7.js} +82 -82
- package/dashboard/dist/index.html +1 -1
- package/dist/cjs/cli/hostHooks.d.ts +3 -1
- package/dist/cjs/cli/hostHooks.d.ts.map +1 -1
- package/dist/cjs/cli/hostHooks.js +31 -13
- package/dist/cjs/cli/hostHooks.js.map +1 -1
- package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
- package/dist/cjs/cli/lemma-proxy.js +20 -1
- package/dist/cjs/cli/lemma-proxy.js.map +1 -1
- package/dist/cjs/mcp/index.js +2 -0
- package/dist/cjs/mcp/index.js.map +1 -1
- package/dist/cjs/mcp/staleBuild.d.ts +19 -0
- package/dist/cjs/mcp/staleBuild.d.ts.map +1 -1
- package/dist/cjs/mcp/staleBuild.js +73 -0
- package/dist/cjs/mcp/staleBuild.js.map +1 -1
- package/dist/cjs/mcp/tools/memory.d.ts.map +1 -1
- package/dist/cjs/mcp/tools/memory.js +84 -13
- package/dist/cjs/mcp/tools/memory.js.map +1 -1
- package/dist/cjs/proxy/DebuggerState.d.ts +3 -0
- package/dist/cjs/proxy/DebuggerState.d.ts.map +1 -0
- package/dist/cjs/proxy/DebuggerState.js +18 -0
- package/dist/cjs/proxy/DebuggerState.js.map +1 -0
- package/dist/cjs/subconscious/ExternalRefs.d.ts +47 -0
- package/dist/cjs/subconscious/ExternalRefs.d.ts.map +1 -0
- package/dist/cjs/subconscious/ExternalRefs.js +131 -0
- package/dist/cjs/subconscious/ExternalRefs.js.map +1 -0
- package/dist/cjs/subconscious/HostRecall.d.ts +22 -0
- package/dist/cjs/subconscious/HostRecall.d.ts.map +1 -1
- package/dist/cjs/subconscious/HostRecall.js +96 -0
- package/dist/cjs/subconscious/HostRecall.js.map +1 -1
- package/dist/cjs/subconscious/TheBrainV2.d.ts +16 -0
- package/dist/cjs/subconscious/TheBrainV2.d.ts.map +1 -1
- package/dist/cjs/subconscious/TheBrainV2.js +17 -0
- package/dist/cjs/subconscious/TheBrainV2.js.map +1 -1
- package/dist/cjs/utils/StoreDraft.d.ts +26 -0
- package/dist/cjs/utils/StoreDraft.d.ts.map +1 -0
- package/dist/cjs/utils/StoreDraft.js +81 -0
- package/dist/cjs/utils/StoreDraft.js.map +1 -0
- package/dist/cjs/utils/ageLabel.d.ts +3 -0
- package/dist/cjs/utils/ageLabel.d.ts.map +1 -0
- package/dist/cjs/utils/ageLabel.js +17 -0
- package/dist/cjs/utils/ageLabel.js.map +1 -0
- package/dist/esm/cli/hostHooks.d.ts +3 -1
- package/dist/esm/cli/hostHooks.d.ts.map +1 -1
- package/dist/esm/cli/hostHooks.js +30 -12
- package/dist/esm/cli/hostHooks.js.map +1 -1
- package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
- package/dist/esm/cli/lemma-proxy.js +20 -1
- package/dist/esm/cli/lemma-proxy.js.map +1 -1
- package/dist/esm/mcp/index.js +2 -0
- package/dist/esm/mcp/index.js.map +1 -1
- package/dist/esm/mcp/staleBuild.d.ts +19 -0
- package/dist/esm/mcp/staleBuild.d.ts.map +1 -1
- package/dist/esm/mcp/staleBuild.js +70 -0
- package/dist/esm/mcp/staleBuild.js.map +1 -1
- package/dist/esm/mcp/tools/memory.d.ts.map +1 -1
- package/dist/esm/mcp/tools/memory.js +84 -13
- package/dist/esm/mcp/tools/memory.js.map +1 -1
- package/dist/esm/proxy/DebuggerState.d.ts +3 -0
- package/dist/esm/proxy/DebuggerState.d.ts.map +1 -0
- package/dist/esm/proxy/DebuggerState.js +14 -0
- package/dist/esm/proxy/DebuggerState.js.map +1 -0
- package/dist/esm/subconscious/ExternalRefs.d.ts +47 -0
- package/dist/esm/subconscious/ExternalRefs.d.ts.map +1 -0
- package/dist/esm/subconscious/ExternalRefs.js +124 -0
- package/dist/esm/subconscious/ExternalRefs.js.map +1 -0
- package/dist/esm/subconscious/HostRecall.d.ts +22 -0
- package/dist/esm/subconscious/HostRecall.d.ts.map +1 -1
- package/dist/esm/subconscious/HostRecall.js +93 -0
- package/dist/esm/subconscious/HostRecall.js.map +1 -1
- package/dist/esm/subconscious/TheBrainV2.d.ts +16 -0
- package/dist/esm/subconscious/TheBrainV2.d.ts.map +1 -1
- package/dist/esm/subconscious/TheBrainV2.js +17 -0
- package/dist/esm/subconscious/TheBrainV2.js.map +1 -1
- package/dist/esm/utils/StoreDraft.d.ts +26 -0
- package/dist/esm/utils/StoreDraft.d.ts.map +1 -0
- package/dist/esm/utils/StoreDraft.js +74 -0
- package/dist/esm/utils/StoreDraft.js.map +1 -0
- package/dist/esm/utils/ageLabel.d.ts +3 -0
- package/dist/esm/utils/ageLabel.d.ts.map +1 -0
- package/dist/esm/utils/ageLabel.js +14 -0
- package/dist/esm/utils/ageLabel.js.map +1 -0
- package/package.json +4 -2
- package/dashboard/dist/assets/index-Dh-whqJ7.js.map +0 -1
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* StoreDraft — the write trigger the Brain was missing.
|
|
4
|
+
*
|
|
5
|
+
* Rule 4 (store only after verification) is right, but nothing prompted a store at the moment
|
|
6
|
+
* something was verified; by the next session the merge, the green pipeline and the closed issue
|
|
7
|
+
* were facts no memory held. A SessionEnd hook cannot speak to the model, so the checkpoint
|
|
8
|
+
* leaves a draft behind and the next UserPromptSubmit surfaces it once (see recallForPrompt):
|
|
9
|
+
* what moved in the last session, with commit shas ready to attach as `refs`.
|
|
10
|
+
*
|
|
11
|
+
* It only records what git shows. It never stores a memory and never decides something was
|
|
12
|
+
* verified — that stays the agent's call.
|
|
13
|
+
*/
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.writeStoreDraft = writeStoreDraft;
|
|
19
|
+
exports.consumeStoreDraft = consumeStoreDraft;
|
|
20
|
+
const fs_1 = __importDefault(require("fs"));
|
|
21
|
+
const path_1 = __importDefault(require("path"));
|
|
22
|
+
const child_process_1 = require("child_process");
|
|
23
|
+
const DRAFT_FILE = path_1.default.join('.lemma', 'session', 'store-draft.json');
|
|
24
|
+
/** Commits older than this were not this session's work. */
|
|
25
|
+
const WINDOW = '12.hours';
|
|
26
|
+
function git(root, args) {
|
|
27
|
+
try {
|
|
28
|
+
return (0, child_process_1.execFileSync)('git', ['-C', root, ...args], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trimEnd();
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return '';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** Writes a draft when the session left something to store; returns it, or null when quiet. */
|
|
35
|
+
function writeStoreDraft(root) {
|
|
36
|
+
try {
|
|
37
|
+
const branch = git(root, ['rev-parse', '--abbrev-ref', 'HEAD']);
|
|
38
|
+
if (!branch)
|
|
39
|
+
return null;
|
|
40
|
+
const commits = git(root, ['log', `--since=${WINDOW}`, '-5', '--format=%h%x09%s'])
|
|
41
|
+
.split('\n')
|
|
42
|
+
.filter(Boolean)
|
|
43
|
+
.map((l) => {
|
|
44
|
+
const [sha, ...rest] = l.split('\t');
|
|
45
|
+
return { sha, subject: rest.join('\t').slice(0, 100) };
|
|
46
|
+
});
|
|
47
|
+
const uncommittedFiles = git(root, ['status', '--porcelain']).split('\n').filter(Boolean).length;
|
|
48
|
+
if (commits.length === 0 && uncommittedFiles === 0)
|
|
49
|
+
return null;
|
|
50
|
+
const draft = { createdAt: new Date().toISOString(), branch, commits, uncommittedFiles };
|
|
51
|
+
const file = path_1.default.join(root, DRAFT_FILE);
|
|
52
|
+
fs_1.default.mkdirSync(path_1.default.dirname(file), { recursive: true });
|
|
53
|
+
fs_1.default.writeFileSync(file, JSON.stringify(draft));
|
|
54
|
+
return draft;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** One-shot: returns the note for a pending draft and deletes it, or '' when there is none. */
|
|
61
|
+
function consumeStoreDraft(root) {
|
|
62
|
+
const file = path_1.default.join(root, DRAFT_FILE);
|
|
63
|
+
try {
|
|
64
|
+
const d = JSON.parse(fs_1.default.readFileSync(file, 'utf8'));
|
|
65
|
+
fs_1.default.unlinkSync(file);
|
|
66
|
+
if (!d || !Array.isArray(d.commits))
|
|
67
|
+
return '';
|
|
68
|
+
const parts = [];
|
|
69
|
+
if (d.commits.length > 0)
|
|
70
|
+
parts.push(`${d.commits.length} commit(s) on ${d.branch} (${d.commits.map((c) => `${c.sha} ${c.subject}`).join('; ')})`);
|
|
71
|
+
if (d.uncommittedFiles > 0)
|
|
72
|
+
parts.push(`${d.uncommittedFiles} uncommitted file(s)`);
|
|
73
|
+
if (parts.length === 0)
|
|
74
|
+
return '';
|
|
75
|
+
return `🧠 The last session ended with ${parts.join(' and ')} and the Brain holds nothing about them unless you stored it. If something was verified (fix confirmed, MR merged, issue closed), store_memory it — attach commit shas, and MR/issue numbers with their state, as \`refs\` so verify_memory can tell when it goes stale.`;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return '';
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=StoreDraft.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StoreDraft.js","sourceRoot":"","sources":["../../../src/utils/StoreDraft.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ageLabel.d.ts","sourceRoot":"","sources":["../../../src/utils/ageLabel.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,GAAE,MAAmB,GAAG,MAAM,CAQlF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ageLabel = ageLabel;
|
|
4
|
+
/** "3d ago" / "5h ago" — a memory's age is half of whether to trust it, so it is always shown. */
|
|
5
|
+
function ageLabel(iso, now = Date.now()) {
|
|
6
|
+
const t = Date.parse(iso || '');
|
|
7
|
+
if (!Number.isFinite(t))
|
|
8
|
+
return 'age unknown';
|
|
9
|
+
const mins = Math.max(0, Math.round((now - t) / 60000));
|
|
10
|
+
if (mins < 60)
|
|
11
|
+
return `${mins}m ago`;
|
|
12
|
+
const hours = Math.round(mins / 60);
|
|
13
|
+
if (hours < 48)
|
|
14
|
+
return `${hours}h ago`;
|
|
15
|
+
return `${Math.round(hours / 24)}d ago`;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=ageLabel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ageLabel.js","sourceRoot":"","sources":["../../../src/utils/ageLabel.ts"],"names":[],"mappings":";;AACA,4BAQC;AATD,kGAAkG;AAClG,SAAgB,QAAQ,CAAC,GAAuB,EAAE,MAAc,IAAI,CAAC,GAAG,EAAE;IACxE,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;IAChC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,aAAa,CAAC;IAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,KAAM,CAAC,CAAC,CAAC;IACzD,IAAI,IAAI,GAAG,EAAE;QAAE,OAAO,GAAG,IAAI,OAAO,CAAC;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IACpC,IAAI,KAAK,GAAG,EAAE;QAAE,OAAO,GAAG,KAAK,OAAO,CAAC;IACvC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,OAAO,CAAC;AAC1C,CAAC"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* FixCapture). Without them the Brain only ever saw Lemma's MCP tools — and agents mostly read,
|
|
5
5
|
* edit and test with their native ones.
|
|
6
6
|
*
|
|
7
|
-
* - Claude Code — `.claude/settings.local.json` PostToolUse (personal, never the team's
|
|
7
|
+
* - Claude Code — `.claude/settings.local.json` PostToolUse + UserPromptSubmit (personal, never the team's
|
|
8
8
|
* versioned settings.json; gitignored if the repo doesn't ignore it yet).
|
|
9
9
|
* - Codex — `~/.codex/hooks.json` PostToolUse, same format as Claude Code.
|
|
10
10
|
* - Cursor — `~/.cursor/hooks.json` postToolUse + postToolUseFailure.
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
*/
|
|
23
23
|
export declare function hookCommand(host: 'claude' | 'codex' | 'cursor'): string;
|
|
24
24
|
export declare const CLAUDE_HOOK_COMMAND: string;
|
|
25
|
+
/** UserPromptSubmit: recall before the agent answers — see HostRecall.recallForPrompt. */
|
|
26
|
+
export declare const CLAUDE_PROMPT_HOOK_COMMAND = "command -v lemma-brain-ingest >/dev/null 2>&1 && lemma-brain-ingest --prompt-submit || true";
|
|
25
27
|
export declare const CLAUDE_HOOK_MATCHER = "Bash|Read|Edit|MultiEdit|Write|NotebookEdit";
|
|
26
28
|
export declare const CODEX_HOOK_MATCHER = "Bash|apply_patch|Edit|Write";
|
|
27
29
|
export declare const CURSOR_POST_MATCHER = "Read|Shell|Write";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hostHooks.d.ts","sourceRoot":"","sources":["../../../src/cli/hostHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;
|
|
1
|
+
{"version":3,"file":"hostHooks.d.ts","sourceRoot":"","sources":["../../../src/cli/hostHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAUH,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAGvE;AAED,eAAO,MAAM,mBAAmB,QAAwB,CAAC;AACzD,0FAA0F;AAC1F,eAAO,MAAM,0BAA0B,gGAA4E,CAAC;AACpH,eAAO,MAAM,mBAAmB,gDAAgD,CAAC;AACjF,eAAO,MAAM,kBAAkB,gCAAgC,CAAC;AAChE,eAAO,MAAM,mBAAmB,qBAAqB,CAAC;AACtD,eAAO,MAAM,sBAAsB,UAAU,CAAC;AAE9C,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6FAA6F;IAC7F,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAgFD,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAsB,GAAG,kBAAkB,CAelF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,MAAqB,GAAG,kBAAkB,CAEjF;AAED,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,IAAI,GAAE,MAAqB,GAAG,kBAAkB,CAkClF;AAID;;;;;GAKG;AACH,eAAO,MAAM,eAAe,szCA0B3B,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,IAAI,GAAE,MAAqB,GAAG,kBAAkB,CAYrF;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,aAAa,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;IACtD,OAAO,EAAE,kBAAkB,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAsB,EAAE,IAAI,GAAE,MAAqB,GAAG,cAAc,EAAE,CAO3G"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* FixCapture). Without them the Brain only ever saw Lemma's MCP tools — and agents mostly read,
|
|
5
5
|
* edit and test with their native ones.
|
|
6
6
|
*
|
|
7
|
-
* - Claude Code — `.claude/settings.local.json` PostToolUse (personal, never the team's
|
|
7
|
+
* - Claude Code — `.claude/settings.local.json` PostToolUse + UserPromptSubmit (personal, never the team's
|
|
8
8
|
* versioned settings.json; gitignored if the repo doesn't ignore it yet).
|
|
9
9
|
* - Codex — `~/.codex/hooks.json` PostToolUse, same format as Claude Code.
|
|
10
10
|
* - Cursor — `~/.cursor/hooks.json` postToolUse + postToolUseFailure.
|
|
@@ -25,16 +25,20 @@ import os from 'os';
|
|
|
25
25
|
import path from 'path';
|
|
26
26
|
import { execFileSync } from 'child_process';
|
|
27
27
|
const HOOK_MARK = 'lemma-brain-ingest --hook-result';
|
|
28
|
+
const PROMPT_MARK = 'lemma-brain-ingest --prompt-submit';
|
|
28
29
|
export function hookCommand(host) {
|
|
29
30
|
const flag = host === 'claude' ? '' : ` --host=${host}`;
|
|
30
31
|
return `command -v lemma-brain-ingest >/dev/null 2>&1 && ${HOOK_MARK}${flag} || true`;
|
|
31
32
|
}
|
|
32
33
|
export const CLAUDE_HOOK_COMMAND = hookCommand('claude');
|
|
34
|
+
/** UserPromptSubmit: recall before the agent answers — see HostRecall.recallForPrompt. */
|
|
35
|
+
export const CLAUDE_PROMPT_HOOK_COMMAND = `command -v lemma-brain-ingest >/dev/null 2>&1 && ${PROMPT_MARK} || true`;
|
|
33
36
|
export const CLAUDE_HOOK_MATCHER = 'Bash|Read|Edit|MultiEdit|Write|NotebookEdit';
|
|
34
37
|
export const CODEX_HOOK_MATCHER = 'Bash|apply_patch|Edit|Write';
|
|
35
38
|
export const CURSOR_POST_MATCHER = 'Read|Shell|Write';
|
|
36
39
|
export const CURSOR_FAILURE_MATCHER = 'Shell';
|
|
37
|
-
const
|
|
40
|
+
const isOursWith = (mark) => (h) => typeof h?.command === 'string' && h.command.includes(mark);
|
|
41
|
+
const isOurs = isOursWith(HOOK_MARK);
|
|
38
42
|
function readJsonObject(file) {
|
|
39
43
|
if (!fs.existsSync(file))
|
|
40
44
|
return {};
|
|
@@ -55,15 +59,17 @@ function writeJson(file, value) {
|
|
|
55
59
|
* Lemma's hook object is identified by its command; when a user put their own hooks in the same
|
|
56
60
|
* entry, Lemma's moves to an entry of its own instead of widening their matcher.
|
|
57
61
|
*/
|
|
58
|
-
function mergeMatcherHooks(file, event, matcher, command) {
|
|
59
|
-
const
|
|
62
|
+
function mergeMatcherHooks(file, event, matcher, command, mark = HOOK_MARK) {
|
|
63
|
+
const isMine = isOursWith(mark);
|
|
64
|
+
// Events without a tool (UserPromptSubmit) take no matcher; the key is left out entirely.
|
|
65
|
+
const wanted = { ...(matcher !== undefined ? { matcher } : {}), hooks: [{ type: 'command', command }] };
|
|
60
66
|
const settings = readJsonObject(file);
|
|
61
67
|
if (!settings) {
|
|
62
68
|
return { status: 'manual', file, snippet: JSON.stringify({ hooks: { [event]: [wanted] } }, null, 2) };
|
|
63
69
|
}
|
|
64
70
|
settings.hooks = settings.hooks && typeof settings.hooks === 'object' ? settings.hooks : {};
|
|
65
71
|
const list = Array.isArray(settings.hooks[event]) ? settings.hooks[event] : [];
|
|
66
|
-
const ours = list.find((e) => Array.isArray(e?.hooks) && e.hooks.some(
|
|
72
|
+
const ours = list.find((e) => Array.isArray(e?.hooks) && e.hooks.some(isMine));
|
|
67
73
|
let status;
|
|
68
74
|
if (!ours) {
|
|
69
75
|
list.push(wanted);
|
|
@@ -72,13 +78,14 @@ function mergeMatcherHooks(file, event, matcher, command) {
|
|
|
72
78
|
else if (JSON.stringify({ matcher: ours.matcher, hooks: ours.hooks }) === JSON.stringify(wanted)) {
|
|
73
79
|
status = 'unchanged';
|
|
74
80
|
}
|
|
75
|
-
else if (ours.hooks.every(
|
|
76
|
-
|
|
81
|
+
else if (ours.hooks.every(isMine)) {
|
|
82
|
+
if (matcher !== undefined)
|
|
83
|
+
ours.matcher = matcher;
|
|
77
84
|
ours.hooks = wanted.hooks;
|
|
78
85
|
status = 'updated';
|
|
79
86
|
}
|
|
80
87
|
else {
|
|
81
|
-
ours.hooks = ours.hooks.filter((h) => !
|
|
88
|
+
ours.hooks = ours.hooks.filter((h) => !isMine(h));
|
|
82
89
|
list.push(wanted);
|
|
83
90
|
status = 'updated';
|
|
84
91
|
}
|
|
@@ -107,11 +114,22 @@ function ensureClaudeLocalIgnored(cwd) {
|
|
|
107
114
|
return true;
|
|
108
115
|
}
|
|
109
116
|
export function installClaudeHooks(cwd = process.cwd()) {
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
117
|
+
const file = path.join(cwd, '.claude', 'settings.local.json');
|
|
118
|
+
const post = mergeMatcherHooks(file, 'PostToolUse', CLAUDE_HOOK_MATCHER, CLAUDE_HOOK_COMMAND);
|
|
119
|
+
if (post.status === 'manual')
|
|
120
|
+
return post;
|
|
121
|
+
const prompt = mergeMatcherHooks(file, 'UserPromptSubmit', undefined, CLAUDE_PROMPT_HOOK_COMMAND, PROMPT_MARK);
|
|
122
|
+
if (prompt.status === 'manual')
|
|
123
|
+
return prompt;
|
|
113
124
|
const gitignored = ensureClaudeLocalIgnored(cwd);
|
|
114
|
-
|
|
125
|
+
// Both new → a fresh install. Extending a project that already had one half is an update.
|
|
126
|
+
const parts = [post.status, prompt.status];
|
|
127
|
+
const status = parts.every((x) => x === 'unchanged')
|
|
128
|
+
? 'unchanged'
|
|
129
|
+
: parts.every((x) => x === 'installed')
|
|
130
|
+
? 'installed'
|
|
131
|
+
: 'updated';
|
|
132
|
+
return { status, file, ...(gitignored ? { gitignored } : {}) };
|
|
115
133
|
}
|
|
116
134
|
export function installCodexHooks(home = os.homedir()) {
|
|
117
135
|
return mergeMatcherHooks(path.join(home, '.codex', 'hooks.json'), 'PostToolUse', CODEX_HOOK_MATCHER, hookCommand('codex'));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hostHooks.js","sourceRoot":"","sources":["../../../src/cli/hostHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,SAAS,GAAG,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"hostHooks.js","sourceRoot":"","sources":["../../../src/cli/hostHooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lemma-proxy.d.ts","sourceRoot":"","sources":["../../../src/cli/lemma-proxy.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"lemma-proxy.d.ts","sourceRoot":"","sources":["../../../src/cli/lemma-proxy.ts"],"names":[],"mappings":";AAycA,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CA8DvF;AAifD,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGtD;AAivDD,wBAAsB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA8KhL"}
|
|
@@ -47,6 +47,7 @@ import { detectProjectName, isProjectMismatch } from '../utils/ProjectIdentity.j
|
|
|
47
47
|
import { ProjectRegistry } from '../proxy/ProjectRegistry.js';
|
|
48
48
|
import { shouldInject, buildMinimalContext, buildDeepContext, sniffProjectFromMessages } from '../proxy/ContextInjector.js';
|
|
49
49
|
import { savingsLedger } from '../utils/SavingsLedger.js';
|
|
50
|
+
import { isDebuggerPaused, setDebuggerPaused } from '../proxy/DebuggerState.js';
|
|
50
51
|
import { CACHE_DIR, PID_FILE, PORT_FILE, STATS_FILE, USAGE_FILE, LICENSE_FILE, CLIPBOARD_PID_FILE, FREE_TIER_LIMIT } from '../proxy/ProjectStore.js';
|
|
51
52
|
import { installBrainHooks } from './gitHooks.js';
|
|
52
53
|
import { installHostHooks } from './hostHooks.js';
|
|
@@ -1002,7 +1003,7 @@ class LemmaServer {
|
|
|
1002
1003
|
setupRoutes() {
|
|
1003
1004
|
this.app.get('/health', async (req, res) => {
|
|
1004
1005
|
const gs = gatekeeper.getStatus();
|
|
1005
|
-
res.json({ status: 'ok', project: this.projectName, mode: gs.mode, tier: gs.isPro ? 'pro' : 'free', port: this.port });
|
|
1006
|
+
res.json({ status: 'ok', version: VERSION, project: this.projectName, mode: gs.mode, tier: gs.isPro ? 'pro' : 'free', port: this.port });
|
|
1006
1007
|
});
|
|
1007
1008
|
// MCP Status endpoint
|
|
1008
1009
|
this.app.get('/api/mcp-status', (req, res) => {
|
|
@@ -1032,6 +1033,20 @@ class LemmaServer {
|
|
|
1032
1033
|
console.log(`🔄 [MCP] Toggled ${state}`);
|
|
1033
1034
|
res.json({ enabled: MCP_STATUS.mcpEnabled, status: state });
|
|
1034
1035
|
});
|
|
1036
|
+
// Debugger pause/resume (dashboard debugger panel)
|
|
1037
|
+
this.app.get('/api/debugger/state', (req, res) => {
|
|
1038
|
+
res.json({ paused: isDebuggerPaused() });
|
|
1039
|
+
});
|
|
1040
|
+
this.app.post('/api/debugger/pause', (req, res) => {
|
|
1041
|
+
setDebuggerPaused(true);
|
|
1042
|
+
console.log('⏸️ [Debugger] Paused — new completions are refused until resumed');
|
|
1043
|
+
res.json({ paused: true, timestamp: new Date().toISOString() });
|
|
1044
|
+
});
|
|
1045
|
+
this.app.post('/api/debugger/resume', (req, res) => {
|
|
1046
|
+
setDebuggerPaused(false);
|
|
1047
|
+
console.log('▶️ [Debugger] Resumed');
|
|
1048
|
+
res.json({ resumed: true, paused: false, timestamp: new Date().toISOString() });
|
|
1049
|
+
});
|
|
1035
1050
|
// Project registration from MCP handshake
|
|
1036
1051
|
this.app.post('/api/handshake', (req, res) => {
|
|
1037
1052
|
const { projectPath, projectName, stack } = req.body;
|
|
@@ -1826,6 +1841,10 @@ class LemmaServer {
|
|
|
1826
1841
|
const tier = pro ? 'pro' : 'standard';
|
|
1827
1842
|
const isStream = !!req.body.stream;
|
|
1828
1843
|
let historyTokensSaved = 0;
|
|
1844
|
+
if (isDebuggerPaused()) {
|
|
1845
|
+
res.setHeader('Retry-After', '5');
|
|
1846
|
+
return res.status(503).json({ error: { message: 'Lemma is paused from the dashboard debugger. Resume it to continue.' } });
|
|
1847
|
+
}
|
|
1829
1848
|
if (!pro) {
|
|
1830
1849
|
const usage = await loadUsage();
|
|
1831
1850
|
if (usage.count >= FREE_TIER_LIMIT) {
|