memorix 1.2.1 → 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 +16 -0
- package/README.md +14 -2
- package/README.zh-CN.md +14 -2
- package/TEAM.md +86 -86
- package/dist/cli/index.js +15407 -13779
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +1321 -529
- package/dist/index.js.map +1 -1
- package/dist/maintenance-runner.d.ts +1 -1
- package/dist/maintenance-runner.js +8458 -8087
- package/dist/maintenance-runner.js.map +1 -1
- package/dist/memcode-runtime/CHANGELOG.md +16 -0
- package/dist/sdk.d.ts +7 -2
- package/dist/sdk.js +1349 -535
- 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 +24 -4
- package/docs/DESIGN_DECISIONS.md +357 -357
- package/docs/README.md +1 -1
- package/docs/dev-log/progress.txt +91 -11
- 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 +15 -5
- 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/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 +8 -2
- package/src/cli/commands/serve-shared.ts +118 -118
- package/src/cli/commands/session.ts +29 -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 +31 -2
- package/src/codegraph/context-pack.ts +1 -0
- package/src/codegraph/project-context.ts +2 -0
- 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 +46 -9
- 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/context-assembly.ts +97 -0
- 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/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.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/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 +260 -81
- 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
|
@@ -24,6 +24,7 @@ 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
26
|
import { scopeKnowledgeGraphToProject } from '../../memory/graph-scope.js';
|
|
27
|
+
import { canManageObservation, filterReadableObservations } from '../../memory/visibility.js';
|
|
27
28
|
|
|
28
29
|
export const DEFAULT_SESSION_TIMEOUT_MS = 30 * 60 * 1000;
|
|
29
30
|
|
|
@@ -558,7 +559,7 @@ export default defineCommand({
|
|
|
558
559
|
|
|
559
560
|
async function loadDashboardObservations(dataDir: string) {
|
|
560
561
|
const store = await getDashboardObservationStore(dataDir);
|
|
561
|
-
return store.loadAll();
|
|
562
|
+
return filterReadableObservations(await store.loadAll(), {});
|
|
562
563
|
}
|
|
563
564
|
|
|
564
565
|
async function loadDashboardProjectObservations(
|
|
@@ -567,7 +568,10 @@ export default defineCommand({
|
|
|
567
568
|
status?: string,
|
|
568
569
|
) {
|
|
569
570
|
const store = await getDashboardObservationStore(dataDir);
|
|
570
|
-
return
|
|
571
|
+
return filterReadableObservations(
|
|
572
|
+
await store.loadByProject(projectId, status ? { status } : undefined),
|
|
573
|
+
{ projectId },
|
|
574
|
+
);
|
|
571
575
|
}
|
|
572
576
|
|
|
573
577
|
// Resolve static directory (dist/dashboard/static)
|
|
@@ -1321,6 +1325,8 @@ export default defineCommand({
|
|
|
1321
1325
|
sendJson({ error: 'Observation not found' }, 404);
|
|
1322
1326
|
} else if ((matchObs as any).projectId !== delProjectId) {
|
|
1323
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);
|
|
1324
1330
|
} else {
|
|
1325
1331
|
await store.remove(obsId);
|
|
1326
1332
|
// Sync: clean up graph entity references
|
|
@@ -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('');
|
|
@@ -1,123 +1,128 @@
|
|
|
1
|
-
import { defineCommand } from 'citty';
|
|
1
|
+
import { defineCommand } from 'citty';
|
|
2
2
|
import type { AgentTarget } from '../../types.js';
|
|
3
3
|
import { getObservationStore } from '../../store/obs-store.js';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const {
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
skills
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
4
|
+
import { filterReadableObservations, resolveObservationVisibility } from '../../memory/visibility.js';
|
|
5
|
+
import { emitError, emitResult, getCliProjectContext } from './operator-shared.js';
|
|
6
|
+
|
|
7
|
+
export default defineCommand({
|
|
8
|
+
meta: {
|
|
9
|
+
name: 'skills',
|
|
10
|
+
description: 'Discover, generate, and inspect project skills from the CLI',
|
|
11
|
+
},
|
|
12
|
+
args: {
|
|
13
|
+
name: { type: 'string', description: 'Skill name for "show"' },
|
|
14
|
+
target: { type: 'string', description: 'Target agent for generated skills' },
|
|
15
|
+
write: { type: 'boolean', description: 'Write generated skills to disk' },
|
|
16
|
+
json: { type: 'boolean', description: 'Emit machine-readable JSON output' },
|
|
17
|
+
},
|
|
18
|
+
run: async ({ args }) => {
|
|
19
|
+
const action = (args._ as string[])?.[0] || '';
|
|
20
|
+
const asJson = !!args.json;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const { project, reader } = await getCliProjectContext();
|
|
24
|
+
const { SkillsEngine } = await import('../../skills/engine.js');
|
|
25
|
+
const engine = new SkillsEngine(project.rootPath);
|
|
26
|
+
|
|
27
|
+
switch (action) {
|
|
28
|
+
case 'list': {
|
|
29
|
+
const skills = engine.listSkills();
|
|
30
|
+
emitResult(
|
|
31
|
+
{ project, skills },
|
|
32
|
+
skills.length === 0
|
|
33
|
+
? 'No skills found in project or global agent directories.'
|
|
34
|
+
: skills.map((skill) => `- ${skill.name} (${skill.sourceAgent})`).join('\n'),
|
|
35
|
+
asJson,
|
|
36
|
+
);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
case 'generate': {
|
|
41
|
+
const observations = filterReadableObservations(
|
|
42
|
+
await getObservationStore().loadAll(),
|
|
43
|
+
reader,
|
|
44
|
+
).filter((observation) => resolveObservationVisibility(observation) === 'project')
|
|
42
45
|
.map((obs) => ({
|
|
43
|
-
id: obs.id,
|
|
44
|
-
entityName: obs.entityName,
|
|
45
|
-
type: obs.type,
|
|
46
|
-
title: obs.title,
|
|
47
|
-
narrative: obs.narrative,
|
|
48
|
-
facts: obs.facts,
|
|
49
|
-
concepts: obs.concepts,
|
|
50
|
-
filesModified: obs.filesModified,
|
|
51
|
-
createdAt: obs.createdAt,
|
|
52
|
-
status: obs.status,
|
|
53
|
-
source: obs.source,
|
|
54
|
-
}));
|
|
55
|
-
const skills = engine.generateFromObservations(observations);
|
|
56
|
-
const written: string[] = [];
|
|
57
|
-
if (args.write && args.target) {
|
|
58
|
-
for (const skill of skills) {
|
|
59
|
-
const writtenPath = engine.writeSkill(skill, args.target as AgentTarget);
|
|
60
|
-
if (writtenPath) written.push(writtenPath);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
emitResult(
|
|
64
|
-
{ project, skills, written },
|
|
65
|
-
skills.length === 0
|
|
66
|
-
? 'No skill-worthy patterns found yet.'
|
|
67
|
-
: skills.map((skill) => `- ${skill.name}: ${skill.description}`).join('\n'),
|
|
68
|
-
asJson,
|
|
69
|
-
);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
case 'show': {
|
|
74
|
-
const name = (args.name as string | undefined)?.trim();
|
|
75
|
-
if (!name) {
|
|
76
|
-
emitError('name is required for "memorix skills show"', asJson);
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
const direct = engine.injectSkill(name);
|
|
80
|
-
if (direct) {
|
|
81
|
-
emitResult({ project, skill: direct }, direct.content, asJson);
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const observations = (
|
|
86
|
-
|
|
46
|
+
id: obs.id,
|
|
47
|
+
entityName: obs.entityName,
|
|
48
|
+
type: obs.type,
|
|
49
|
+
title: obs.title,
|
|
50
|
+
narrative: obs.narrative,
|
|
51
|
+
facts: obs.facts,
|
|
52
|
+
concepts: obs.concepts,
|
|
53
|
+
filesModified: obs.filesModified,
|
|
54
|
+
createdAt: obs.createdAt,
|
|
55
|
+
status: obs.status,
|
|
56
|
+
source: obs.source,
|
|
57
|
+
}));
|
|
58
|
+
const skills = engine.generateFromObservations(observations);
|
|
59
|
+
const written: string[] = [];
|
|
60
|
+
if (args.write && args.target) {
|
|
61
|
+
for (const skill of skills) {
|
|
62
|
+
const writtenPath = engine.writeSkill(skill, args.target as AgentTarget);
|
|
63
|
+
if (writtenPath) written.push(writtenPath);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
emitResult(
|
|
67
|
+
{ project, skills, written },
|
|
68
|
+
skills.length === 0
|
|
69
|
+
? 'No skill-worthy patterns found yet.'
|
|
70
|
+
: skills.map((skill) => `- ${skill.name}: ${skill.description}`).join('\n'),
|
|
71
|
+
asJson,
|
|
72
|
+
);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
case 'show': {
|
|
77
|
+
const name = (args.name as string | undefined)?.trim();
|
|
78
|
+
if (!name) {
|
|
79
|
+
emitError('name is required for "memorix skills show"', asJson);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const direct = engine.injectSkill(name);
|
|
83
|
+
if (direct) {
|
|
84
|
+
emitResult({ project, skill: direct }, direct.content, asJson);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const observations = filterReadableObservations(
|
|
89
|
+
await getObservationStore().loadAll(),
|
|
90
|
+
reader,
|
|
91
|
+
).filter((observation) => resolveObservationVisibility(observation) === 'project')
|
|
87
92
|
.map((obs) => ({
|
|
88
|
-
id: obs.id,
|
|
89
|
-
entityName: obs.entityName,
|
|
90
|
-
type: obs.type,
|
|
91
|
-
title: obs.title,
|
|
92
|
-
narrative: obs.narrative,
|
|
93
|
-
facts: obs.facts,
|
|
94
|
-
concepts: obs.concepts,
|
|
95
|
-
filesModified: obs.filesModified,
|
|
96
|
-
createdAt: obs.createdAt,
|
|
97
|
-
status: obs.status,
|
|
98
|
-
source: obs.source,
|
|
99
|
-
}));
|
|
100
|
-
const generated = engine.generateFromObservations(observations);
|
|
101
|
-
const skill = generated.find((entry) => entry.name.toLowerCase() === name.toLowerCase());
|
|
102
|
-
if (!skill) {
|
|
103
|
-
emitError(`Skill "${name}" not found`, asJson);
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
emitResult({ project, skill }, skill.content, asJson);
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
default:
|
|
111
|
-
console.log('Memorix Skills Commands');
|
|
112
|
-
console.log('');
|
|
113
|
-
console.log('Usage:');
|
|
114
|
-
console.log(' memorix skills list');
|
|
115
|
-
console.log(' memorix skills generate [--write --target codex]');
|
|
116
|
-
console.log(' memorix skills show --name <skill>');
|
|
117
|
-
}
|
|
118
|
-
} catch (error) {
|
|
119
|
-
emitError(error instanceof Error ? error.message : String(error), asJson);
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
});
|
|
123
|
-
|
|
93
|
+
id: obs.id,
|
|
94
|
+
entityName: obs.entityName,
|
|
95
|
+
type: obs.type,
|
|
96
|
+
title: obs.title,
|
|
97
|
+
narrative: obs.narrative,
|
|
98
|
+
facts: obs.facts,
|
|
99
|
+
concepts: obs.concepts,
|
|
100
|
+
filesModified: obs.filesModified,
|
|
101
|
+
createdAt: obs.createdAt,
|
|
102
|
+
status: obs.status,
|
|
103
|
+
source: obs.source,
|
|
104
|
+
}));
|
|
105
|
+
const generated = engine.generateFromObservations(observations);
|
|
106
|
+
const skill = generated.find((entry) => entry.name.toLowerCase() === name.toLowerCase());
|
|
107
|
+
if (!skill) {
|
|
108
|
+
emitError(`Skill "${name}" not found`, asJson);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
emitResult({ project, skill }, skill.content, asJson);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
default:
|
|
116
|
+
console.log('Memorix Skills Commands');
|
|
117
|
+
console.log('');
|
|
118
|
+
console.log('Usage:');
|
|
119
|
+
console.log(' memorix skills list');
|
|
120
|
+
console.log(' memorix skills generate [--write --target codex]');
|
|
121
|
+
console.log(' memorix skills show --name <skill>');
|
|
122
|
+
}
|
|
123
|
+
} catch (error) {
|
|
124
|
+
emitError(error instanceof Error ? error.message : String(error), asJson);
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
@@ -39,8 +39,8 @@ export default defineCommand({
|
|
|
39
39
|
const { initObservationStore, getObservationStore } = await import('../../store/obs-store.js');
|
|
40
40
|
await initObservationStore(dataDir);
|
|
41
41
|
const store = getObservationStore();
|
|
42
|
-
const
|
|
43
|
-
const projectObs =
|
|
42
|
+
const { filterReadableObservations } = await import('../../memory/visibility.js');
|
|
43
|
+
const projectObs = filterReadableObservations(await store.loadAll(), { projectId: project.id });
|
|
44
44
|
obsCount = projectObs.length;
|
|
45
45
|
activeCount = projectObs.filter(o => (o.status ?? 'active') === 'active').length;
|
|
46
46
|
} catch { /* ignore */ }
|
|
@@ -165,7 +165,8 @@ export default defineCommand({
|
|
|
165
165
|
const { initObservationStore, getObservationStore } = await import('../../store/obs-store.js');
|
|
166
166
|
await initObservationStore(dataDir);
|
|
167
167
|
const store = getObservationStore();
|
|
168
|
-
const
|
|
168
|
+
const { filterReadableObservations } = await import('../../memory/visibility.js');
|
|
169
|
+
const allObs = filterReadableObservations(await store.loadAll(), { projectId: project.id });
|
|
169
170
|
const gitCount = allObs.filter(o => o.source === 'git').length;
|
|
170
171
|
const reasoningCount = allObs.filter(o => o.type === 'reasoning').length;
|
|
171
172
|
if (gitCount > 0 || reasoningCount > 0) {
|