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
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLI Command: memorix hooks status
|
|
3
|
-
*
|
|
4
|
-
* Show hook installation status for all agents.
|
|
1
|
+
/**
|
|
2
|
+
* CLI Command: memorix hooks status
|
|
3
|
+
*
|
|
4
|
+
* Show hook installation status for all agents.
|
|
5
5
|
* Status marks:
|
|
6
6
|
* [OK] - installed and verified (config-based agent, file read directly)
|
|
7
7
|
* [??] - installed but unverified (plugin-based agent, runtime load not confirmed)
|
|
8
8
|
* [!!] - installed but outdated
|
|
9
9
|
* [ ] - not installed
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { defineCommand } from 'citty';
|
|
13
|
-
|
|
14
|
-
export default defineCommand({
|
|
15
|
-
meta: {
|
|
16
|
-
name: 'status',
|
|
17
|
-
description: 'Show hook installation status for all agents',
|
|
18
|
-
},
|
|
19
|
-
run: async () => {
|
|
20
|
-
const { getHookStatus } = await import('../../hooks/installers/index.js');
|
|
21
|
-
const { AGENT_SUPPORT_TIER } = await import('../../hooks/types.js');
|
|
22
|
-
const os = await import('node:os');
|
|
23
|
-
let cwd: string;
|
|
24
|
-
try { cwd = process.cwd(); } catch { cwd = os.homedir(); }
|
|
25
|
-
|
|
26
|
-
const statuses = await getHookStatus(cwd);
|
|
27
|
-
|
|
28
|
-
console.log('\nMemorix Hooks Status');
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { defineCommand } from 'citty';
|
|
13
|
+
|
|
14
|
+
export default defineCommand({
|
|
15
|
+
meta: {
|
|
16
|
+
name: 'status',
|
|
17
|
+
description: 'Show hook installation status for all agents',
|
|
18
|
+
},
|
|
19
|
+
run: async () => {
|
|
20
|
+
const { getHookStatus } = await import('../../hooks/installers/index.js');
|
|
21
|
+
const { AGENT_SUPPORT_TIER } = await import('../../hooks/types.js');
|
|
22
|
+
const os = await import('node:os');
|
|
23
|
+
let cwd: string;
|
|
24
|
+
try { cwd = process.cwd(); } catch { cwd = os.homedir(); }
|
|
25
|
+
|
|
26
|
+
const statuses = await getHookStatus(cwd);
|
|
27
|
+
|
|
28
|
+
console.log('\nMemorix Hooks Status');
|
|
29
29
|
console.log('-'.repeat(50));
|
|
30
|
-
|
|
31
|
-
let hasOutdated = false;
|
|
32
|
-
let hasUnverified = false;
|
|
33
|
-
let hasRuntimeIssue = false;
|
|
34
|
-
for (const { agent, installed, outdated, verified, runtimeReady, configPath } of statuses) {
|
|
35
|
-
const icon = installed
|
|
36
|
-
? (!runtimeReady ? '[!!]' : (outdated ? '[!!]' : (verified ? '[OK]' : '[??]')))
|
|
37
|
-
: '[ ]';
|
|
38
|
-
const label = agent.charAt(0).toUpperCase() + agent.slice(1);
|
|
39
|
-
const tier = AGENT_SUPPORT_TIER[agent];
|
|
30
|
+
|
|
31
|
+
let hasOutdated = false;
|
|
32
|
+
let hasUnverified = false;
|
|
33
|
+
let hasRuntimeIssue = false;
|
|
34
|
+
for (const { agent, installed, outdated, verified, runtimeReady, configPath } of statuses) {
|
|
35
|
+
const icon = installed
|
|
36
|
+
? (!runtimeReady ? '[!!]' : (outdated ? '[!!]' : (verified ? '[OK]' : '[??]')))
|
|
37
|
+
: '[ ]';
|
|
38
|
+
const label = agent.charAt(0).toUpperCase() + agent.slice(1);
|
|
39
|
+
const tier = AGENT_SUPPORT_TIER[agent];
|
|
40
40
|
const tierLabel = tier === 'core' ? '[core]' : tier === 'extended' ? '[extended]' : '[community]';
|
|
41
|
-
const suffix = !runtimeReady && installed
|
|
42
|
-
? ' (installed but runtime NOT ready — missing pwsh on Windows)'
|
|
43
|
-
: outdated
|
|
44
|
-
? ' (outdated - re-run `memorix hooks install`)'
|
|
45
|
-
: (!verified && installed ? ' (plugin file installed, runtime load unverified)' : '');
|
|
46
|
-
console.log(`${icon} ${tierLabel} ${label.padEnd(12)} ${installed ? configPath + suffix : '(not installed)'}`);
|
|
47
|
-
if (outdated) hasOutdated = true;
|
|
48
|
-
if (!verified && installed) hasUnverified = true;
|
|
49
|
-
if (!runtimeReady && installed) hasRuntimeIssue = true;
|
|
50
|
-
}
|
|
51
|
-
|
|
41
|
+
const suffix = !runtimeReady && installed
|
|
42
|
+
? ' (installed but runtime NOT ready — missing pwsh on Windows)'
|
|
43
|
+
: outdated
|
|
44
|
+
? ' (outdated - re-run `memorix hooks install`)'
|
|
45
|
+
: (!verified && installed ? ' (plugin file installed, runtime load unverified)' : '');
|
|
46
|
+
console.log(`${icon} ${tierLabel} ${label.padEnd(12)} ${installed ? configPath + suffix : '(not installed)'}`);
|
|
47
|
+
if (outdated) hasOutdated = true;
|
|
48
|
+
if (!verified && installed) hasUnverified = true;
|
|
49
|
+
if (!runtimeReady && installed) hasRuntimeIssue = true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
52
|
console.log('\nSupport tiers: [core] core | [extended] extended | [community] community');
|
|
53
|
-
|
|
54
|
-
if (hasOutdated) {
|
|
55
|
-
console.log('\n[warn] Outdated hooks detected. Run `memorix hooks install` to update.');
|
|
56
|
-
}
|
|
57
|
-
if (hasUnverified) {
|
|
58
|
-
console.log('\n[info] [??] = plugin file installed but runtime load unverified.');
|
|
59
|
-
console.log(' For OpenCode: verify by running `opencode --log-level DEBUG` and checking');
|
|
60
|
-
console.log(' for [memorix-plugin] messages in the log output.');
|
|
61
|
-
}
|
|
62
|
-
if (hasRuntimeIssue) {
|
|
63
|
-
console.log('\n[warn] [!!] = installed but runtime will fail.');
|
|
64
|
-
console.log(' Copilot on Windows requires PowerShell v6+ (pwsh.exe) for hook execution.');
|
|
65
|
-
console.log(' Install pwsh: https://learn.microsoft.com/powershell/scripting/install/installing-powershell');
|
|
66
|
-
console.log(' Without pwsh, Copilot hooks will fail at runtime with "spawn pwsh.exe ENOENT".');
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
console.log('\nRun `memorix hooks install` to set up hooks for detected agents.');
|
|
70
|
-
},
|
|
71
|
-
});
|
|
53
|
+
|
|
54
|
+
if (hasOutdated) {
|
|
55
|
+
console.log('\n[warn] Outdated hooks detected. Run `memorix hooks install` to update.');
|
|
56
|
+
}
|
|
57
|
+
if (hasUnverified) {
|
|
58
|
+
console.log('\n[info] [??] = plugin file installed but runtime load unverified.');
|
|
59
|
+
console.log(' For OpenCode: verify by running `opencode --log-level DEBUG` and checking');
|
|
60
|
+
console.log(' for [memorix-plugin] messages in the log output.');
|
|
61
|
+
}
|
|
62
|
+
if (hasRuntimeIssue) {
|
|
63
|
+
console.log('\n[warn] [!!] = installed but runtime will fail.');
|
|
64
|
+
console.log(' Copilot on Windows requires PowerShell v6+ (pwsh.exe) for hook execution.');
|
|
65
|
+
console.log(' Install pwsh: https://learn.microsoft.com/powershell/scripting/install/installing-powershell');
|
|
66
|
+
console.log(' Without pwsh, Copilot hooks will fail at runtime with "spawn pwsh.exe ENOENT".');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
console.log('\nRun `memorix hooks install` to set up hooks for detected agents.');
|
|
70
|
+
},
|
|
71
|
+
});
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { defineCommand } from 'citty';
|
|
2
|
+
import { AGENT_TYPE_ROLE_MAP } from '../../team/team-store.js';
|
|
3
|
+
import { clearCliIdentity, loadCliIdentity, saveCliIdentity } from '../identity.js';
|
|
4
|
+
import { emitError, emitResult, getCliProjectContext, parseCsvList } from './operator-shared.js';
|
|
5
|
+
|
|
6
|
+
function requiredText(value: unknown, label: string): string {
|
|
7
|
+
const text = typeof value === 'string' ? value.trim() : '';
|
|
8
|
+
if (!text) throw new Error(`${label} is required`);
|
|
9
|
+
return text;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default defineCommand({
|
|
13
|
+
meta: {
|
|
14
|
+
name: 'identity',
|
|
15
|
+
description: 'Select the explicit CLI actor used for private or team-scoped operations',
|
|
16
|
+
},
|
|
17
|
+
args: {
|
|
18
|
+
agentId: { type: 'string', description: 'Existing active coordination agent ID' },
|
|
19
|
+
agentType: { type: 'string', description: 'Agent type when joining (for example codex)' },
|
|
20
|
+
instanceId: { type: 'string', description: 'Stable instance identity when joining' },
|
|
21
|
+
name: { type: 'string', description: 'Optional display name when joining' },
|
|
22
|
+
role: { type: 'string', description: 'Optional coordination role when joining' },
|
|
23
|
+
capabilities: { type: 'string', description: 'Comma-separated capability list when joining' },
|
|
24
|
+
json: { type: 'boolean', description: 'Emit machine-readable JSON output' },
|
|
25
|
+
},
|
|
26
|
+
run: async ({ args }) => {
|
|
27
|
+
const action = ((args._ as string[])?.[0] || 'status').toLowerCase();
|
|
28
|
+
const asJson = !!args.json;
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const { project, dataDir, teamStore, identity, reader, identityWarning } = await getCliProjectContext();
|
|
32
|
+
|
|
33
|
+
switch (action) {
|
|
34
|
+
case 'status': {
|
|
35
|
+
const saved = await loadCliIdentity(dataDir, project.id);
|
|
36
|
+
const agent = saved ? teamStore.getAgent(saved.agentId) : undefined;
|
|
37
|
+
emitResult(
|
|
38
|
+
{
|
|
39
|
+
project,
|
|
40
|
+
identity,
|
|
41
|
+
savedIdentity: saved,
|
|
42
|
+
agent: agent ?? null,
|
|
43
|
+
reader,
|
|
44
|
+
...(identityWarning ? { warning: identityWarning } : {}),
|
|
45
|
+
},
|
|
46
|
+
identity
|
|
47
|
+
? `CLI identity: ${agent?.name ?? identity.agentId} (${identity.agentId})`
|
|
48
|
+
: identityWarning ?? 'CLI identity: project-scoped only. Use "memorix identity join" or "memorix identity use --agent-id <id>" for private/team operations.',
|
|
49
|
+
asJson,
|
|
50
|
+
);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
case 'join': {
|
|
55
|
+
const agentType = requiredText(args.agentType, 'agentType');
|
|
56
|
+
const agent = teamStore.registerAgent({
|
|
57
|
+
projectId: project.id,
|
|
58
|
+
agentType,
|
|
59
|
+
instanceId: args.instanceId as string | undefined,
|
|
60
|
+
name: args.name as string | undefined,
|
|
61
|
+
role: (args.role as string | undefined) || AGENT_TYPE_ROLE_MAP[agentType] || 'engineer',
|
|
62
|
+
capabilities: parseCsvList(args.capabilities as string | undefined),
|
|
63
|
+
});
|
|
64
|
+
const nextIdentity = {
|
|
65
|
+
agentId: agent.agent_id,
|
|
66
|
+
projectId: project.id,
|
|
67
|
+
activatedAt: new Date().toISOString(),
|
|
68
|
+
};
|
|
69
|
+
await saveCliIdentity(dataDir, nextIdentity);
|
|
70
|
+
emitResult(
|
|
71
|
+
{ project, identity: nextIdentity, agent },
|
|
72
|
+
`CLI identity activated: ${agent.name} (${agent.agent_id})`,
|
|
73
|
+
asJson,
|
|
74
|
+
);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
case 'use': {
|
|
79
|
+
const agentId = requiredText(args.agentId, 'agentId');
|
|
80
|
+
const agent = teamStore.getAgent(agentId);
|
|
81
|
+
if (!agent || agent.project_id !== project.id || agent.status !== 'active') {
|
|
82
|
+
emitError('agentId must identify an active coordination member of this project.', asJson);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const nextIdentity = {
|
|
86
|
+
agentId: agent.agent_id,
|
|
87
|
+
projectId: project.id,
|
|
88
|
+
activatedAt: new Date().toISOString(),
|
|
89
|
+
};
|
|
90
|
+
await saveCliIdentity(dataDir, nextIdentity);
|
|
91
|
+
emitResult(
|
|
92
|
+
{ project, identity: nextIdentity, agent },
|
|
93
|
+
`CLI identity activated: ${agent.name} (${agent.agent_id})`,
|
|
94
|
+
asJson,
|
|
95
|
+
);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
case 'clear': {
|
|
100
|
+
await clearCliIdentity(dataDir);
|
|
101
|
+
emitResult(
|
|
102
|
+
{ project, cleared: true },
|
|
103
|
+
'CLI identity cleared. Subsequent commands use project-scoped access only.',
|
|
104
|
+
asJson,
|
|
105
|
+
);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
default:
|
|
110
|
+
emitError(`unknown identity action "${action}". Use "status", "join", "use", or "clear".`, asJson);
|
|
111
|
+
}
|
|
112
|
+
} catch (error) {
|
|
113
|
+
emitError(error instanceof Error ? error.message : String(error), asJson);
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
});
|
|
@@ -1,153 +1,153 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLI Command: memorix ingest commit
|
|
3
|
-
*
|
|
4
|
-
* Extract engineering knowledge from a git commit and store as memory.
|
|
5
|
-
* This is the Git→Memory direction — unique to Memorix.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { defineCommand } from 'citty';
|
|
9
|
-
import * as p from '@clack/prompts';
|
|
10
|
-
|
|
11
|
-
export default defineCommand({
|
|
12
|
-
meta: {
|
|
13
|
-
name: 'commit',
|
|
14
|
-
description: 'Ingest a git commit as memory',
|
|
15
|
-
},
|
|
16
|
-
args: {
|
|
17
|
-
ref: {
|
|
18
|
-
type: 'string',
|
|
19
|
-
description: 'Commit ref (default: HEAD)',
|
|
20
|
-
required: false,
|
|
21
|
-
},
|
|
22
|
-
auto: {
|
|
23
|
-
type: 'boolean',
|
|
24
|
-
description: 'Non-interactive mode (used by git post-commit hook)',
|
|
25
|
-
required: false,
|
|
26
|
-
},
|
|
27
|
-
force: {
|
|
28
|
-
type: 'boolean',
|
|
29
|
-
description: 'Bypass Git noise filter and ingest anyway',
|
|
30
|
-
required: false,
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
run: async ({ args }) => {
|
|
34
|
-
const os = await import('node:os');
|
|
35
|
-
let cwd: string;
|
|
36
|
-
try { cwd = process.cwd(); } catch { cwd = os.homedir(); }
|
|
37
|
-
|
|
38
|
-
const ref = args.ref || 'HEAD';
|
|
39
|
-
const auto = !!args.auto;
|
|
40
|
-
const force = !!args.force;
|
|
41
|
-
|
|
42
|
-
if (!auto) p.intro(`Ingest commit: ${ref}`);
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
const { getCommitInfo, ingestCommit } = await import('../../git/extractor.js');
|
|
46
|
-
const commit = getCommitInfo(cwd, ref);
|
|
47
|
-
|
|
48
|
-
// Noise filter: skip low-value commits (typo, format, lockfile, merge, etc.)
|
|
49
|
-
const { shouldFilterCommit } = await import('../../git/noise-filter.js');
|
|
50
|
-
const { getGitConfig } = await import('../../config.js');
|
|
51
|
-
const gitCfg = getGitConfig();
|
|
52
|
-
const filterResult = shouldFilterCommit(commit, {
|
|
53
|
-
skipMergeCommits: gitCfg.skipMergeCommits,
|
|
54
|
-
excludePatterns: gitCfg.excludePatterns,
|
|
55
|
-
noiseKeywords: gitCfg.noiseKeywords,
|
|
56
|
-
});
|
|
57
|
-
if (filterResult.skip && !force) {
|
|
58
|
-
if (auto) {
|
|
59
|
-
console.error(`[memorix] Skipped ${commit.shortHash}: ${filterResult.reason}`);
|
|
60
|
-
process.exit(0);
|
|
61
|
-
} else {
|
|
62
|
-
p.log.warn(`Commit ${commit.shortHash} filtered as noise: ${filterResult.reason}`);
|
|
63
|
-
p.outro('Use --force to override the noise filter.');
|
|
64
|
-
}
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const result = ingestCommit(commit);
|
|
69
|
-
|
|
70
|
-
// Store via memorix_store logic
|
|
71
|
-
const { initObservations, storeObservation } = await import('../../memory/observations.js');
|
|
72
|
-
const { getProjectDataDir } = await import('../../store/persistence.js');
|
|
73
|
-
const { detectProject } = await import('../../project/detector.js');
|
|
74
|
-
const { initObservationStore, getObservationStore: getStore } = await import('../../store/obs-store.js');
|
|
75
|
-
|
|
76
|
-
const project = detectProject(cwd);
|
|
77
|
-
if (!project) {
|
|
78
|
-
if (!auto) p.log.error('No .git found — not a project directory.');
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
const dataDir = await getProjectDataDir(project.id);
|
|
82
|
-
await initObservationStore(dataDir);
|
|
83
|
-
await initObservations(dataDir);
|
|
84
|
-
|
|
85
|
-
// Dedup: skip if this commit hash was already ingested
|
|
86
|
-
const existingObs = await getStore().loadAll() as Array<{ commitHash?: string }>;
|
|
87
|
-
if (existingObs.some(o => o.commitHash === commit.hash)) {
|
|
88
|
-
if (!auto) p.log.warn(`Commit ${commit.shortHash} already ingested. Skipping.`);
|
|
89
|
-
if (auto) process.exit(0);
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (!auto) {
|
|
94
|
-
// Interactive: show details and confirm
|
|
95
|
-
console.log('');
|
|
96
|
-
console.log(`Commit: ${commit.shortHash} — ${commit.subject}`);
|
|
97
|
-
console.log(`Author: ${commit.author} @ ${commit.date}`);
|
|
98
|
-
console.log(`Files: ${commit.filesChanged.length} changed (+${commit.insertions}/-${commit.deletions})`);
|
|
99
|
-
console.log('');
|
|
100
|
-
console.log(`Entity: ${result.entityName}`);
|
|
101
|
-
console.log(`Type: ${result.type}`);
|
|
102
|
-
console.log(`Title: ${result.title}`);
|
|
103
|
-
console.log('');
|
|
104
|
-
console.log('Facts:');
|
|
105
|
-
for (const fact of result.facts) {
|
|
106
|
-
console.log(` - ${fact}`);
|
|
107
|
-
}
|
|
108
|
-
if (result.concepts.length > 0) {
|
|
109
|
-
console.log(`Concepts: ${result.concepts.join(', ')}`);
|
|
110
|
-
}
|
|
111
|
-
console.log('');
|
|
112
|
-
|
|
113
|
-
const confirmed = await p.confirm({
|
|
114
|
-
message: 'Store this commit as memory?',
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
if (p.isCancel(confirmed) || !confirmed) {
|
|
118
|
-
p.outro('Ingest cancelled.');
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
await storeObservation({
|
|
124
|
-
entityName: result.entityName,
|
|
125
|
-
type: result.type as any,
|
|
126
|
-
title: result.title,
|
|
127
|
-
sourceDetail: 'git-ingest',
|
|
128
|
-
narrative: result.narrative,
|
|
129
|
-
facts: result.facts,
|
|
130
|
-
concepts: result.concepts,
|
|
131
|
-
filesModified: result.filesModified,
|
|
132
|
-
projectId: project.id,
|
|
133
|
-
source: 'git',
|
|
134
|
-
commitHash: commit.hash,
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
if (auto) {
|
|
138
|
-
console.error(`[memorix] Git memory: ${commit.shortHash} — ${commit.subject}`);
|
|
139
|
-
process.exit(0);
|
|
140
|
-
} else {
|
|
141
|
-
p.outro(`Memory stored from commit ${commit.shortHash}.`);
|
|
142
|
-
}
|
|
143
|
-
} catch (err) {
|
|
144
|
-
if (auto) {
|
|
145
|
-
console.error(`[memorix] Git hook ingest failed: ${err}`);
|
|
146
|
-
process.exit(1);
|
|
147
|
-
} else {
|
|
148
|
-
console.error(`Failed to ingest commit: ${err}`);
|
|
149
|
-
p.outro('Ingest failed. Make sure you are in a git repository.');
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* CLI Command: memorix ingest commit
|
|
3
|
+
*
|
|
4
|
+
* Extract engineering knowledge from a git commit and store as memory.
|
|
5
|
+
* This is the Git→Memory direction — unique to Memorix.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { defineCommand } from 'citty';
|
|
9
|
+
import * as p from '@clack/prompts';
|
|
10
|
+
|
|
11
|
+
export default defineCommand({
|
|
12
|
+
meta: {
|
|
13
|
+
name: 'commit',
|
|
14
|
+
description: 'Ingest a git commit as memory',
|
|
15
|
+
},
|
|
16
|
+
args: {
|
|
17
|
+
ref: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'Commit ref (default: HEAD)',
|
|
20
|
+
required: false,
|
|
21
|
+
},
|
|
22
|
+
auto: {
|
|
23
|
+
type: 'boolean',
|
|
24
|
+
description: 'Non-interactive mode (used by git post-commit hook)',
|
|
25
|
+
required: false,
|
|
26
|
+
},
|
|
27
|
+
force: {
|
|
28
|
+
type: 'boolean',
|
|
29
|
+
description: 'Bypass Git noise filter and ingest anyway',
|
|
30
|
+
required: false,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
run: async ({ args }) => {
|
|
34
|
+
const os = await import('node:os');
|
|
35
|
+
let cwd: string;
|
|
36
|
+
try { cwd = process.cwd(); } catch { cwd = os.homedir(); }
|
|
37
|
+
|
|
38
|
+
const ref = args.ref || 'HEAD';
|
|
39
|
+
const auto = !!args.auto;
|
|
40
|
+
const force = !!args.force;
|
|
41
|
+
|
|
42
|
+
if (!auto) p.intro(`Ingest commit: ${ref}`);
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const { getCommitInfo, ingestCommit } = await import('../../git/extractor.js');
|
|
46
|
+
const commit = getCommitInfo(cwd, ref);
|
|
47
|
+
|
|
48
|
+
// Noise filter: skip low-value commits (typo, format, lockfile, merge, etc.)
|
|
49
|
+
const { shouldFilterCommit } = await import('../../git/noise-filter.js');
|
|
50
|
+
const { getGitConfig } = await import('../../config.js');
|
|
51
|
+
const gitCfg = getGitConfig();
|
|
52
|
+
const filterResult = shouldFilterCommit(commit, {
|
|
53
|
+
skipMergeCommits: gitCfg.skipMergeCommits,
|
|
54
|
+
excludePatterns: gitCfg.excludePatterns,
|
|
55
|
+
noiseKeywords: gitCfg.noiseKeywords,
|
|
56
|
+
});
|
|
57
|
+
if (filterResult.skip && !force) {
|
|
58
|
+
if (auto) {
|
|
59
|
+
console.error(`[memorix] Skipped ${commit.shortHash}: ${filterResult.reason}`);
|
|
60
|
+
process.exit(0);
|
|
61
|
+
} else {
|
|
62
|
+
p.log.warn(`Commit ${commit.shortHash} filtered as noise: ${filterResult.reason}`);
|
|
63
|
+
p.outro('Use --force to override the noise filter.');
|
|
64
|
+
}
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const result = ingestCommit(commit);
|
|
69
|
+
|
|
70
|
+
// Store via memorix_store logic
|
|
71
|
+
const { initObservations, storeObservation } = await import('../../memory/observations.js');
|
|
72
|
+
const { getProjectDataDir } = await import('../../store/persistence.js');
|
|
73
|
+
const { detectProject } = await import('../../project/detector.js');
|
|
74
|
+
const { initObservationStore, getObservationStore: getStore } = await import('../../store/obs-store.js');
|
|
75
|
+
|
|
76
|
+
const project = detectProject(cwd);
|
|
77
|
+
if (!project) {
|
|
78
|
+
if (!auto) p.log.error('No .git found — not a project directory.');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const dataDir = await getProjectDataDir(project.id);
|
|
82
|
+
await initObservationStore(dataDir);
|
|
83
|
+
await initObservations(dataDir);
|
|
84
|
+
|
|
85
|
+
// Dedup: skip if this commit hash was already ingested
|
|
86
|
+
const existingObs = await getStore().loadAll() as Array<{ commitHash?: string }>;
|
|
87
|
+
if (existingObs.some(o => o.commitHash === commit.hash)) {
|
|
88
|
+
if (!auto) p.log.warn(`Commit ${commit.shortHash} already ingested. Skipping.`);
|
|
89
|
+
if (auto) process.exit(0);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!auto) {
|
|
94
|
+
// Interactive: show details and confirm
|
|
95
|
+
console.log('');
|
|
96
|
+
console.log(`Commit: ${commit.shortHash} — ${commit.subject}`);
|
|
97
|
+
console.log(`Author: ${commit.author} @ ${commit.date}`);
|
|
98
|
+
console.log(`Files: ${commit.filesChanged.length} changed (+${commit.insertions}/-${commit.deletions})`);
|
|
99
|
+
console.log('');
|
|
100
|
+
console.log(`Entity: ${result.entityName}`);
|
|
101
|
+
console.log(`Type: ${result.type}`);
|
|
102
|
+
console.log(`Title: ${result.title}`);
|
|
103
|
+
console.log('');
|
|
104
|
+
console.log('Facts:');
|
|
105
|
+
for (const fact of result.facts) {
|
|
106
|
+
console.log(` - ${fact}`);
|
|
107
|
+
}
|
|
108
|
+
if (result.concepts.length > 0) {
|
|
109
|
+
console.log(`Concepts: ${result.concepts.join(', ')}`);
|
|
110
|
+
}
|
|
111
|
+
console.log('');
|
|
112
|
+
|
|
113
|
+
const confirmed = await p.confirm({
|
|
114
|
+
message: 'Store this commit as memory?',
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (p.isCancel(confirmed) || !confirmed) {
|
|
118
|
+
p.outro('Ingest cancelled.');
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
await storeObservation({
|
|
124
|
+
entityName: result.entityName,
|
|
125
|
+
type: result.type as any,
|
|
126
|
+
title: result.title,
|
|
127
|
+
sourceDetail: 'git-ingest',
|
|
128
|
+
narrative: result.narrative,
|
|
129
|
+
facts: result.facts,
|
|
130
|
+
concepts: result.concepts,
|
|
131
|
+
filesModified: result.filesModified,
|
|
132
|
+
projectId: project.id,
|
|
133
|
+
source: 'git',
|
|
134
|
+
commitHash: commit.hash,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
if (auto) {
|
|
138
|
+
console.error(`[memorix] Git memory: ${commit.shortHash} — ${commit.subject}`);
|
|
139
|
+
process.exit(0);
|
|
140
|
+
} else {
|
|
141
|
+
p.outro(`Memory stored from commit ${commit.shortHash}.`);
|
|
142
|
+
}
|
|
143
|
+
} catch (err) {
|
|
144
|
+
if (auto) {
|
|
145
|
+
console.error(`[memorix] Git hook ingest failed: ${err}`);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
} else {
|
|
148
|
+
console.error(`Failed to ingest commit: ${err}`);
|
|
149
|
+
p.outro('Ingest failed. Make sure you are in a git repository.');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
});
|