memorix 1.2.0 → 1.2.2
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 +30 -1
- package/README.md +18 -4
- package/README.zh-CN.md +18 -4
- package/TEAM.md +86 -86
- package/dist/cli/index.js +15919 -14055
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +1997 -1021
- package/dist/index.js.map +1 -1
- package/dist/maintenance-runner.d.ts +1 -1
- package/dist/maintenance-runner.js +8481 -8005
- package/dist/maintenance-runner.js.map +1 -1
- package/dist/memcode-runtime/CHANGELOG.md +30 -1
- package/dist/sdk.d.ts +7 -2
- package/dist/sdk.js +2022 -1024
- package/dist/sdk.js.map +1 -1
- package/dist/types.d.ts +49 -1
- package/dist/types.js.map +1 -1
- package/docs/1.2.2-MEMORY-CONTROL-PLANE.md +434 -0
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +4 -0
- package/docs/API_REFERENCE.md +27 -5
- package/docs/DESIGN_DECISIONS.md +357 -357
- package/docs/DEVELOPMENT.md +4 -0
- package/docs/README.md +1 -1
- package/docs/SETUP.md +7 -1
- package/docs/dev-log/progress.txt +91 -11
- package/docs/knowledge/workflows/memorix-release.md +57 -0
- package/package.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/src/audit/index.ts +156 -156
- package/src/cli/command-guide.ts +192 -0
- package/src/cli/commands/audit-list.ts +89 -89
- package/src/cli/commands/audit.ts +9 -4
- package/src/cli/commands/background.ts +659 -659
- package/src/cli/commands/cleanup.ts +5 -1
- package/src/cli/commands/codegraph.ts +17 -8
- package/src/cli/commands/context.ts +3 -2
- package/src/cli/commands/doctor.ts +4 -2
- package/src/cli/commands/explain.ts +9 -3
- package/src/cli/commands/formation.ts +48 -48
- package/src/cli/commands/git-hook-install.ts +111 -111
- package/src/cli/commands/handoff.ts +75 -61
- package/src/cli/commands/hooks-status.ts +63 -63
- package/src/cli/commands/identity.ts +116 -0
- package/src/cli/commands/ingest-commit.ts +153 -153
- package/src/cli/commands/ingest-image.ts +71 -69
- 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/knowledge.ts +40 -0
- package/src/cli/commands/lock.ts +93 -92
- package/src/cli/commands/memory.ts +58 -21
- package/src/cli/commands/message.ts +123 -118
- package/src/cli/commands/operator-shared.ts +98 -3
- package/src/cli/commands/poll.ts +74 -64
- 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 +135 -121
- package/src/cli/commands/retention.ts +9 -4
- package/src/cli/commands/serve-http.ts +22 -43
- package/src/cli/commands/serve-shared.ts +118 -118
- package/src/cli/commands/session.ts +29 -3
- package/src/cli/commands/setup.ts +9 -3
- package/src/cli/commands/skills.ts +124 -119
- package/src/cli/commands/status.ts +4 -3
- package/src/cli/commands/task.ts +193 -184
- package/src/cli/commands/team.ts +14 -10
- package/src/cli/commands/transfer.ts +108 -55
- package/src/cli/commands/uninstall-project-artifacts.ts +85 -85
- package/src/cli/identity.ts +89 -0
- package/src/cli/index.ts +96 -19
- package/src/cli/invocation.ts +115 -0
- 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/Sidebar.tsx +179 -179
- package/src/cli/tui/chat-service.ts +41 -18
- package/src/cli/tui/data.ts +23 -44
- package/src/cli/tui/index.ts +41 -41
- package/src/cli/tui/markdown-render.tsx +371 -371
- package/src/cli/tui/operator-context.ts +60 -0
- package/src/cli/tui/use-mouse.ts +157 -157
- package/src/cli/tui/useNavigation.ts +56 -56
- package/src/cli/tui/views/MemoryView.tsx +10 -8
- 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/auto-context.ts +34 -17
- package/src/codegraph/context-pack.ts +1 -0
- package/src/codegraph/current-facts.ts +19 -1
- package/src/codegraph/project-context.ts +2 -0
- package/src/codegraph/task-lens.ts +49 -5
- package/src/compact/engine.ts +26 -10
- package/src/compact/index-format.ts +25 -2
- package/src/compact/token-budget.ts +74 -74
- package/src/dashboard/project-classification.ts +64 -64
- package/src/dashboard/server.ts +58 -52
- 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/hooks/admission.ts +117 -0
- package/src/hooks/handler.ts +98 -91
- package/src/hooks/pattern-detector.ts +173 -173
- package/src/hooks/significance-filter.ts +250 -250
- package/src/knowledge/claims.ts +51 -1
- package/src/knowledge/context-assembly.ts +97 -0
- package/src/knowledge/types.ts +1 -0
- package/src/knowledge/workflows.ts +34 -3
- package/src/knowledge/workset.ts +179 -10
- 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/admission.ts +57 -0
- package/src/memory/attribution-guard.ts +249 -249
- package/src/memory/auto-relations.ts +21 -0
- package/src/memory/consolidation.ts +13 -2
- package/src/memory/disclosure-policy.ts +140 -135
- package/src/memory/entity-extractor.ts +197 -197
- package/src/memory/export-import.ts +11 -3
- 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-context.ts +8 -2
- package/src/memory/graph-scope.ts +46 -0
- package/src/memory/graph.ts +197 -197
- package/src/memory/observations.ts +162 -4
- package/src/memory/quality-audit.ts +2 -0
- package/src/memory/refs.ts +94 -94
- package/src/memory/retention.ts +22 -2
- package/src/memory/secret-filter.ts +79 -79
- package/src/memory/session.ts +5 -2
- package/src/memory/visibility.ts +80 -0
- 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 +378 -340
- 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 +33 -10
- 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/runtime/control-plane-maintenance.ts +1 -0
- package/src/runtime/isolated-maintenance.ts +1 -0
- package/src/runtime/lifecycle.ts +18 -0
- package/src/runtime/maintenance-jobs.ts +1 -0
- package/src/runtime/maintenance-runner.ts +2 -0
- package/src/runtime/project-maintenance.ts +89 -0
- package/src/sdk.ts +334 -304
- 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/server.ts +334 -93
- package/src/skills/mini-skills.ts +386 -386
- package/src/store/chat-store.ts +119 -119
- package/src/store/graph-store.ts +249 -249
- package/src/store/mini-skill-store.ts +349 -349
- package/src/store/orama-store.ts +61 -6
- 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/sqlite-db.ts +23 -1
- package/src/store/sqlite-store.ts +12 -2
- package/src/team/event-bus.ts +76 -76
- package/src/team/file-locks.ts +173 -173
- package/src/team/handoff.ts +168 -161
- package/src/team/messages.ts +203 -203
- package/src/team/poll.ts +132 -132
- package/src/team/tasks.ts +211 -211
- package/src/types.ts +51 -0
- package/src/wiki/generator.ts +2 -0
- 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
|
@@ -23,6 +23,8 @@ import { defineCommand } from 'citty';
|
|
|
23
23
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
24
24
|
import type { ObservationStore } from '../../store/obs-store.js';
|
|
25
25
|
import { resolveToolProfile } from '../../server/tool-profile.js';
|
|
26
|
+
import { scopeKnowledgeGraphToProject } from '../../memory/graph-scope.js';
|
|
27
|
+
import { canManageObservation, filterReadableObservations } from '../../memory/visibility.js';
|
|
26
28
|
|
|
27
29
|
export const DEFAULT_SESSION_TIMEOUT_MS = 30 * 60 * 1000;
|
|
28
30
|
|
|
@@ -557,7 +559,7 @@ export default defineCommand({
|
|
|
557
559
|
|
|
558
560
|
async function loadDashboardObservations(dataDir: string) {
|
|
559
561
|
const store = await getDashboardObservationStore(dataDir);
|
|
560
|
-
return store.loadAll();
|
|
562
|
+
return filterReadableObservations(await store.loadAll(), {});
|
|
561
563
|
}
|
|
562
564
|
|
|
563
565
|
async function loadDashboardProjectObservations(
|
|
@@ -566,7 +568,10 @@ export default defineCommand({
|
|
|
566
568
|
status?: string,
|
|
567
569
|
) {
|
|
568
570
|
const store = await getDashboardObservationStore(dataDir);
|
|
569
|
-
return
|
|
571
|
+
return filterReadableObservations(
|
|
572
|
+
await store.loadByProject(projectId, status ? { status } : undefined),
|
|
573
|
+
{ projectId },
|
|
574
|
+
);
|
|
570
575
|
}
|
|
571
576
|
|
|
572
577
|
// Resolve static directory (dist/dashboard/static)
|
|
@@ -764,6 +769,7 @@ export default defineCommand({
|
|
|
764
769
|
source?: string;
|
|
765
770
|
commitHash?: string;
|
|
766
771
|
filesModified?: string[];
|
|
772
|
+
relatedEntities?: string[];
|
|
767
773
|
status?: string;
|
|
768
774
|
importance?: number;
|
|
769
775
|
accessCount?: number;
|
|
@@ -860,12 +866,7 @@ export default defineCommand({
|
|
|
860
866
|
} catch { /* best effort */ }
|
|
861
867
|
|
|
862
868
|
// Project-scoped graph counts (must match /graph and /export)
|
|
863
|
-
const
|
|
864
|
-
observations.filter(o => o.entityName).map(o => o.entityName!)
|
|
865
|
-
);
|
|
866
|
-
const projectEntities = graph.entities.filter((e: any) => projectEntityNames.has(e.name));
|
|
867
|
-
const projectEntitySet = new Set(projectEntities.map((e: any) => e.name));
|
|
868
|
-
const projectRelations = graph.relations.filter((r: any) => projectEntitySet.has(r.from) && projectEntitySet.has(r.to));
|
|
869
|
+
const projectGraph = scopeKnowledgeGraphToProject(graph, observations);
|
|
869
870
|
|
|
870
871
|
let maintenance = { total: 0, pending: 0, running: 0, retrying: 0, completed: 0, failed: 0 };
|
|
871
872
|
let lifecycle: unknown;
|
|
@@ -877,8 +878,8 @@ export default defineCommand({
|
|
|
877
878
|
} catch { /* optional maintenance diagnostics */ }
|
|
878
879
|
|
|
879
880
|
sendJson({
|
|
880
|
-
entities:
|
|
881
|
-
relations:
|
|
881
|
+
entities: projectGraph.entities.length,
|
|
882
|
+
relations: projectGraph.relations.length,
|
|
882
883
|
observations: observations.length,
|
|
883
884
|
nextId,
|
|
884
885
|
typeCounts,
|
|
@@ -930,19 +931,9 @@ export default defineCommand({
|
|
|
930
931
|
await initGraphStore(graphDataDir);
|
|
931
932
|
const fullGraph = { entities: getGraphStore().loadEntities(), relations: getGraphStore().loadRelations() };
|
|
932
933
|
|
|
933
|
-
|
|
934
|
-
const
|
|
935
|
-
|
|
936
|
-
allObs
|
|
937
|
-
.filter(o => o.entityName)
|
|
938
|
-
.map(o => o.entityName!)
|
|
939
|
-
);
|
|
940
|
-
|
|
941
|
-
const entities = fullGraph.entities.filter(e => projectEntityNames.has(e.name));
|
|
942
|
-
const entityNameSet = new Set(entities.map(e => e.name));
|
|
943
|
-
const relations = fullGraph.relations.filter(r => entityNameSet.has(r.from) && entityNameSet.has(r.to));
|
|
944
|
-
|
|
945
|
-
sendJson({ entities, relations });
|
|
934
|
+
const allObs = await loadDashboardProjectObservations(graphDataDir, graphProjectId, 'active');
|
|
935
|
+
const scoped = scopeKnowledgeGraphToProject(fullGraph, allObs);
|
|
936
|
+
sendJson({ entities: scoped.entities, relations: scoped.relations });
|
|
946
937
|
return;
|
|
947
938
|
}
|
|
948
939
|
|
|
@@ -1012,24 +1003,15 @@ export default defineCommand({
|
|
|
1012
1003
|
const allObs = await loadDashboardProjectObservations(kgDataDir, kgProjectId, 'active');
|
|
1013
1004
|
const skills = await getMiniSkillStore().loadByProject(kgProjectId);
|
|
1014
1005
|
|
|
1015
|
-
// Project-scope graph store (same logic as /api/graph)
|
|
1016
1006
|
const fullGraph = { entities: getGraphStore().loadEntities(), relations: getGraphStore().loadRelations() };
|
|
1017
|
-
const
|
|
1018
|
-
const projectEntityNames = new Set(
|
|
1019
|
-
graphObs
|
|
1020
|
-
.filter(o => o.entityName)
|
|
1021
|
-
.map(o => o.entityName!)
|
|
1022
|
-
);
|
|
1023
|
-
const scopedEntities = fullGraph.entities.filter(e => projectEntityNames.has(e.name));
|
|
1024
|
-
const scopedEntityNameSet = new Set(scopedEntities.map(e => e.name));
|
|
1025
|
-
const scopedRelations = fullGraph.relations.filter(r => scopedEntityNameSet.has(r.from) && scopedEntityNameSet.has(r.to));
|
|
1007
|
+
const scoped = scopeKnowledgeGraphToProject(fullGraph, allObs);
|
|
1026
1008
|
|
|
1027
1009
|
const graph = generateKnowledgeGraph({
|
|
1028
1010
|
projectId: kgProjectId,
|
|
1029
1011
|
observations: allObs,
|
|
1030
1012
|
miniSkills: skills,
|
|
1031
|
-
graphEntities:
|
|
1032
|
-
graphRelations:
|
|
1013
|
+
graphEntities: scoped.entities,
|
|
1014
|
+
graphRelations: scoped.relations,
|
|
1033
1015
|
});
|
|
1034
1016
|
|
|
1035
1017
|
sendJson(graph);
|
|
@@ -1343,6 +1325,8 @@ export default defineCommand({
|
|
|
1343
1325
|
sendJson({ error: 'Observation not found' }, 404);
|
|
1344
1326
|
} else if ((matchObs as any).projectId !== delProjectId) {
|
|
1345
1327
|
sendJson({ error: `Observation #${obsId} belongs to project "${(matchObs as any).projectId}", not "${delProjectId}"` }, 403);
|
|
1328
|
+
} else if (!canManageObservation(matchObs, { projectId: delProjectId })) {
|
|
1329
|
+
sendJson({ error: `Observation #${obsId} is not manageable from the unbound dashboard.` }, 403);
|
|
1346
1330
|
} else {
|
|
1347
1331
|
await store.remove(obsId);
|
|
1348
1332
|
// Sync: clean up graph entity references
|
|
@@ -1369,19 +1353,14 @@ export default defineCommand({
|
|
|
1369
1353
|
const { initGraphStore, getGraphStore } = await import('../../store/graph-store.js');
|
|
1370
1354
|
await initGraphStore(expDataDir);
|
|
1371
1355
|
const fullGraph = { entities: getGraphStore().loadEntities(), relations: getGraphStore().loadRelations() };
|
|
1372
|
-
const observations = await loadDashboardProjectObservations(expDataDir, expProjectId, 'active')
|
|
1356
|
+
const observations = await loadDashboardProjectObservations(expDataDir, expProjectId, 'active');
|
|
1373
1357
|
const expStore = await getDashboardObservationStore(expDataDir);
|
|
1374
1358
|
const nextId = await expStore.loadIdCounter();
|
|
1375
|
-
const
|
|
1376
|
-
observations.filter(o => o.entityName).map(o => o.entityName!),
|
|
1377
|
-
);
|
|
1378
|
-
const exportEntities = fullGraph.entities.filter((e: any) => exportEntityNames.has(e.name));
|
|
1379
|
-
const exportEntitySet = new Set(exportEntities.map((e: any) => e.name));
|
|
1380
|
-
const exportRelations = fullGraph.relations.filter((r: any) => exportEntitySet.has(r.from) && exportEntitySet.has(r.to));
|
|
1359
|
+
const scoped = scopeKnowledgeGraphToProject(fullGraph, observations);
|
|
1381
1360
|
const exportData = {
|
|
1382
1361
|
project: { id: expProjectId, name: expProjectName },
|
|
1383
1362
|
exportedAt: new Date().toISOString(),
|
|
1384
|
-
graph: { entities:
|
|
1363
|
+
graph: { entities: scoped.entities, relations: scoped.relations },
|
|
1385
1364
|
observations,
|
|
1386
1365
|
nextId,
|
|
1387
1366
|
};
|
|
@@ -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
|
+
}
|
|
@@ -5,6 +5,8 @@ import { computeWatermark } from '../../team/poll.js';
|
|
|
5
5
|
import { withFreshIndex } from '../../memory/freshness.js';
|
|
6
6
|
import { getAllObservations } from '../../memory/observations.js';
|
|
7
7
|
import { getObservationStore } from '../../store/obs-store.js';
|
|
8
|
+
import { filterReadableObservations } from '../../memory/visibility.js';
|
|
9
|
+
import { saveCliIdentity } from '../identity.js';
|
|
8
10
|
import { emitError, emitResult, getCliProjectContext, parsePositiveInt } from './operator-shared.js';
|
|
9
11
|
|
|
10
12
|
export default defineCommand({
|
|
@@ -18,6 +20,7 @@ export default defineCommand({
|
|
|
18
20
|
instanceId: { type: 'string', description: 'Stable instance identity across restarts' },
|
|
19
21
|
projectRoot: { type: 'string', description: 'Absolute project root used to bind the session context' },
|
|
20
22
|
joinTeam: { type: 'boolean', description: 'Explicitly join orchestration coordination state for this session' },
|
|
23
|
+
use: { type: 'boolean', description: 'Make the joined coordination identity active for later CLI commands' },
|
|
21
24
|
role: { type: 'string', description: 'Explicit role override used only when --joinTeam is set' },
|
|
22
25
|
sessionId: { type: 'string', description: 'Custom session ID (optional)' },
|
|
23
26
|
summary: { type: 'string', description: 'Structured session summary for session end' },
|
|
@@ -35,6 +38,14 @@ export default defineCommand({
|
|
|
35
38
|
|
|
36
39
|
switch (action) {
|
|
37
40
|
case 'start': {
|
|
41
|
+
if (args.use && !args.joinTeam) {
|
|
42
|
+
emitError('use requires --joinTeam when starting a session.', asJson);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (args.use && !args.agent && !args.agentType) {
|
|
46
|
+
emitError('use requires --agent or --agentType so Memorix can activate a coordination identity.', asJson);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
38
49
|
const result = await startSession(dataDir, project.id, {
|
|
39
50
|
sessionId: args.sessionId as string | undefined,
|
|
40
51
|
agent: args.agent as string | undefined,
|
|
@@ -61,6 +72,16 @@ export default defineCommand({
|
|
|
61
72
|
teamJoinNotice = 'Coordination join skipped: provide --agent or --agentType to create a coordination identity.';
|
|
62
73
|
}
|
|
63
74
|
|
|
75
|
+
let identityActivated = false;
|
|
76
|
+
if (args.use && agentRecord) {
|
|
77
|
+
await saveCliIdentity(dataDir, {
|
|
78
|
+
agentId: agentRecord.agent_id,
|
|
79
|
+
projectId: project.id,
|
|
80
|
+
activatedAt: new Date().toISOString(),
|
|
81
|
+
});
|
|
82
|
+
identityActivated = true;
|
|
83
|
+
}
|
|
84
|
+
|
|
64
85
|
let watermark = computeWatermark(0, 0, 0);
|
|
65
86
|
let rescuedAgentIds: string[] = [];
|
|
66
87
|
let availableTasks = 0;
|
|
@@ -70,8 +91,11 @@ export default defineCommand({
|
|
|
70
91
|
const store = getObservationStore();
|
|
71
92
|
const currentGen = store.getGeneration();
|
|
72
93
|
const projectObs = await withFreshIndex(() =>
|
|
73
|
-
|
|
74
|
-
(
|
|
94
|
+
filterReadableObservations(
|
|
95
|
+
getAllObservations().filter(
|
|
96
|
+
(obs) => obs.projectId === project.id && (obs.writeGeneration ?? 0) > lastSeen,
|
|
97
|
+
),
|
|
98
|
+
{ projectId: project.id, agentId: agentRecord.agent_id, isTeamMember: agentRecord.status === 'active' },
|
|
75
99
|
),
|
|
76
100
|
);
|
|
77
101
|
watermark = computeWatermark(lastSeen, currentGen, projectObs.length);
|
|
@@ -97,6 +121,7 @@ export default defineCommand({
|
|
|
97
121
|
joined: !!agentRecord,
|
|
98
122
|
notice: teamJoinNotice,
|
|
99
123
|
},
|
|
124
|
+
identityActivated,
|
|
100
125
|
watermark,
|
|
101
126
|
rescue: {
|
|
102
127
|
staleAgents: rescuedAgentIds,
|
|
@@ -113,6 +138,7 @@ export default defineCommand({
|
|
|
113
138
|
agentRecord
|
|
114
139
|
? `Agent: ${agentRecord.name} [${agentRecord.agent_type}] as ${agentRecord.role} (${agentRecord.agent_id})`
|
|
115
140
|
: '',
|
|
141
|
+
identityActivated ? 'CLI identity activated for follow-up memory and coordination commands.' : '',
|
|
116
142
|
!agentRecord ? 'Coordination identity: not joined (memory/session context only)' : '',
|
|
117
143
|
teamJoinNotice ?? '',
|
|
118
144
|
agentRecord && watermark.newObservationCount > 0
|
|
@@ -173,7 +199,7 @@ export default defineCommand({
|
|
|
173
199
|
console.log('Memorix Session Commands');
|
|
174
200
|
console.log('');
|
|
175
201
|
console.log('Usage:');
|
|
176
|
-
console.log(' memorix session start [--agent codex --agentType codex --instanceId abc] [--projectRoot <path>] [--joinTeam]');
|
|
202
|
+
console.log(' memorix session start [--agent codex --agentType codex --instanceId abc] [--projectRoot <path>] [--joinTeam --use]');
|
|
177
203
|
console.log(' memorix session end --sessionId <id> [--summary "..."]');
|
|
178
204
|
console.log(' memorix session context [--limit 3]');
|
|
179
205
|
console.log('');
|
|
@@ -1062,7 +1062,7 @@ function tryInstallOmpPackage(packagePath: string): { ok: boolean; message: stri
|
|
|
1062
1062
|
};
|
|
1063
1063
|
}
|
|
1064
1064
|
|
|
1065
|
-
async function installAgentSetup(agent: AgentName, plan: SetupPlan, global: boolean): Promise<void> {
|
|
1065
|
+
export async function installAgentSetup(agent: AgentName, plan: SetupPlan, global: boolean): Promise<void> {
|
|
1066
1066
|
const { installAgentGuidance, installHooks } = await import('../../hooks/installers/index.js');
|
|
1067
1067
|
const targetRoot = global ? homedir() : process.cwd();
|
|
1068
1068
|
const hasPluginPackage = plan.actions.includes('plugin-package') && PLUGIN_PACKAGE_AGENTS.has(agent);
|
|
@@ -1200,13 +1200,19 @@ async function installAgentSetup(agent: AgentName, plan: SetupPlan, global: bool
|
|
|
1200
1200
|
} else if (hasOmpPackage) {
|
|
1201
1201
|
p.log.info(`${agent}: extension command, hook events, and skills are bundled in the Oh-my-Pi package`);
|
|
1202
1202
|
} else if (hasExtensionPackage) {
|
|
1203
|
-
if (plan.actions.includes('hooks')
|
|
1203
|
+
if (plan.actions.includes('hooks')) {
|
|
1204
1204
|
const result = await installHooks(agent, targetRoot, global);
|
|
1205
1205
|
p.log.success(`${agent}: integration files -> ${result.configPath}`);
|
|
1206
|
+
} else if (plan.actions.includes('project-guidance')) {
|
|
1207
|
+
const rulesPath = await installAgentGuidance(agent, targetRoot, global);
|
|
1208
|
+
p.log.success(`${agent}: guidance -> ${rulesPath}`);
|
|
1206
1209
|
}
|
|
1207
|
-
} else if (
|
|
1210
|
+
} else if (plan.actions.includes('hooks')) {
|
|
1208
1211
|
const result = await installHooks(agent, targetRoot, global);
|
|
1209
1212
|
p.log.success(`${agent}: integration files -> ${result.configPath}`);
|
|
1213
|
+
} else if (plan.actions.includes('project-guidance')) {
|
|
1214
|
+
const rulesPath = await installAgentGuidance(agent, targetRoot, global);
|
|
1215
|
+
p.log.success(`${agent}: guidance -> ${rulesPath}`);
|
|
1210
1216
|
}
|
|
1211
1217
|
|
|
1212
1218
|
if (agent === 'pi') {
|