memorix 1.1.13 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +3 -2
- package/README.zh-CN.md +3 -2
- package/dist/cli/index.js +36313 -31189
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/static/app.js +50 -30
- package/dist/index.js +5348 -674
- package/dist/index.js.map +1 -1
- package/dist/maintenance-runner.d.ts +1 -1
- package/dist/maintenance-runner.js +3661 -293
- package/dist/maintenance-runner.js.map +1 -1
- package/dist/memcode-runtime/CHANGELOG.md +19 -0
- package/dist/sdk.d.ts +1 -1
- package/dist/sdk.js +5346 -672
- package/dist/sdk.js.map +1 -1
- package/docs/1.2.0-CLAIM-LEDGER.md +72 -0
- package/docs/1.2.0-CODE-STATE.md +61 -0
- package/docs/1.2.0-DEVELOPMENT-CHARTER.md +255 -0
- package/docs/1.2.0-DYNAMIC-LIFECYCLE.md +71 -0
- package/docs/1.2.0-EVALUATION-HARNESS.md +51 -0
- package/docs/1.2.0-IMPLEMENTATION-PLAN.md +554 -0
- package/docs/1.2.0-KNOWLEDGE-WORKFLOW-RESEARCH.md +205 -0
- package/docs/1.2.0-KNOWLEDGE-WORKSPACE.md +68 -0
- package/docs/1.2.0-PRODUCT-STORY.md +234 -0
- package/docs/1.2.0-PROVIDER-QUALITY.md +189 -0
- package/docs/1.2.0-WORKFLOW-INHERITANCE.md +101 -0
- package/docs/1.2.0-WORKSET-RETRIEVAL.md +80 -0
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +6 -3
- package/docs/API_REFERENCE.md +25 -6
- package/docs/CONFIGURATION.md +21 -3
- package/docs/README.md +17 -2
- package/docs/dev-log/progress.txt +120 -40
- package/llms-full.txt +16 -2
- package/llms.txt +9 -4
- package/package.json +3 -2
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/src/cli/capability-map.ts +1 -0
- package/src/cli/commands/codegraph.ts +112 -9
- package/src/cli/commands/context.ts +2 -0
- package/src/cli/commands/doctor.ts +73 -4
- package/src/cli/commands/knowledge.ts +282 -0
- package/src/cli/commands/serve-http.ts +12 -1
- package/src/cli/index.ts +3 -1
- package/src/cli/tui/App.tsx +1 -1
- package/src/cli/tui/Panels.tsx +8 -8
- package/src/cli/tui/theme.ts +1 -1
- package/src/cli/tui/views/GraphView.tsx +8 -7
- package/src/cli/tui/views/KnowledgeView.tsx +9 -9
- package/src/codegraph/auto-context.ts +171 -9
- package/src/codegraph/code-state.ts +95 -0
- package/src/codegraph/context-pack.ts +82 -1
- package/src/codegraph/external-provider.ts +581 -0
- package/src/codegraph/lite-provider.ts +64 -19
- package/src/codegraph/project-context.ts +9 -1
- package/src/codegraph/store.ts +154 -6
- package/src/codegraph/types.ts +117 -0
- package/src/config/resolved-config.ts +28 -0
- package/src/config/toml-loader.ts +3 -0
- package/src/config/yaml-loader.ts +6 -0
- package/src/dashboard/server.ts +15 -1
- package/src/evaluation/workset-evaluation.ts +120 -0
- package/src/hooks/handler.ts +48 -6
- package/src/knowledge/claim-store.ts +267 -0
- package/src/knowledge/claims.ts +537 -0
- package/src/knowledge/markdown.ts +129 -0
- package/src/knowledge/types.ts +157 -0
- package/src/knowledge/wiki.ts +524 -0
- package/src/knowledge/workflow-store.ts +168 -0
- package/src/knowledge/workflow-types.ts +95 -0
- package/src/knowledge/workflows.ts +743 -0
- package/src/knowledge/workset.ts +515 -0
- package/src/knowledge/workspace-store.ts +220 -0
- package/src/knowledge/workspace-types.ts +106 -0
- package/src/knowledge/workspace.ts +220 -0
- package/src/memory/observations.ts +19 -0
- package/src/runtime/control-plane-maintenance.ts +5 -0
- package/src/runtime/isolated-maintenance.ts +5 -0
- package/src/runtime/lifecycle-status.ts +102 -0
- package/src/runtime/lifecycle.ts +107 -0
- package/src/runtime/maintenance-jobs.ts +5 -0
- package/src/runtime/project-maintenance.ts +190 -0
- package/src/server/tool-profile.ts +3 -2
- package/src/server.ts +354 -14
- package/src/store/file-lock.ts +24 -4
- package/src/store/sqlite-db.ts +307 -0
- package/src/wiki/generator.ts +4 -2
- package/src/wiki/knowledge-graph.ts +7 -4
- package/src/wiki/types.ts +16 -4
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { defineCommand } from 'citty';
|
|
2
|
+
import { CodeGraphStore } from '../../codegraph/store.js';
|
|
3
|
+
import { ClaimStore } from '../../knowledge/claim-store.js';
|
|
4
|
+
import { applyKnowledgeProposal, compileKnowledgeWorkspace, lintKnowledgeWorkspace } from '../../knowledge/wiki.js';
|
|
5
|
+
import { initializeKnowledgeWorkspace, loadKnowledgeWorkspace } from '../../knowledge/workspace.js';
|
|
6
|
+
import { KnowledgeWorkspaceStore } from '../../knowledge/workspace-store.js';
|
|
7
|
+
import { WorkflowStore } from '../../knowledge/workflow-store.js';
|
|
8
|
+
import {
|
|
9
|
+
applyWorkflowAdapter,
|
|
10
|
+
importWindsurfWorkflows,
|
|
11
|
+
previewWorkflowAdapter,
|
|
12
|
+
recordWorkflowRun,
|
|
13
|
+
selectWorkspaceWorkflows,
|
|
14
|
+
syncCanonicalWorkflows,
|
|
15
|
+
} from '../../knowledge/workflows.js';
|
|
16
|
+
import { emitError, emitResult, getCliProjectContext } from './operator-shared.js';
|
|
17
|
+
|
|
18
|
+
function modeFrom(value: unknown): 'local' | 'versioned' {
|
|
19
|
+
if (!value || value === 'local') return 'local';
|
|
20
|
+
if (value === 'versioned') return 'versioned';
|
|
21
|
+
throw new Error('knowledge mode must be local or versioned');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function usage(): string {
|
|
25
|
+
return [
|
|
26
|
+
'Memorix Knowledge Commands',
|
|
27
|
+
'',
|
|
28
|
+
' memorix knowledge init [--mode local]',
|
|
29
|
+
' memorix knowledge init --mode versioned --path C:\\project\\docs\\knowledge',
|
|
30
|
+
' memorix knowledge status',
|
|
31
|
+
' memorix knowledge compile',
|
|
32
|
+
' memorix knowledge lint',
|
|
33
|
+
' memorix knowledge apply --proposal <id> [--force]',
|
|
34
|
+
' memorix knowledge workflow import',
|
|
35
|
+
' memorix knowledge workflow list',
|
|
36
|
+
' memorix knowledge workflow select --task "prepare a release"',
|
|
37
|
+
' memorix knowledge workflow preview --id <workflow-id> --agent codex',
|
|
38
|
+
' memorix knowledge workflow apply --id <workflow-id> --agent codex',
|
|
39
|
+
' memorix knowledge workflow run --id <workflow-id> --task "..." --outcome passed',
|
|
40
|
+
].join('\n');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function requiredText(value: unknown, field: string): string {
|
|
44
|
+
const text = typeof value === 'string' ? value.trim() : '';
|
|
45
|
+
if (!text) throw new Error(field + ' is required');
|
|
46
|
+
return text;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function workflowOutcome(value: unknown): 'passed' | 'failed' | 'cancelled' | 'in-progress' {
|
|
50
|
+
if (value === 'passed' || value === 'failed' || value === 'cancelled' || value === 'in-progress') return value;
|
|
51
|
+
throw new Error('workflow outcome must be passed, failed, cancelled, or in-progress');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function workflowVerdict(value: unknown): 'passed' | 'failed' | 'not-run' | undefined {
|
|
55
|
+
if (value === undefined || value === null || value === '') return undefined;
|
|
56
|
+
if (value === 'passed' || value === 'failed' || value === 'not-run') return value;
|
|
57
|
+
throw new Error('workflow verdict must be passed, failed, or not-run');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function evidenceList(value: unknown): string[] {
|
|
61
|
+
if (typeof value !== 'string' || !value.trim()) return [];
|
|
62
|
+
return [...new Set(value.split(',').map(item => item.trim()).filter(Boolean))];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default defineCommand({
|
|
66
|
+
meta: {
|
|
67
|
+
name: 'knowledge',
|
|
68
|
+
description: 'Initialize, review, and lint the Memorix Knowledge Workspace',
|
|
69
|
+
},
|
|
70
|
+
args: {
|
|
71
|
+
action: { type: 'string', description: 'Action: init, status, compile, lint, or apply' },
|
|
72
|
+
mode: { type: 'string', description: 'Workspace mode: local or versioned' },
|
|
73
|
+
path: { type: 'string', description: 'Explicit versioned workspace path for init' },
|
|
74
|
+
proposal: { type: 'string', description: 'Proposal id for apply' },
|
|
75
|
+
force: { type: 'boolean', description: 'Explicitly allow an approved proposal to replace manual page edits' },
|
|
76
|
+
id: { type: 'string', description: 'Canonical workflow id' },
|
|
77
|
+
agent: { type: 'string', description: 'Target agent for a workflow adapter' },
|
|
78
|
+
task: { type: 'string', description: 'Task wording for workflow selection or a workflow run' },
|
|
79
|
+
outcome: { type: 'string', description: 'Workflow run outcome: passed, failed, cancelled, or in-progress' },
|
|
80
|
+
verdict: { type: 'string', description: 'Workflow verification verdict: passed, failed, or not-run' },
|
|
81
|
+
failure: { type: 'string', description: 'Sanitized failure reason for a workflow run' },
|
|
82
|
+
snapshot: { type: 'string', description: 'Starting code snapshot id for a workflow run' },
|
|
83
|
+
evidence: { type: 'string', description: 'Comma-separated evidence ids selected for a workflow run' },
|
|
84
|
+
json: { type: 'boolean', description: 'Emit machine-readable JSON output' },
|
|
85
|
+
},
|
|
86
|
+
run: async ({ args }) => {
|
|
87
|
+
const positional = (args._ as string[]) ?? [];
|
|
88
|
+
const action = (positional[0] || (args.action as string | undefined) || 'status').toLowerCase();
|
|
89
|
+
const asJson = !!args.json;
|
|
90
|
+
try {
|
|
91
|
+
const { project, dataDir } = await getCliProjectContext();
|
|
92
|
+
const mode = modeFrom(args.mode);
|
|
93
|
+
if (action === 'init') {
|
|
94
|
+
const workspace = await initializeKnowledgeWorkspace({
|
|
95
|
+
projectId: project.id,
|
|
96
|
+
dataDir,
|
|
97
|
+
mode,
|
|
98
|
+
...(mode === 'versioned'
|
|
99
|
+
? {
|
|
100
|
+
projectRoot: project.rootPath,
|
|
101
|
+
rootPath: (args.path as string | undefined) ?? '',
|
|
102
|
+
}
|
|
103
|
+
: {}),
|
|
104
|
+
});
|
|
105
|
+
emitResult(
|
|
106
|
+
{ project, workspace },
|
|
107
|
+
'Knowledge workspace initialized at ' + workspace.rootPath,
|
|
108
|
+
asJson,
|
|
109
|
+
);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const workspace = await loadKnowledgeWorkspace({ projectId: project.id, dataDir, mode });
|
|
114
|
+
if (!workspace) {
|
|
115
|
+
emitError('Knowledge workspace is not initialized. Run "memorix knowledge init" first.', asJson);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const claimStore = new ClaimStore();
|
|
119
|
+
await claimStore.init(dataDir);
|
|
120
|
+
const workspaceStore = new KnowledgeWorkspaceStore();
|
|
121
|
+
await workspaceStore.init(dataDir);
|
|
122
|
+
|
|
123
|
+
if (action === 'workflow') {
|
|
124
|
+
const workflowAction = (positional[1] || 'list').toLowerCase();
|
|
125
|
+
const workflowStore = new WorkflowStore();
|
|
126
|
+
await workflowStore.init(dataDir);
|
|
127
|
+
const projectRoot = workspace.projectRoot ?? project.rootPath;
|
|
128
|
+
|
|
129
|
+
if (workflowAction === 'import') {
|
|
130
|
+
const result = await importWindsurfWorkflows({ workspace, projectRoot });
|
|
131
|
+
emitResult(
|
|
132
|
+
{ project, workspace, result },
|
|
133
|
+
'Imported ' + result.imported.length + ' Windsurf workflow(s); preserved ' + result.skipped.length + ' existing source or canonical file(s).',
|
|
134
|
+
asJson,
|
|
135
|
+
);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const synced = await syncCanonicalWorkflows(workspace);
|
|
140
|
+
if (workflowAction === 'list') {
|
|
141
|
+
emitResult(
|
|
142
|
+
{
|
|
143
|
+
project,
|
|
144
|
+
workspace,
|
|
145
|
+
workflows: workflowStore.listWorkflows(workspace.id),
|
|
146
|
+
parseErrors: synced.errors,
|
|
147
|
+
},
|
|
148
|
+
[
|
|
149
|
+
'Canonical workflows: ' + workflowStore.listWorkflows(workspace.id).length,
|
|
150
|
+
'Parse errors: ' + synced.errors.length,
|
|
151
|
+
].join('\n'),
|
|
152
|
+
asJson,
|
|
153
|
+
);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (workflowAction === 'select') {
|
|
158
|
+
const task = requiredText(args.task, 'task');
|
|
159
|
+
const result = await selectWorkspaceWorkflows({ workspace, task });
|
|
160
|
+
emitResult(
|
|
161
|
+
{ project, workspace, task, ...result },
|
|
162
|
+
result.selections.length
|
|
163
|
+
? 'Selected ' + result.selections.length + ' workflow(s) for this task.'
|
|
164
|
+
: 'No project workflow matches this task.',
|
|
165
|
+
asJson,
|
|
166
|
+
);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const workflowId = requiredText(args.id, 'workflow id');
|
|
171
|
+
const workflow = workflowStore.getWorkflow(workflowId);
|
|
172
|
+
if (!workflow || workflow.workspaceId !== workspace.id) {
|
|
173
|
+
emitError('Workflow was not found for this knowledge workspace.', asJson);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (workflowAction === 'preview' || workflowAction === 'apply') {
|
|
178
|
+
const agent = requiredText(args.agent, 'agent');
|
|
179
|
+
const result = workflowAction === 'preview'
|
|
180
|
+
? await previewWorkflowAdapter({ workflow, projectRoot, agent: agent as any })
|
|
181
|
+
: await applyWorkflowAdapter({ workflow, projectRoot, agent: agent as any });
|
|
182
|
+
emitResult(
|
|
183
|
+
{ project, workspace, result },
|
|
184
|
+
'Workflow adapter ' + result.status + ': ' + result.reason,
|
|
185
|
+
asJson,
|
|
186
|
+
);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (workflowAction === 'run') {
|
|
191
|
+
const task = requiredText(args.task, 'task');
|
|
192
|
+
const outcome = workflowOutcome(args.outcome);
|
|
193
|
+
const result = await recordWorkflowRun({
|
|
194
|
+
workspace,
|
|
195
|
+
run: {
|
|
196
|
+
workflowId,
|
|
197
|
+
projectId: project.id,
|
|
198
|
+
task,
|
|
199
|
+
outcome,
|
|
200
|
+
...(workflowVerdict(args.verdict) ? { verificationVerdict: workflowVerdict(args.verdict) } : {}),
|
|
201
|
+
...(typeof args.failure === 'string' && args.failure.trim() ? { failureReason: args.failure.trim() } : {}),
|
|
202
|
+
...(typeof args.snapshot === 'string' && args.snapshot.trim() ? { startingSnapshotId: args.snapshot.trim() } : {}),
|
|
203
|
+
selectedEvidence: evidenceList(args.evidence),
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
emitResult(
|
|
207
|
+
{ project, workspace, result },
|
|
208
|
+
'Recorded workflow run ' + result.id + ' (' + result.outcome + ').',
|
|
209
|
+
asJson,
|
|
210
|
+
);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
emitResult({ usage: usage() }, usage(), asJson);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
switch (action) {
|
|
219
|
+
case 'status': {
|
|
220
|
+
const pages = workspaceStore.listPages(workspace.id);
|
|
221
|
+
const pending = workspaceStore.listProposals(workspace.id, 'pending');
|
|
222
|
+
emitResult(
|
|
223
|
+
{ project, workspace, pages, pendingProposals: pending },
|
|
224
|
+
[
|
|
225
|
+
'Knowledge workspace: ' + workspace.rootPath,
|
|
226
|
+
'- Mode: ' + workspace.mode,
|
|
227
|
+
'- Published pages: ' + pages.filter(page => page.status === 'active').length,
|
|
228
|
+
'- Pending proposals: ' + pending.length,
|
|
229
|
+
'- Status: ' + workspace.status,
|
|
230
|
+
].join('\n'),
|
|
231
|
+
asJson,
|
|
232
|
+
);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
case 'compile': {
|
|
236
|
+
const result = await compileKnowledgeWorkspace({ workspace, claims: claimStore });
|
|
237
|
+
emitResult(
|
|
238
|
+
{ project, workspace, result },
|
|
239
|
+
'Knowledge compilation completed: ' + result.proposals.length + ' proposal(s), ' + result.published.length + ' unchanged published page(s).',
|
|
240
|
+
asJson,
|
|
241
|
+
);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
case 'lint': {
|
|
245
|
+
const codeStore = new CodeGraphStore();
|
|
246
|
+
await codeStore.init(dataDir);
|
|
247
|
+
const result = await lintKnowledgeWorkspace({ workspace, claims: claimStore, codeStore });
|
|
248
|
+
emitResult(
|
|
249
|
+
{ project, workspace, result },
|
|
250
|
+
result.valid
|
|
251
|
+
? 'Knowledge workspace lint passed.'
|
|
252
|
+
: 'Knowledge workspace lint found ' + result.issues.length + ' issue(s).',
|
|
253
|
+
asJson,
|
|
254
|
+
);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
case 'apply': {
|
|
258
|
+
const proposalId = (args.proposal as string | undefined)?.trim();
|
|
259
|
+
if (!proposalId) {
|
|
260
|
+
emitError('proposal is required for "memorix knowledge apply"', asJson);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
const result = await applyKnowledgeProposal({
|
|
264
|
+
workspace,
|
|
265
|
+
proposalId,
|
|
266
|
+
allowManualOverwrite: !!args.force,
|
|
267
|
+
});
|
|
268
|
+
emitResult(
|
|
269
|
+
{ project, workspace, result },
|
|
270
|
+
'Knowledge proposal applied to ' + result.targetPath,
|
|
271
|
+
asJson,
|
|
272
|
+
);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
default:
|
|
276
|
+
emitResult({ usage: usage() }, usage(), asJson);
|
|
277
|
+
}
|
|
278
|
+
} catch (error) {
|
|
279
|
+
emitError(error instanceof Error ? error.message : String(error), asJson);
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
});
|
|
@@ -868,9 +868,12 @@ export default defineCommand({
|
|
|
868
868
|
const projectRelations = graph.relations.filter((r: any) => projectEntitySet.has(r.from) && projectEntitySet.has(r.to));
|
|
869
869
|
|
|
870
870
|
let maintenance = { total: 0, pending: 0, running: 0, retrying: 0, completed: 0, failed: 0 };
|
|
871
|
+
let lifecycle: unknown;
|
|
871
872
|
try {
|
|
872
873
|
const { MaintenanceJobStore } = await import('../../runtime/maintenance-jobs.js');
|
|
873
874
|
maintenance = new MaintenanceJobStore(statsDataDir).summary(statsProjectId);
|
|
875
|
+
const { collectLifecycleDiagnostics } = await import('../../runtime/lifecycle-status.js');
|
|
876
|
+
lifecycle = await collectLifecycleDiagnostics({ dataDir: statsDataDir, projectId: statsProjectId });
|
|
874
877
|
} catch { /* optional maintenance diagnostics */ }
|
|
875
878
|
|
|
876
879
|
sendJson({
|
|
@@ -892,17 +895,25 @@ export default defineCommand({
|
|
|
892
895
|
},
|
|
893
896
|
retentionSummary,
|
|
894
897
|
maintenance,
|
|
898
|
+
...(lifecycle ? { lifecycle } : {}),
|
|
895
899
|
});
|
|
896
900
|
return;
|
|
897
901
|
}
|
|
898
902
|
|
|
899
903
|
if (apiPath === '/maintenance') {
|
|
900
904
|
const { projectId: maintenanceProjectId, dataDir: maintenanceDataDir } = await resolveRequestProject(url);
|
|
901
|
-
const { MaintenanceJobStore } = await
|
|
905
|
+
const [{ MaintenanceJobStore }, { collectLifecycleDiagnostics }] = await Promise.all([
|
|
906
|
+
import('../../runtime/maintenance-jobs.js'),
|
|
907
|
+
import('../../runtime/lifecycle-status.js'),
|
|
908
|
+
]);
|
|
902
909
|
const queue = new MaintenanceJobStore(maintenanceDataDir);
|
|
903
910
|
sendJson({
|
|
904
911
|
summary: queue.summary(maintenanceProjectId),
|
|
905
912
|
jobs: queue.list({ projectId: maintenanceProjectId, limit: 50 }),
|
|
913
|
+
lifecycle: await collectLifecycleDiagnostics({
|
|
914
|
+
dataDir: maintenanceDataDir,
|
|
915
|
+
projectId: maintenanceProjectId,
|
|
916
|
+
}),
|
|
906
917
|
});
|
|
907
918
|
return;
|
|
908
919
|
}
|
package/src/cli/index.ts
CHANGED
|
@@ -989,6 +989,7 @@ const main = defineCommand({
|
|
|
989
989
|
context: () => import('./commands/context.js').then(m => m.default),
|
|
990
990
|
explain: () => import('./commands/explain.js').then(m => m.default),
|
|
991
991
|
codegraph: () => import('./commands/codegraph.js').then(m => m.default),
|
|
992
|
+
knowledge: () => import('./commands/knowledge.js').then(m => m.default),
|
|
992
993
|
reasoning: () => import('./commands/reasoning.js').then(m => m.default),
|
|
993
994
|
retention: () => import('./commands/retention.js').then(m => m.default),
|
|
994
995
|
formation: () => import('./commands/formation.js').then(m => m.default),
|
|
@@ -1048,7 +1049,7 @@ const main = defineCommand({
|
|
|
1048
1049
|
// Detect by checking if the first CLI arg matches a registered subcommand name.
|
|
1049
1050
|
const firstArg = process.argv[2];
|
|
1050
1051
|
const knownSubs = ['ask', 'search', 'remember', 'recent', 'memcode', 'config',
|
|
1051
|
-
'init', 'setup', 'integrate', 'memory', 'context', 'explain', 'codegraph', 'reasoning', 'retention', 'formation', 'audit', 'transfer', 'skills',
|
|
1052
|
+
'init', 'setup', 'integrate', 'memory', 'context', 'explain', 'codegraph', 'knowledge', 'reasoning', 'retention', 'formation', 'audit', 'transfer', 'skills',
|
|
1052
1053
|
'session', 'team', 'task', 'message', 'lock', 'handoff', 'poll',
|
|
1053
1054
|
'receipt',
|
|
1054
1055
|
'serve', 'serve-http', 'status', 'sync',
|
|
@@ -1088,6 +1089,7 @@ const main = defineCommand({
|
|
|
1088
1089
|
console.error(' context Show the Memory Autopilot brief for this project');
|
|
1089
1090
|
console.error(' explain Explain where Memorix project context comes from');
|
|
1090
1091
|
console.error(' codegraph Refresh/status/context-pack for CodeGraph Memory');
|
|
1092
|
+
console.error(' knowledge Review source-backed knowledge pages and project workflows');
|
|
1091
1093
|
console.error(' reasoning Store/search decision rationale');
|
|
1092
1094
|
console.error(' retention Inspect stale/archive status');
|
|
1093
1095
|
console.error(' formation Inspect Memory Formation metrics');
|
package/src/cli/tui/App.tsx
CHANGED
|
@@ -598,7 +598,7 @@ export function WorkbenchApp({ version, onExitForInteractive }: AppProps): React
|
|
|
598
598
|
setKnowledgeSelectedIdx(0);
|
|
599
599
|
setLoading(false);
|
|
600
600
|
navigateTo('knowledge');
|
|
601
|
-
setStatusMsg({ text: kb ? `
|
|
601
|
+
setStatusMsg({ text: kb ? `Memory Overview: ${kb.stats.observationsUsed} obs, ${kb.stats.miniSkillsUsed} skills` : 'No memory overview available', type: 'info' });
|
|
602
602
|
break;
|
|
603
603
|
}
|
|
604
604
|
case 'memory': {
|
package/src/cli/tui/Panels.tsx
CHANGED
|
@@ -553,8 +553,8 @@ export function WikiView({ knowledge, loading }: WikiViewProps): React.ReactElem
|
|
|
553
553
|
if (loading) {
|
|
554
554
|
return (
|
|
555
555
|
<Box flexDirection="column" paddingX={1}>
|
|
556
|
-
<Text color={COLORS.brand} bold>
|
|
557
|
-
<Text color={COLORS.muted}>
|
|
556
|
+
<Text color={COLORS.brand} bold>Memory Overview</Text>
|
|
557
|
+
<Text color={COLORS.muted}> Generated from durable memory</Text>
|
|
558
558
|
<Text color={COLORS.border}>{separator()}</Text>
|
|
559
559
|
<Text color={COLORS.muted}>Loading...</Text>
|
|
560
560
|
</Box>
|
|
@@ -564,19 +564,19 @@ export function WikiView({ knowledge, loading }: WikiViewProps): React.ReactElem
|
|
|
564
564
|
if (!knowledge) {
|
|
565
565
|
return (
|
|
566
566
|
<Box flexDirection="column" paddingX={1}>
|
|
567
|
-
<Text color={COLORS.brand} bold>
|
|
568
|
-
<Text color={COLORS.muted}>
|
|
567
|
+
<Text color={COLORS.brand} bold>Memory Overview</Text>
|
|
568
|
+
<Text color={COLORS.muted}> Generated from durable memory</Text>
|
|
569
569
|
<Text color={COLORS.border}>{separator()}</Text>
|
|
570
|
-
<Text color={COLORS.warning}>No
|
|
571
|
-
<Text color={COLORS.textDim}>Store memories with /remember or /chat to build your
|
|
570
|
+
<Text color={COLORS.warning}>No memory overview is available for this project.</Text>
|
|
571
|
+
<Text color={COLORS.textDim}>Store durable memories with /remember or /chat to build your overview.</Text>
|
|
572
572
|
</Box>
|
|
573
573
|
);
|
|
574
574
|
}
|
|
575
575
|
|
|
576
576
|
return (
|
|
577
577
|
<Box flexDirection="column" paddingX={1}>
|
|
578
|
-
<Text color={COLORS.brand} bold>
|
|
579
|
-
<Text color={COLORS.muted}>
|
|
578
|
+
<Text color={COLORS.brand} bold>Memory Overview</Text>
|
|
579
|
+
<Text color={COLORS.muted}> Generated from durable memory</Text>
|
|
580
580
|
<Box>
|
|
581
581
|
<Text color={COLORS.textDim}> Project: {knowledge.projectId}</Text>
|
|
582
582
|
<Text color={COLORS.muted}> │ {knowledge.stats.observationsUsed} obs, {knowledge.stats.miniSkillsUsed} skills</Text>
|
package/src/cli/tui/theme.ts
CHANGED
|
@@ -31,7 +31,7 @@ export const SLASH_COMMANDS: SlashCommand[] = [
|
|
|
31
31
|
{ name: '/integrate', description: 'Set up an IDE', alias: '/setup' },
|
|
32
32
|
{ name: '/cleanup', description: 'Cleanup and purge' },
|
|
33
33
|
{ name: '/ingest', description: 'Git to Memory' },
|
|
34
|
-
{ name: '/wiki', description: '
|
|
34
|
+
{ name: '/wiki', description: 'Memory overview', alias: '/knowledge' },
|
|
35
35
|
{ name: '/exit', description: 'Exit workbench', alias: '/q' },
|
|
36
36
|
];
|
|
37
37
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* GraphView —
|
|
2
|
+
* GraphView — deterministic memory-map text browser.
|
|
3
3
|
*
|
|
4
4
|
* Modes: browse (clusters + nodes), detail (single node with edge summary).
|
|
5
5
|
* Keyboard: f filter, up/down navigate, enter detail, k -> Knowledge, esc back.
|
|
@@ -168,7 +168,7 @@ export function GraphView({ projectId, inputFocused, onNavigateKnowledge }: Grap
|
|
|
168
168
|
return (
|
|
169
169
|
<Box flexDirection="column" paddingX={1}>
|
|
170
170
|
<Box>
|
|
171
|
-
<Text color={COLORS.brand} bold>
|
|
171
|
+
<Text color={COLORS.brand} bold>Memory Map Item</Text>
|
|
172
172
|
</Box>
|
|
173
173
|
<Text color={COLORS.border}>{separator()}</Text>
|
|
174
174
|
<Box marginY={1} flexDirection="column">
|
|
@@ -190,7 +190,7 @@ export function GraphView({ projectId, inputFocused, onNavigateKnowledge }: Grap
|
|
|
190
190
|
)}
|
|
191
191
|
{/* Edge summary */}
|
|
192
192
|
<Box marginY={1} flexDirection="column">
|
|
193
|
-
<Text color={COLORS.brandDim} bold>
|
|
193
|
+
<Text color={COLORS.brandDim} bold>Links</Text>
|
|
194
194
|
<Text color={COLORS.muted}>Outgoing ({outgoing.length}): </Text>
|
|
195
195
|
{outgoing.slice(0, 6).map((e) => {
|
|
196
196
|
const targetNode = graph?.nodes.find((n) => n.id === e.target);
|
|
@@ -213,7 +213,7 @@ export function GraphView({ projectId, inputFocused, onNavigateKnowledge }: Grap
|
|
|
213
213
|
{incoming.length > 6 && <Text color={COLORS.muted}> ... +{incoming.length - 6} more</Text>}
|
|
214
214
|
</Box>
|
|
215
215
|
<Box marginTop={1}>
|
|
216
|
-
<Text color={COLORS.muted}>esc back | k {'>'}
|
|
216
|
+
<Text color={COLORS.muted}>esc back | k {'>'} Memory Overview</Text>
|
|
217
217
|
</Box>
|
|
218
218
|
</Box>
|
|
219
219
|
);
|
|
@@ -230,11 +230,12 @@ export function GraphView({ projectId, inputFocused, onNavigateKnowledge }: Grap
|
|
|
230
230
|
<Box flexDirection="column" paddingX={1}>
|
|
231
231
|
<Box flexDirection="column">
|
|
232
232
|
<Box>
|
|
233
|
-
<Text color={COLORS.brand} bold>
|
|
233
|
+
<Text color={COLORS.brand} bold>Memory Map</Text>
|
|
234
234
|
{!loading && graph && (
|
|
235
235
|
<Text color={COLORS.muted}> | {graph.stats.totalNodes} nodes, {graph.stats.totalEdges} edges, {graph.stats.clusterCount} clusters</Text>
|
|
236
236
|
)}
|
|
237
237
|
</Box>
|
|
238
|
+
<Text color={COLORS.textDim}>Deterministic links from shared entities, skill sources, and explicit relations</Text>
|
|
238
239
|
{/* Filter bar */}
|
|
239
240
|
{!loading && graph && (
|
|
240
241
|
<Box marginTop={0}>
|
|
@@ -248,7 +249,7 @@ export function GraphView({ projectId, inputFocused, onNavigateKnowledge }: Grap
|
|
|
248
249
|
{loading ? (
|
|
249
250
|
<Text color={COLORS.muted}>Loading...</Text>
|
|
250
251
|
) : !graph ? (
|
|
251
|
-
<Text color={COLORS.muted}>No
|
|
252
|
+
<Text color={COLORS.muted}>No memory map data is available. Store durable observations to build deterministic links.</Text>
|
|
252
253
|
) : flatItems.length === 0 ? (
|
|
253
254
|
<Text color={COLORS.muted}>
|
|
254
255
|
{filterMode !== 'all' ? 'No nodes match this filter.' : 'No nodes in graph.'}
|
|
@@ -290,7 +291,7 @@ export function GraphView({ projectId, inputFocused, onNavigateKnowledge }: Grap
|
|
|
290
291
|
|
|
291
292
|
<Box marginTop={1} flexDirection="column">
|
|
292
293
|
<Text color={COLORS.textDim}>
|
|
293
|
-
f filter | up/down navigate | enter detail | k {'>'}
|
|
294
|
+
f filter | up/down navigate | enter detail | k {'>'} Memory Overview
|
|
294
295
|
</Text>
|
|
295
296
|
</Box>
|
|
296
297
|
</Box>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* KnowledgeView —
|
|
2
|
+
* KnowledgeView — read-only memory overview browser.
|
|
3
3
|
*
|
|
4
4
|
* Displays ProjectKnowledgeOverview sections and items.
|
|
5
5
|
* Each item shows its provenance refs; pressing 'm' on an item
|
|
@@ -36,8 +36,8 @@ export function KnowledgeView({ knowledge, loading, selectedItemIdx, itemCount }
|
|
|
36
36
|
if (loading) {
|
|
37
37
|
return (
|
|
38
38
|
<Box flexDirection="column" paddingX={1}>
|
|
39
|
-
<Text color={COLORS.brand} bold>
|
|
40
|
-
<Text color={COLORS.muted}>
|
|
39
|
+
<Text color={COLORS.brand} bold>Memory Overview</Text>
|
|
40
|
+
<Text color={COLORS.muted}> Generated from durable memory</Text>
|
|
41
41
|
<Text color={COLORS.border}>{separator()}</Text>
|
|
42
42
|
<Text color={COLORS.muted}>Loading…</Text>
|
|
43
43
|
</Box>
|
|
@@ -47,11 +47,11 @@ export function KnowledgeView({ knowledge, loading, selectedItemIdx, itemCount }
|
|
|
47
47
|
if (!knowledge) {
|
|
48
48
|
return (
|
|
49
49
|
<Box flexDirection="column" paddingX={1}>
|
|
50
|
-
<Text color={COLORS.brand} bold>
|
|
51
|
-
<Text color={COLORS.muted}>
|
|
50
|
+
<Text color={COLORS.brand} bold>Memory Overview</Text>
|
|
51
|
+
<Text color={COLORS.muted}> Generated from durable memory</Text>
|
|
52
52
|
<Text color={COLORS.border}>{separator()}</Text>
|
|
53
|
-
<Text color={COLORS.warning}>No
|
|
54
|
-
<Text color={COLORS.textDim}>Store memories with /remember or use Workbench to build context.</Text>
|
|
53
|
+
<Text color={COLORS.warning}>No memory overview is available for this project.</Text>
|
|
54
|
+
<Text color={COLORS.textDim}>Store durable memories with /remember or use Workbench to build context.</Text>
|
|
55
55
|
</Box>
|
|
56
56
|
);
|
|
57
57
|
}
|
|
@@ -68,8 +68,8 @@ export function KnowledgeView({ knowledge, loading, selectedItemIdx, itemCount }
|
|
|
68
68
|
return (
|
|
69
69
|
<Box flexDirection="column" paddingX={1}>
|
|
70
70
|
<Box>
|
|
71
|
-
<Text color={COLORS.brand} bold>
|
|
72
|
-
<Text color={COLORS.muted}>
|
|
71
|
+
<Text color={COLORS.brand} bold>Memory Overview</Text>
|
|
72
|
+
<Text color={COLORS.muted}> Generated from durable memory</Text>
|
|
73
73
|
</Box>
|
|
74
74
|
<Box>
|
|
75
75
|
<Text color={COLORS.textDim}> {knowledge.projectId}</Text>
|