memorix 1.1.7 → 1.1.8
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/CHANGELOG.md +13 -0
- package/CLAUDE.md +6 -1
- package/README.md +21 -0
- package/README.zh-CN.md +21 -0
- package/TEAM.md +86 -86
- package/dist/cli/index.js +730 -150
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/static/index.html +201 -201
- package/dist/dashboard/static/style.css +3584 -3584
- package/dist/index.js +15 -8
- package/dist/index.js.map +1 -1
- package/dist/memcode-runtime/CHANGELOG.md +13 -0
- package/dist/memcode-runtime/package.json +4 -4
- package/dist/sdk.js +15 -8
- package/dist/sdk.js.map +1 -1
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +18 -0
- package/docs/DESIGN_DECISIONS.md +357 -357
- package/docs/SETUP.md +10 -0
- package/docs/dev-log/progress.txt +35 -26
- package/package.json +1 -1
- package/src/audit/index.ts +156 -156
- package/src/cli/commands/agent-integrations.ts +623 -0
- package/src/cli/commands/audit-list.ts +89 -89
- package/src/cli/commands/background.ts +659 -659
- package/src/cli/commands/cleanup.ts +255 -255
- package/src/cli/commands/doctor.ts +23 -0
- package/src/cli/commands/formation.ts +48 -48
- package/src/cli/commands/git-hook-install.ts +111 -111
- package/src/cli/commands/handoff.ts +66 -66
- package/src/cli/commands/hooks-status.ts +63 -63
- package/src/cli/commands/ingest-commit.ts +153 -153
- package/src/cli/commands/ingest-image.ts +73 -73
- package/src/cli/commands/ingest-log.ts +180 -180
- package/src/cli/commands/ingest.ts +44 -44
- package/src/cli/commands/integrate-shared.ts +15 -15
- package/src/cli/commands/lock.ts +96 -96
- package/src/cli/commands/message.ts +121 -121
- package/src/cli/commands/poll.ts +70 -70
- package/src/cli/commands/purge-all-memory.ts +85 -85
- package/src/cli/commands/purge-project-memory.ts +83 -83
- package/src/cli/commands/reasoning.ts +132 -132
- package/src/cli/commands/repair.ts +60 -0
- package/src/cli/commands/retention.ts +108 -108
- package/src/cli/commands/serve-shared.ts +118 -118
- package/src/cli/commands/setup.ts +3 -3
- package/src/cli/commands/skills.ts +123 -123
- package/src/cli/commands/task.ts +192 -192
- package/src/cli/commands/transfer.ts +73 -73
- package/src/cli/commands/uninstall-project-artifacts.ts +85 -85
- package/src/cli/index.ts +3 -1
- package/src/cli/tui/ChatView.tsx +234 -234
- package/src/cli/tui/CommandBar.tsx +312 -312
- package/src/cli/tui/ContextRail.tsx +118 -118
- package/src/cli/tui/HeaderBar.tsx +72 -72
- package/src/cli/tui/LogoBanner.tsx +51 -51
- package/src/cli/tui/Panels.tsx +632 -632
- package/src/cli/tui/Sidebar.tsx +179 -179
- package/src/cli/tui/chat-service.ts +742 -742
- package/src/cli/tui/data.ts +547 -547
- package/src/cli/tui/index.ts +41 -41
- package/src/cli/tui/markdown-render.tsx +371 -371
- package/src/cli/tui/theme.ts +178 -178
- package/src/cli/tui/use-mouse.ts +157 -157
- package/src/cli/tui/useNavigation.ts +56 -56
- package/src/cli/update-checker.ts +211 -211
- package/src/cli/version.ts +7 -7
- package/src/cli/workbench.ts +1 -1
- package/src/codegraph/context-pack.ts +5 -1
- package/src/codegraph/lite-provider.ts +5 -1
- package/src/codegraph/project-context.ts +5 -1
- package/src/compact/token-budget.ts +74 -74
- package/src/config/behavior.ts +59 -59
- package/src/dashboard/project-classification.ts +64 -64
- package/src/dashboard/static/index.html +201 -201
- package/src/dashboard/static/style.css +3584 -3584
- package/src/embedding/fastembed-provider.ts +142 -142
- package/src/embedding/transformers-provider.ts +111 -111
- package/src/git/extractor.ts +209 -209
- package/src/git/hooks-path.ts +85 -85
- package/src/git/noise-filter.ts +210 -210
- package/src/hooks/installers/index.ts +4 -4
- package/src/hooks/official-skills.ts +1 -1
- package/src/hooks/pattern-detector.ts +173 -173
- package/src/hooks/rules/memorix-agent-rules.md +2 -2
- package/src/hooks/significance-filter.ts +250 -250
- package/src/llm/memory-manager.ts +328 -328
- package/src/llm/provider.ts +885 -885
- package/src/llm/quality.ts +248 -248
- package/src/memory/attribution-guard.ts +249 -249
- package/src/memory/auto-relations.ts +107 -107
- package/src/memory/consolidation.ts +302 -302
- package/src/memory/disclosure-policy.ts +141 -141
- package/src/memory/entity-extractor.ts +197 -197
- package/src/memory/formation/evaluate.ts +217 -217
- package/src/memory/formation/extract.ts +361 -361
- package/src/memory/formation/index.ts +417 -417
- package/src/memory/formation/resolve.ts +344 -344
- package/src/memory/formation/types.ts +315 -315
- package/src/memory/freshness.ts +122 -122
- package/src/memory/graph.ts +197 -197
- package/src/memory/refs.ts +94 -94
- package/src/memory/retention.ts +433 -433
- package/src/memory/secret-filter.ts +79 -79
- package/src/memory/session.ts +523 -523
- package/src/multimodal/image-loader.ts +143 -143
- package/src/orchestrate/adapters/claude-stream.ts +192 -192
- package/src/orchestrate/adapters/claude.ts +111 -111
- package/src/orchestrate/adapters/codex-stream.ts +134 -134
- package/src/orchestrate/adapters/codex.ts +41 -41
- package/src/orchestrate/adapters/gemini-stream.ts +166 -166
- package/src/orchestrate/adapters/gemini.ts +42 -42
- package/src/orchestrate/adapters/index.ts +73 -73
- package/src/orchestrate/adapters/opencode-stream.ts +143 -143
- package/src/orchestrate/adapters/opencode.ts +47 -47
- package/src/orchestrate/adapters/spawn-helper.ts +286 -286
- package/src/orchestrate/adapters/types.ts +77 -77
- package/src/orchestrate/capability-router.ts +284 -284
- package/src/orchestrate/context-compact.ts +188 -188
- package/src/orchestrate/cost-tracker.ts +219 -219
- package/src/orchestrate/error-recovery.ts +191 -191
- package/src/orchestrate/evidence.ts +140 -140
- package/src/orchestrate/ledger.ts +110 -110
- package/src/orchestrate/memorix-bridge.ts +380 -380
- package/src/orchestrate/output-budget.ts +80 -80
- package/src/orchestrate/permission.ts +152 -152
- package/src/orchestrate/pipeline-trace.ts +131 -131
- package/src/orchestrate/prompt-builder.ts +155 -155
- package/src/orchestrate/ring-buffer.ts +37 -37
- package/src/orchestrate/task-graph.ts +389 -389
- package/src/orchestrate/verify-gate.ts +219 -219
- package/src/orchestrate/worktree.ts +232 -232
- package/src/project/aliases.ts +374 -374
- package/src/project/detector.ts +268 -268
- package/src/rules/adapters/claude-code.ts +99 -99
- package/src/rules/adapters/codex.ts +97 -97
- package/src/rules/adapters/copilot.ts +124 -124
- package/src/rules/adapters/cursor.ts +114 -114
- package/src/rules/adapters/kiro.ts +126 -126
- package/src/rules/adapters/trae.ts +56 -56
- package/src/rules/adapters/windsurf.ts +83 -83
- package/src/rules/syncer.ts +235 -235
- package/src/sdk.ts +327 -327
- package/src/search/intent-detector.ts +289 -289
- package/src/search/query-expansion.ts +52 -52
- package/src/server/formation-timeout.ts +27 -27
- package/src/skills/mini-skills.ts +386 -386
- package/src/store/chat-store.ts +119 -119
- package/src/store/file-lock.ts +100 -100
- package/src/store/graph-store.ts +249 -249
- package/src/store/mini-skill-store.ts +349 -349
- package/src/store/obs-store.ts +255 -255
- package/src/store/persistence-json.ts +212 -212
- package/src/store/persistence.ts +291 -291
- package/src/store/project-affinity.ts +195 -195
- package/src/store/session-store.ts +259 -259
- package/src/store/sqlite-store.ts +339 -339
- package/src/team/event-bus.ts +76 -76
- package/src/team/file-locks.ts +173 -173
- package/src/team/handoff.ts +167 -167
- package/src/team/messages.ts +203 -203
- package/src/team/poll.ts +132 -132
- package/src/team/tasks.ts +211 -211
- package/src/wiki/generator.ts +237 -237
- package/src/wiki/knowledge-graph.ts +334 -334
- package/src/wiki/types.ts +85 -85
- package/src/workspace/mcp-adapters/codex.ts +191 -191
- package/src/workspace/mcp-adapters/copilot.ts +105 -105
- package/src/workspace/mcp-adapters/cursor.ts +53 -53
- package/src/workspace/mcp-adapters/kiro.ts +64 -64
- package/src/workspace/mcp-adapters/opencode.ts +123 -123
- package/src/workspace/mcp-adapters/trae.ts +134 -134
- package/src/workspace/mcp-adapters/windsurf.ts +91 -91
- package/src/workspace/sanitizer.ts +60 -60
- package/src/workspace/workflow-sync.ts +131 -131
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
import { defineCommand } from 'citty';
|
|
2
|
-
import { getAllObservations } from '../../memory/observations.js';
|
|
3
|
-
import { archiveExpired, explainRetention, getArchiveCandidates, getRetentionSummary, getRetentionZone, rankByRelevance } from '../../memory/retention.js';
|
|
4
|
-
import type { MemorixDocument } from '../../types.js';
|
|
5
|
-
import { emitError, emitResult, getCliProjectContext } from './operator-shared.js';
|
|
6
|
-
|
|
7
|
-
function toDocument(obs: Awaited<ReturnType<typeof getAllObservations>>[number]): MemorixDocument {
|
|
8
|
-
return {
|
|
9
|
-
id: `obs-${obs.id}`,
|
|
10
|
-
observationId: obs.id,
|
|
11
|
-
entityName: obs.entityName,
|
|
12
|
-
type: obs.type,
|
|
13
|
-
title: obs.title,
|
|
14
|
-
narrative: obs.narrative,
|
|
15
|
-
facts: obs.facts.join('\n'),
|
|
16
|
-
filesModified: obs.filesModified.join('\n'),
|
|
17
|
-
concepts: obs.concepts.join(', '),
|
|
18
|
-
tokens: obs.tokens,
|
|
19
|
-
createdAt: obs.createdAt,
|
|
20
|
-
projectId: obs.projectId,
|
|
21
|
-
accessCount: 0,
|
|
22
|
-
lastAccessedAt: '',
|
|
23
|
-
status: obs.status ?? 'active',
|
|
24
|
-
source: obs.source ?? 'agent',
|
|
25
|
-
sourceDetail: obs.sourceDetail ?? '',
|
|
26
|
-
valueCategory: obs.valueCategory ?? '',
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export default defineCommand({
|
|
31
|
-
meta: {
|
|
32
|
-
name: 'retention',
|
|
33
|
-
description: 'Inspect retention state and archive expired memories',
|
|
34
|
-
},
|
|
35
|
-
args: {
|
|
36
|
-
json: { type: 'boolean', description: 'Emit machine-readable JSON output' },
|
|
37
|
-
},
|
|
38
|
-
run: async ({ args }) => {
|
|
39
|
-
const action = (args._ as string[])?.[0] || '';
|
|
40
|
-
const asJson = !!args.json;
|
|
41
|
-
|
|
42
|
-
try {
|
|
43
|
-
const { project, dataDir } = await getCliProjectContext();
|
|
44
|
-
const activeDocs = getAllObservations()
|
|
45
|
-
.filter((obs) => obs.projectId === project.id && (obs.status ?? 'active') === 'active')
|
|
46
|
-
.map(toDocument);
|
|
47
|
-
|
|
48
|
-
switch (action) {
|
|
49
|
-
case 'status': {
|
|
50
|
-
const summary = getRetentionSummary(activeDocs);
|
|
51
|
-
const archiveCandidates = getArchiveCandidates(activeDocs);
|
|
52
|
-
const ranked = rankByRelevance(activeDocs).slice(0, 5);
|
|
53
|
-
emitResult(
|
|
54
|
-
{ project, summary, archiveCandidates, ranked },
|
|
55
|
-
[
|
|
56
|
-
`Retention status for ${project.name}`,
|
|
57
|
-
`- Active: ${summary.active}`,
|
|
58
|
-
`- Stale: ${summary.stale}`,
|
|
59
|
-
`- Archive candidates: ${summary.archiveCandidates}`,
|
|
60
|
-
`- Immune: ${summary.immune}`,
|
|
61
|
-
].join('\n'),
|
|
62
|
-
asJson,
|
|
63
|
-
);
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
case 'archive': {
|
|
68
|
-
const result = await archiveExpired(dataDir);
|
|
69
|
-
emitResult(
|
|
70
|
-
{ project, result },
|
|
71
|
-
result.archived === 0
|
|
72
|
-
? 'No expired observations to archive.'
|
|
73
|
-
: `Archived ${result.archived} expired observation(s); ${result.remaining} active observation(s) remain.`,
|
|
74
|
-
asJson,
|
|
75
|
-
);
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
case 'stale': {
|
|
80
|
-
const stale = activeDocs
|
|
81
|
-
.filter((doc) => getRetentionZone(doc) !== 'active')
|
|
82
|
-
.map((doc) => explainRetention(doc));
|
|
83
|
-
emitResult(
|
|
84
|
-
{ project, stale },
|
|
85
|
-
stale.length === 0
|
|
86
|
-
? 'No stale or archive-candidate observations.'
|
|
87
|
-
: stale
|
|
88
|
-
.map((entry) => `- #${entry.observationId}: ${entry.summary}`)
|
|
89
|
-
.join('\n'),
|
|
90
|
-
asJson,
|
|
91
|
-
);
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
default:
|
|
96
|
-
console.log('Memorix Retention Commands');
|
|
97
|
-
console.log('');
|
|
98
|
-
console.log('Usage:');
|
|
99
|
-
console.log(' memorix retention status');
|
|
100
|
-
console.log(' memorix retention stale');
|
|
101
|
-
console.log(' memorix retention archive');
|
|
102
|
-
}
|
|
103
|
-
} catch (error) {
|
|
104
|
-
emitError(error instanceof Error ? error.message : String(error), asJson);
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
|
-
});
|
|
108
|
-
|
|
1
|
+
import { defineCommand } from 'citty';
|
|
2
|
+
import { getAllObservations } from '../../memory/observations.js';
|
|
3
|
+
import { archiveExpired, explainRetention, getArchiveCandidates, getRetentionSummary, getRetentionZone, rankByRelevance } from '../../memory/retention.js';
|
|
4
|
+
import type { MemorixDocument } from '../../types.js';
|
|
5
|
+
import { emitError, emitResult, getCliProjectContext } from './operator-shared.js';
|
|
6
|
+
|
|
7
|
+
function toDocument(obs: Awaited<ReturnType<typeof getAllObservations>>[number]): MemorixDocument {
|
|
8
|
+
return {
|
|
9
|
+
id: `obs-${obs.id}`,
|
|
10
|
+
observationId: obs.id,
|
|
11
|
+
entityName: obs.entityName,
|
|
12
|
+
type: obs.type,
|
|
13
|
+
title: obs.title,
|
|
14
|
+
narrative: obs.narrative,
|
|
15
|
+
facts: obs.facts.join('\n'),
|
|
16
|
+
filesModified: obs.filesModified.join('\n'),
|
|
17
|
+
concepts: obs.concepts.join(', '),
|
|
18
|
+
tokens: obs.tokens,
|
|
19
|
+
createdAt: obs.createdAt,
|
|
20
|
+
projectId: obs.projectId,
|
|
21
|
+
accessCount: 0,
|
|
22
|
+
lastAccessedAt: '',
|
|
23
|
+
status: obs.status ?? 'active',
|
|
24
|
+
source: obs.source ?? 'agent',
|
|
25
|
+
sourceDetail: obs.sourceDetail ?? '',
|
|
26
|
+
valueCategory: obs.valueCategory ?? '',
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default defineCommand({
|
|
31
|
+
meta: {
|
|
32
|
+
name: 'retention',
|
|
33
|
+
description: 'Inspect retention state and archive expired memories',
|
|
34
|
+
},
|
|
35
|
+
args: {
|
|
36
|
+
json: { type: 'boolean', description: 'Emit machine-readable JSON output' },
|
|
37
|
+
},
|
|
38
|
+
run: async ({ args }) => {
|
|
39
|
+
const action = (args._ as string[])?.[0] || '';
|
|
40
|
+
const asJson = !!args.json;
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const { project, dataDir } = await getCliProjectContext();
|
|
44
|
+
const activeDocs = getAllObservations()
|
|
45
|
+
.filter((obs) => obs.projectId === project.id && (obs.status ?? 'active') === 'active')
|
|
46
|
+
.map(toDocument);
|
|
47
|
+
|
|
48
|
+
switch (action) {
|
|
49
|
+
case 'status': {
|
|
50
|
+
const summary = getRetentionSummary(activeDocs);
|
|
51
|
+
const archiveCandidates = getArchiveCandidates(activeDocs);
|
|
52
|
+
const ranked = rankByRelevance(activeDocs).slice(0, 5);
|
|
53
|
+
emitResult(
|
|
54
|
+
{ project, summary, archiveCandidates, ranked },
|
|
55
|
+
[
|
|
56
|
+
`Retention status for ${project.name}`,
|
|
57
|
+
`- Active: ${summary.active}`,
|
|
58
|
+
`- Stale: ${summary.stale}`,
|
|
59
|
+
`- Archive candidates: ${summary.archiveCandidates}`,
|
|
60
|
+
`- Immune: ${summary.immune}`,
|
|
61
|
+
].join('\n'),
|
|
62
|
+
asJson,
|
|
63
|
+
);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
case 'archive': {
|
|
68
|
+
const result = await archiveExpired(dataDir);
|
|
69
|
+
emitResult(
|
|
70
|
+
{ project, result },
|
|
71
|
+
result.archived === 0
|
|
72
|
+
? 'No expired observations to archive.'
|
|
73
|
+
: `Archived ${result.archived} expired observation(s); ${result.remaining} active observation(s) remain.`,
|
|
74
|
+
asJson,
|
|
75
|
+
);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
case 'stale': {
|
|
80
|
+
const stale = activeDocs
|
|
81
|
+
.filter((doc) => getRetentionZone(doc) !== 'active')
|
|
82
|
+
.map((doc) => explainRetention(doc));
|
|
83
|
+
emitResult(
|
|
84
|
+
{ project, stale },
|
|
85
|
+
stale.length === 0
|
|
86
|
+
? 'No stale or archive-candidate observations.'
|
|
87
|
+
: stale
|
|
88
|
+
.map((entry) => `- #${entry.observationId}: ${entry.summary}`)
|
|
89
|
+
.join('\n'),
|
|
90
|
+
asJson,
|
|
91
|
+
);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
default:
|
|
96
|
+
console.log('Memorix Retention Commands');
|
|
97
|
+
console.log('');
|
|
98
|
+
console.log('Usage:');
|
|
99
|
+
console.log(' memorix retention status');
|
|
100
|
+
console.log(' memorix retention stale');
|
|
101
|
+
console.log(' memorix retention archive');
|
|
102
|
+
}
|
|
103
|
+
} catch (error) {
|
|
104
|
+
emitError(error instanceof Error ? error.message : String(error), asJson);
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
@@ -1,118 +1,118 @@
|
|
|
1
|
-
import type { ProjectInfo } from '../../types.js';
|
|
2
|
-
|
|
3
|
-
export interface ResolveServeProjectOptions {
|
|
4
|
-
cwdArg?: string;
|
|
5
|
-
envProjectRoot?: string;
|
|
6
|
-
initCwd?: string;
|
|
7
|
-
processCwd: string;
|
|
8
|
-
homeDir: string;
|
|
9
|
-
lastKnownProjectRoot?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface ResolveServeProjectDeps {
|
|
13
|
-
detectProject: (cwd: string) => ProjectInfo | null;
|
|
14
|
-
findGitInSubdirs: (dir: string) => string | null;
|
|
15
|
-
isSystemDirectory: (dir: string) => boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface ServeProjectResolution {
|
|
19
|
-
projectRoot: string;
|
|
20
|
-
detectedProject: ProjectInfo | null;
|
|
21
|
-
source: 'direct' | 'subdir' | 'last-known' | 'home' | 'home-subdir' | 'unresolved';
|
|
22
|
-
messages: string[];
|
|
23
|
-
error?: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function resolveServeProject(
|
|
27
|
-
options: ResolveServeProjectOptions,
|
|
28
|
-
deps: ResolveServeProjectDeps,
|
|
29
|
-
): ServeProjectResolution {
|
|
30
|
-
let projectRoot =
|
|
31
|
-
options.cwdArg ||
|
|
32
|
-
options.envProjectRoot ||
|
|
33
|
-
options.initCwd ||
|
|
34
|
-
options.processCwd;
|
|
35
|
-
|
|
36
|
-
const messages: string[] = [`[memorix] Starting with cwd: ${projectRoot}`];
|
|
37
|
-
|
|
38
|
-
let detected = deps.detectProject(projectRoot);
|
|
39
|
-
if (detected) {
|
|
40
|
-
return {
|
|
41
|
-
projectRoot,
|
|
42
|
-
detectedProject: detected,
|
|
43
|
-
source: 'direct',
|
|
44
|
-
messages,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const subGit = deps.findGitInSubdirs(projectRoot);
|
|
49
|
-
if (subGit) {
|
|
50
|
-
projectRoot = subGit;
|
|
51
|
-
detected = deps.detectProject(subGit);
|
|
52
|
-
if (detected) {
|
|
53
|
-
messages.push(`[memorix] Found .git in subdirectory: ${subGit}`);
|
|
54
|
-
return {
|
|
55
|
-
projectRoot,
|
|
56
|
-
detectedProject: detected,
|
|
57
|
-
source: 'subdir',
|
|
58
|
-
messages,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (deps.isSystemDirectory(projectRoot)) {
|
|
64
|
-
messages.push(`[memorix] System directory detected: ${projectRoot}`);
|
|
65
|
-
messages.push('[memorix] Your IDE launched memorix from a non-workspace directory.');
|
|
66
|
-
messages.push('[memorix] Fix: add --cwd to your MCP config, or use an IDE/client that exposes workspace roots.');
|
|
67
|
-
|
|
68
|
-
if (options.lastKnownProjectRoot) {
|
|
69
|
-
detected = deps.detectProject(options.lastKnownProjectRoot);
|
|
70
|
-
if (detected) {
|
|
71
|
-
messages.push(`[memorix] Restored last known project: ${options.lastKnownProjectRoot}`);
|
|
72
|
-
return {
|
|
73
|
-
projectRoot: options.lastKnownProjectRoot,
|
|
74
|
-
detectedProject: detected,
|
|
75
|
-
source: 'last-known',
|
|
76
|
-
messages,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
detected = deps.detectProject(options.homeDir);
|
|
82
|
-
if (detected) {
|
|
83
|
-
messages.push(`[memorix] Restored project from home directory: ${options.homeDir}`);
|
|
84
|
-
return {
|
|
85
|
-
projectRoot: options.homeDir,
|
|
86
|
-
detectedProject: detected,
|
|
87
|
-
source: 'home',
|
|
88
|
-
messages,
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const homeSubGit = deps.findGitInSubdirs(options.homeDir);
|
|
93
|
-
if (homeSubGit) {
|
|
94
|
-
detected = deps.detectProject(homeSubGit);
|
|
95
|
-
if (detected) {
|
|
96
|
-
messages.push(`[memorix] Found .git in home subdirectory: ${homeSubGit}`);
|
|
97
|
-
return {
|
|
98
|
-
projectRoot: homeSubGit,
|
|
99
|
-
detectedProject: detected,
|
|
100
|
-
source: 'home-subdir',
|
|
101
|
-
messages,
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
messages.push('[memorix] Unable to establish a reliable git-backed project context.');
|
|
108
|
-
messages.push('[memorix] Memorix now refuses to silently fall back to untracked/* in stdio mode.');
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
projectRoot,
|
|
112
|
-
detectedProject: null,
|
|
113
|
-
source: 'unresolved',
|
|
114
|
-
messages,
|
|
115
|
-
error:
|
|
116
|
-
'No git project could be resolved from the current workspace. Open the repo root, pass --cwd, or use an MCP client that sends workspace roots.',
|
|
117
|
-
};
|
|
118
|
-
}
|
|
1
|
+
import type { ProjectInfo } from '../../types.js';
|
|
2
|
+
|
|
3
|
+
export interface ResolveServeProjectOptions {
|
|
4
|
+
cwdArg?: string;
|
|
5
|
+
envProjectRoot?: string;
|
|
6
|
+
initCwd?: string;
|
|
7
|
+
processCwd: string;
|
|
8
|
+
homeDir: string;
|
|
9
|
+
lastKnownProjectRoot?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ResolveServeProjectDeps {
|
|
13
|
+
detectProject: (cwd: string) => ProjectInfo | null;
|
|
14
|
+
findGitInSubdirs: (dir: string) => string | null;
|
|
15
|
+
isSystemDirectory: (dir: string) => boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ServeProjectResolution {
|
|
19
|
+
projectRoot: string;
|
|
20
|
+
detectedProject: ProjectInfo | null;
|
|
21
|
+
source: 'direct' | 'subdir' | 'last-known' | 'home' | 'home-subdir' | 'unresolved';
|
|
22
|
+
messages: string[];
|
|
23
|
+
error?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function resolveServeProject(
|
|
27
|
+
options: ResolveServeProjectOptions,
|
|
28
|
+
deps: ResolveServeProjectDeps,
|
|
29
|
+
): ServeProjectResolution {
|
|
30
|
+
let projectRoot =
|
|
31
|
+
options.cwdArg ||
|
|
32
|
+
options.envProjectRoot ||
|
|
33
|
+
options.initCwd ||
|
|
34
|
+
options.processCwd;
|
|
35
|
+
|
|
36
|
+
const messages: string[] = [`[memorix] Starting with cwd: ${projectRoot}`];
|
|
37
|
+
|
|
38
|
+
let detected = deps.detectProject(projectRoot);
|
|
39
|
+
if (detected) {
|
|
40
|
+
return {
|
|
41
|
+
projectRoot,
|
|
42
|
+
detectedProject: detected,
|
|
43
|
+
source: 'direct',
|
|
44
|
+
messages,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const subGit = deps.findGitInSubdirs(projectRoot);
|
|
49
|
+
if (subGit) {
|
|
50
|
+
projectRoot = subGit;
|
|
51
|
+
detected = deps.detectProject(subGit);
|
|
52
|
+
if (detected) {
|
|
53
|
+
messages.push(`[memorix] Found .git in subdirectory: ${subGit}`);
|
|
54
|
+
return {
|
|
55
|
+
projectRoot,
|
|
56
|
+
detectedProject: detected,
|
|
57
|
+
source: 'subdir',
|
|
58
|
+
messages,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (deps.isSystemDirectory(projectRoot)) {
|
|
64
|
+
messages.push(`[memorix] System directory detected: ${projectRoot}`);
|
|
65
|
+
messages.push('[memorix] Your IDE launched memorix from a non-workspace directory.');
|
|
66
|
+
messages.push('[memorix] Fix: add --cwd to your MCP config, or use an IDE/client that exposes workspace roots.');
|
|
67
|
+
|
|
68
|
+
if (options.lastKnownProjectRoot) {
|
|
69
|
+
detected = deps.detectProject(options.lastKnownProjectRoot);
|
|
70
|
+
if (detected) {
|
|
71
|
+
messages.push(`[memorix] Restored last known project: ${options.lastKnownProjectRoot}`);
|
|
72
|
+
return {
|
|
73
|
+
projectRoot: options.lastKnownProjectRoot,
|
|
74
|
+
detectedProject: detected,
|
|
75
|
+
source: 'last-known',
|
|
76
|
+
messages,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
detected = deps.detectProject(options.homeDir);
|
|
82
|
+
if (detected) {
|
|
83
|
+
messages.push(`[memorix] Restored project from home directory: ${options.homeDir}`);
|
|
84
|
+
return {
|
|
85
|
+
projectRoot: options.homeDir,
|
|
86
|
+
detectedProject: detected,
|
|
87
|
+
source: 'home',
|
|
88
|
+
messages,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const homeSubGit = deps.findGitInSubdirs(options.homeDir);
|
|
93
|
+
if (homeSubGit) {
|
|
94
|
+
detected = deps.detectProject(homeSubGit);
|
|
95
|
+
if (detected) {
|
|
96
|
+
messages.push(`[memorix] Found .git in home subdirectory: ${homeSubGit}`);
|
|
97
|
+
return {
|
|
98
|
+
projectRoot: homeSubGit,
|
|
99
|
+
detectedProject: detected,
|
|
100
|
+
source: 'home-subdir',
|
|
101
|
+
messages,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
messages.push('[memorix] Unable to establish a reliable git-backed project context.');
|
|
108
|
+
messages.push('[memorix] Memorix now refuses to silently fall back to untracked/* in stdio mode.');
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
projectRoot,
|
|
112
|
+
detectedProject: null,
|
|
113
|
+
source: 'unresolved',
|
|
114
|
+
messages,
|
|
115
|
+
error:
|
|
116
|
+
'No git project could be resolved from the current workspace. Open the repo root, pass --cwd, or use an MCP client that sends workspace roots.',
|
|
117
|
+
};
|
|
118
|
+
}
|
|
@@ -357,9 +357,9 @@ function relativePosix(from: string, to: string): string {
|
|
|
357
357
|
return rel;
|
|
358
358
|
}
|
|
359
359
|
|
|
360
|
-
type McpConfigAgent = Exclude<AgentName, 'pi'>;
|
|
360
|
+
export type McpConfigAgent = Exclude<AgentName, 'pi'>;
|
|
361
361
|
|
|
362
|
-
function getMcpAdapter(agent: McpConfigAgent): MCPConfigAdapter {
|
|
362
|
+
export function getMcpAdapter(agent: McpConfigAgent): MCPConfigAdapter {
|
|
363
363
|
const adapters: Record<McpConfigAgent, MCPConfigAdapter> = {
|
|
364
364
|
claude: new ClaudeCodeMCPAdapter(),
|
|
365
365
|
codex: new CodexMCPAdapter(),
|
|
@@ -378,7 +378,7 @@ function getMcpAdapter(agent: McpConfigAgent): MCPConfigAdapter {
|
|
|
378
378
|
return adapters[agent];
|
|
379
379
|
}
|
|
380
380
|
|
|
381
|
-
function buildMemorixServer(mcp: Exclude<SetupMcpTransport, 'none'>): MCPServerEntry {
|
|
381
|
+
export function buildMemorixServer(mcp: Exclude<SetupMcpTransport, 'none'>): MCPServerEntry {
|
|
382
382
|
if (mcp === 'http') {
|
|
383
383
|
return {
|
|
384
384
|
name: 'memorix',
|