memorix 1.8.0 → 1.8.1
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 +9 -0
- package/dist/cli/index.js +83 -80
- package/dist/dashboard/static/app.js +37 -23
- package/dist/dashboard/static/index.html +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +54 -78
- package/dist/memcode-runtime/CHANGELOG.md +9 -0
- package/dist/sdk.js +53 -77
- package/docs/API_REFERENCE.md +2 -0
- package/docs/ARCHITECTURE.md +3 -1
- package/docs/DASHBOARD.md +6 -0
- package/docs/DEVELOPMENT.md +2 -2
- package/docs/README.md +5 -2
- package/package.json +1 -1
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/gemini/memorix/gemini-extension.json +1 -1
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/pi/memorix/package.json +1 -1
- package/server.json +2 -2
- package/src/cli/commands/dashboard.ts +1 -1
- package/src/cli/commands/serve-http.ts +28 -1
- package/src/dashboard/server.ts +85 -86
- package/src/dashboard/static/index.html +1 -1
- package/src/server.ts +4 -4
package/dist/index.js
CHANGED
|
@@ -164845,6 +164845,37 @@ function normalizeDashboardTask(task) {
|
|
|
164845
164845
|
preferredRole: task.preferred_role ?? task.preferredRole ?? null
|
|
164846
164846
|
};
|
|
164847
164847
|
}
|
|
164848
|
+
function emptyTeamSnapshot(mode, scope, status) {
|
|
164849
|
+
return {
|
|
164850
|
+
status,
|
|
164851
|
+
mode,
|
|
164852
|
+
readOnly: true,
|
|
164853
|
+
scope,
|
|
164854
|
+
agents: [],
|
|
164855
|
+
activeCount: 0,
|
|
164856
|
+
recentCount: 0,
|
|
164857
|
+
historicalCount: 0,
|
|
164858
|
+
totalAgents: 0,
|
|
164859
|
+
recentWindowDays: 7,
|
|
164860
|
+
locks: [],
|
|
164861
|
+
tasks: [],
|
|
164862
|
+
availableTasks: 0,
|
|
164863
|
+
sessions: 0,
|
|
164864
|
+
roles: [],
|
|
164865
|
+
roleOccupancy: [],
|
|
164866
|
+
handoffs: [],
|
|
164867
|
+
openTasks: 0,
|
|
164868
|
+
openHandoffs: 0,
|
|
164869
|
+
totalUnread: 0,
|
|
164870
|
+
activeSessions: 0,
|
|
164871
|
+
error: status === "error" ? "Coordination state unavailable" : "Coordination state is incomplete",
|
|
164872
|
+
errorCode: status === "error" ? "COORDINATION_STATE_UNAVAILABLE" : "COORDINATION_STATE_DEGRADED"
|
|
164873
|
+
};
|
|
164874
|
+
}
|
|
164875
|
+
function logTeamSnapshotFailure(scope, status) {
|
|
164876
|
+
const safeScope = scope === "global" ? "global" : "project";
|
|
164877
|
+
console.error("[dashboard] coordination snapshot unavailable", { status, scope: safeScope });
|
|
164878
|
+
}
|
|
164848
164879
|
async function buildTeamSnapshot(dataDir, projectId, scope, mode) {
|
|
164849
164880
|
try {
|
|
164850
164881
|
const { initTeamStore: initTeamStore2 } = await Promise.resolve().then(() => (init_team_store(), team_store_exports));
|
|
@@ -164871,8 +164902,9 @@ async function buildTeamSnapshot(dataDir, projectId, scope, mode) {
|
|
|
164871
164902
|
const roleOccupancy = effectiveProjectId ? teamStore.getRoleOccupancy(effectiveProjectId) : [];
|
|
164872
164903
|
const handoffs = effectiveProjectId ? teamStore.listHandoffs(effectiveProjectId) : [];
|
|
164873
164904
|
return {
|
|
164905
|
+
status: "ok",
|
|
164874
164906
|
mode,
|
|
164875
|
-
readOnly:
|
|
164907
|
+
readOnly: true,
|
|
164876
164908
|
scope,
|
|
164877
164909
|
agents: withTier,
|
|
164878
164910
|
activeCount,
|
|
@@ -164893,28 +164925,8 @@ async function buildTeamSnapshot(dataDir, projectId, scope, mode) {
|
|
|
164893
164925
|
activeSessions: activeCount
|
|
164894
164926
|
};
|
|
164895
164927
|
} catch {
|
|
164896
|
-
|
|
164897
|
-
|
|
164898
|
-
readOnly: mode === "standalone",
|
|
164899
|
-
scope,
|
|
164900
|
-
agents: [],
|
|
164901
|
-
activeCount: 0,
|
|
164902
|
-
recentCount: 0,
|
|
164903
|
-
historicalCount: 0,
|
|
164904
|
-
totalAgents: 0,
|
|
164905
|
-
recentWindowDays: 7,
|
|
164906
|
-
locks: [],
|
|
164907
|
-
tasks: [],
|
|
164908
|
-
availableTasks: 0,
|
|
164909
|
-
sessions: 0,
|
|
164910
|
-
roles: [],
|
|
164911
|
-
roleOccupancy: [],
|
|
164912
|
-
handoffs: [],
|
|
164913
|
-
openTasks: 0,
|
|
164914
|
-
openHandoffs: 0,
|
|
164915
|
-
totalUnread: 0,
|
|
164916
|
-
activeSessions: 0
|
|
164917
|
-
};
|
|
164928
|
+
logTeamSnapshotFailure(scope, "error");
|
|
164929
|
+
return emptyTeamSnapshot(mode, scope, "error");
|
|
164918
164930
|
}
|
|
164919
164931
|
}
|
|
164920
164932
|
function readBody(req) {
|
|
@@ -164933,13 +164945,12 @@ function readBody(req) {
|
|
|
164933
164945
|
req.on("error", reject);
|
|
164934
164946
|
});
|
|
164935
164947
|
}
|
|
164936
|
-
async function startDashboard(dataDir, port, staticDir, projectId, projectName, autoOpen = true,
|
|
164948
|
+
async function startDashboard(dataDir, port, staticDir, projectId, projectName, autoOpen = true, projectRoot = null, projectResolved = true) {
|
|
164937
164949
|
await initObservationStore(dataDir);
|
|
164938
164950
|
await initSessionStore(dataDir);
|
|
164939
164951
|
const resolvedStaticDir = staticDir;
|
|
164940
164952
|
const baseDir = getBaseDataDir();
|
|
164941
|
-
const
|
|
164942
|
-
const state = { projectId, projectName, dataDir, projectRoot, projectResolved, mode: isControlPlane ? "control-plane" : "standalone", port };
|
|
164953
|
+
const state = { projectId, projectName, dataDir, projectRoot, projectResolved, mode: "standalone", port };
|
|
164943
164954
|
const server = createServer(async (req, res) => {
|
|
164944
164955
|
const url = req.url || "/";
|
|
164945
164956
|
if (url.startsWith("/api/set-current-project") && req.method === "POST") {
|
|
@@ -164961,54 +164972,20 @@ async function startDashboard(dataDir, port, staticDir, projectId, projectName,
|
|
|
164961
164972
|
}
|
|
164962
164973
|
return;
|
|
164963
164974
|
}
|
|
164964
|
-
|
|
164965
|
-
|
|
164966
|
-
|
|
164967
|
-
const scope = parsedUrl.searchParams.get("scope") || "project";
|
|
164968
|
-
sendJson(res, await buildTeamSnapshot(state.dataDir, state.projectId, scope, state.mode));
|
|
164969
|
-
return;
|
|
164970
|
-
}
|
|
164971
|
-
try {
|
|
164972
|
-
teamInstances.fileLocks.cleanExpired();
|
|
164973
|
-
const agents = teamInstances.registry.listAgents();
|
|
164974
|
-
const locks = teamInstances.fileLocks.listLocks();
|
|
164975
|
-
const tasks = teamInstances.taskManager.list();
|
|
164976
|
-
const available = teamInstances.taskManager.getAvailable();
|
|
164977
|
-
let roles = [];
|
|
164978
|
-
let roleOccupancy = [];
|
|
164979
|
-
let handoffs = [];
|
|
164980
|
-
try {
|
|
164981
|
-
const { getTeamStore: getTeamStore2, isTeamStoreInitialized: isTeamStoreInitialized2 } = await Promise.resolve().then(() => (init_team_store(), team_store_exports));
|
|
164982
|
-
if (isTeamStoreInitialized2()) {
|
|
164983
|
-
const teamStore = getTeamStore2();
|
|
164984
|
-
const projectId2 = state.projectId;
|
|
164985
|
-
roles = teamStore.listRoles(projectId2);
|
|
164986
|
-
roleOccupancy = teamStore.getRoleOccupancy(projectId2);
|
|
164987
|
-
handoffs = teamStore.listHandoffs(projectId2);
|
|
164988
|
-
}
|
|
164989
|
-
} catch {
|
|
164990
|
-
}
|
|
164975
|
+
const parsedUrl = new URL(url, `http://127.0.0.1:${port}`);
|
|
164976
|
+
if (parsedUrl.pathname === "/api/team") {
|
|
164977
|
+
if (req.method !== "GET") {
|
|
164991
164978
|
sendJson(res, {
|
|
164992
|
-
|
|
164993
|
-
|
|
164994
|
-
|
|
164995
|
-
|
|
164996
|
-
|
|
164997
|
-
|
|
164998
|
-
tasks,
|
|
164999
|
-
availableTasks: available.length,
|
|
165000
|
-
roles,
|
|
165001
|
-
roleOccupancy,
|
|
165002
|
-
handoffs,
|
|
165003
|
-
// Resume data for "Continue this project" area
|
|
165004
|
-
openTasks: tasks.filter((t2) => t2.status === "pending" || t2.status === "in_progress").length,
|
|
165005
|
-
openHandoffs: handoffs.filter((h2) => h2.handoff_status === "open" || h2.handoffStatus === "open").length,
|
|
165006
|
-
totalUnread: agents.reduce((sum, a) => sum + teamInstances.messageBus.getUnreadCount(a.id), 0),
|
|
165007
|
-
activeSessions: agents.filter((a) => a.status === "active").length
|
|
165008
|
-
});
|
|
165009
|
-
} catch {
|
|
165010
|
-
sendJson(res, { agents: [], activeCount: 0, locks: [], tasks: [], availableTasks: 0, roles: [], roleOccupancy: [], handoffs: [] });
|
|
164979
|
+
status: "error",
|
|
164980
|
+
readOnly: true,
|
|
164981
|
+
error: "Coordination status is read-only",
|
|
164982
|
+
errorCode: "COORDINATION_STATUS_READ_ONLY"
|
|
164983
|
+
}, 405);
|
|
164984
|
+
return;
|
|
165011
164985
|
}
|
|
164986
|
+
const scope = parsedUrl.searchParams.get("scope") || "project";
|
|
164987
|
+
const snapshot = await buildTeamSnapshot(state.dataDir, state.projectId, scope, state.mode);
|
|
164988
|
+
sendJson(res, snapshot, snapshot.status === "error" ? 503 : 200);
|
|
165012
164989
|
return;
|
|
165013
164990
|
}
|
|
165014
164991
|
if (url.startsWith("/api/")) {
|
|
@@ -165029,13 +165006,12 @@ async function startDashboard(dataDir, port, staticDir, projectId, projectName,
|
|
|
165029
165006
|
server.listen(port, "127.0.0.1", () => {
|
|
165030
165007
|
const url = `http://127.0.0.1:${port}`;
|
|
165031
165008
|
const resolvedLabel = projectResolved ? "resolved" : "unresolved";
|
|
165032
|
-
const modeLabel =
|
|
165009
|
+
const modeLabel = "Standalone";
|
|
165033
165010
|
console.error(` Memorix Dashboard [${modeLabel}]`);
|
|
165034
165011
|
console.error(` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
|
|
165035
165012
|
console.error(` Mode: ${modeLabel}`);
|
|
165036
165013
|
console.error(` Project: ${projectName} (${projectId}) [${resolvedLabel}]`);
|
|
165037
165014
|
console.error(` Local: ${url}`);
|
|
165038
|
-
if (isControlPlane) console.error(` MCP: ${url}/mcp`);
|
|
165039
165015
|
console.error(` Data dir: ${dataDir}`);
|
|
165040
165016
|
console.error(`
|
|
165041
165017
|
Press Ctrl+C to stop
|
|
@@ -168210,7 +168186,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
168210
168186
|
};
|
|
168211
168187
|
const server = existingServer ?? new McpServer({
|
|
168212
168188
|
name: "memorix",
|
|
168213
|
-
version: true ? "1.8.
|
|
168189
|
+
version: true ? "1.8.1" : "1.0.1"
|
|
168214
168190
|
});
|
|
168215
168191
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
168216
168192
|
server.registerTool = ((name, ...args) => {
|
|
@@ -171363,7 +171339,7 @@ ${json2}
|
|
|
171363
171339
|
}
|
|
171364
171340
|
}
|
|
171365
171341
|
console.error(`[memorix] Dashboard staticDir: ${staticDir}`);
|
|
171366
|
-
startDashboard2(projectDir2, portNum, staticDir, project.id, project.name, false,
|
|
171342
|
+
startDashboard2(projectDir2, portNum, staticDir, project.id, project.name, false, project.rootPath, projectResolved).then(() => {
|
|
171367
171343
|
dashboardRunning = true;
|
|
171368
171344
|
}).catch((err) => {
|
|
171369
171345
|
console.error("[memorix] Dashboard error:", err);
|
|
@@ -171705,7 +171681,7 @@ ${lines.join("\n")}` }] };
|
|
|
171705
171681
|
server.registerTool(
|
|
171706
171682
|
"team_task",
|
|
171707
171683
|
{
|
|
171708
|
-
title: "Task
|
|
171684
|
+
title: "Task Status",
|
|
171709
171685
|
description: 'Create, claim, complete, or list tasks in the team task board. Supports dependencies. Action "create": create a task. Action "claim": assign to yourself (atomic, race-safe). Action "complete": mark done with result. Action "list": show tasks.',
|
|
171710
171686
|
inputSchema: {
|
|
171711
171687
|
action: z626.enum(["create", "claim", "complete", "list"]).describe("Operation to perform"),
|
|
@@ -172759,7 +172735,7 @@ var init_serve_shared = __esm({
|
|
|
172759
172735
|
|
|
172760
172736
|
// src/cli/version.ts
|
|
172761
172737
|
function getCliVersion() {
|
|
172762
|
-
return true ? "1.8.
|
|
172738
|
+
return true ? "1.8.1" : pkg.version;
|
|
172763
172739
|
}
|
|
172764
172740
|
var init_version3 = __esm({
|
|
172765
172741
|
"src/cli/version.ts"() {
|
|
@@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.8.1] - 2026-08-24
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- **Truthful coordination status** -- the persistent SQLite `TeamStore` is the
|
|
11
|
+
sole coordination truth for agents, tasks, messages, locks, handoffs, and poll
|
|
12
|
+
state. The Dashboard exposes read-only `Coordination Status` and `Task Status`
|
|
13
|
+
views, and `/api/team` reports explicit `error` or `degraded` status instead of
|
|
14
|
+
presenting a failed coordination read as a healthy empty result.
|
|
15
|
+
|
|
7
16
|
## [1.8.0] - 2026-08-23
|
|
8
17
|
|
|
9
18
|
### Added
|
package/dist/sdk.js
CHANGED
|
@@ -160824,6 +160824,37 @@ function normalizeDashboardTask(task) {
|
|
|
160824
160824
|
preferredRole: task.preferred_role ?? task.preferredRole ?? null
|
|
160825
160825
|
};
|
|
160826
160826
|
}
|
|
160827
|
+
function emptyTeamSnapshot(mode, scope, status) {
|
|
160828
|
+
return {
|
|
160829
|
+
status,
|
|
160830
|
+
mode,
|
|
160831
|
+
readOnly: true,
|
|
160832
|
+
scope,
|
|
160833
|
+
agents: [],
|
|
160834
|
+
activeCount: 0,
|
|
160835
|
+
recentCount: 0,
|
|
160836
|
+
historicalCount: 0,
|
|
160837
|
+
totalAgents: 0,
|
|
160838
|
+
recentWindowDays: 7,
|
|
160839
|
+
locks: [],
|
|
160840
|
+
tasks: [],
|
|
160841
|
+
availableTasks: 0,
|
|
160842
|
+
sessions: 0,
|
|
160843
|
+
roles: [],
|
|
160844
|
+
roleOccupancy: [],
|
|
160845
|
+
handoffs: [],
|
|
160846
|
+
openTasks: 0,
|
|
160847
|
+
openHandoffs: 0,
|
|
160848
|
+
totalUnread: 0,
|
|
160849
|
+
activeSessions: 0,
|
|
160850
|
+
error: status === "error" ? "Coordination state unavailable" : "Coordination state is incomplete",
|
|
160851
|
+
errorCode: status === "error" ? "COORDINATION_STATE_UNAVAILABLE" : "COORDINATION_STATE_DEGRADED"
|
|
160852
|
+
};
|
|
160853
|
+
}
|
|
160854
|
+
function logTeamSnapshotFailure(scope, status) {
|
|
160855
|
+
const safeScope = scope === "global" ? "global" : "project";
|
|
160856
|
+
console.error("[dashboard] coordination snapshot unavailable", { status, scope: safeScope });
|
|
160857
|
+
}
|
|
160827
160858
|
async function buildTeamSnapshot(dataDir, projectId, scope, mode) {
|
|
160828
160859
|
try {
|
|
160829
160860
|
const { initTeamStore: initTeamStore2 } = await Promise.resolve().then(() => (init_team_store(), team_store_exports));
|
|
@@ -160850,8 +160881,9 @@ async function buildTeamSnapshot(dataDir, projectId, scope, mode) {
|
|
|
160850
160881
|
const roleOccupancy = effectiveProjectId ? teamStore.getRoleOccupancy(effectiveProjectId) : [];
|
|
160851
160882
|
const handoffs = effectiveProjectId ? teamStore.listHandoffs(effectiveProjectId) : [];
|
|
160852
160883
|
return {
|
|
160884
|
+
status: "ok",
|
|
160853
160885
|
mode,
|
|
160854
|
-
readOnly:
|
|
160886
|
+
readOnly: true,
|
|
160855
160887
|
scope,
|
|
160856
160888
|
agents: withTier,
|
|
160857
160889
|
activeCount,
|
|
@@ -160872,28 +160904,8 @@ async function buildTeamSnapshot(dataDir, projectId, scope, mode) {
|
|
|
160872
160904
|
activeSessions: activeCount
|
|
160873
160905
|
};
|
|
160874
160906
|
} catch {
|
|
160875
|
-
|
|
160876
|
-
|
|
160877
|
-
readOnly: mode === "standalone",
|
|
160878
|
-
scope,
|
|
160879
|
-
agents: [],
|
|
160880
|
-
activeCount: 0,
|
|
160881
|
-
recentCount: 0,
|
|
160882
|
-
historicalCount: 0,
|
|
160883
|
-
totalAgents: 0,
|
|
160884
|
-
recentWindowDays: 7,
|
|
160885
|
-
locks: [],
|
|
160886
|
-
tasks: [],
|
|
160887
|
-
availableTasks: 0,
|
|
160888
|
-
sessions: 0,
|
|
160889
|
-
roles: [],
|
|
160890
|
-
roleOccupancy: [],
|
|
160891
|
-
handoffs: [],
|
|
160892
|
-
openTasks: 0,
|
|
160893
|
-
openHandoffs: 0,
|
|
160894
|
-
totalUnread: 0,
|
|
160895
|
-
activeSessions: 0
|
|
160896
|
-
};
|
|
160907
|
+
logTeamSnapshotFailure(scope, "error");
|
|
160908
|
+
return emptyTeamSnapshot(mode, scope, "error");
|
|
160897
160909
|
}
|
|
160898
160910
|
}
|
|
160899
160911
|
function readBody(req) {
|
|
@@ -160912,13 +160924,12 @@ function readBody(req) {
|
|
|
160912
160924
|
req.on("error", reject);
|
|
160913
160925
|
});
|
|
160914
160926
|
}
|
|
160915
|
-
async function startDashboard(dataDir, port, staticDir, projectId, projectName, autoOpen = true,
|
|
160927
|
+
async function startDashboard(dataDir, port, staticDir, projectId, projectName, autoOpen = true, projectRoot = null, projectResolved = true) {
|
|
160916
160928
|
await initObservationStore(dataDir);
|
|
160917
160929
|
await initSessionStore(dataDir);
|
|
160918
160930
|
const resolvedStaticDir = staticDir;
|
|
160919
160931
|
const baseDir = getBaseDataDir();
|
|
160920
|
-
const
|
|
160921
|
-
const state = { projectId, projectName, dataDir, projectRoot, projectResolved, mode: isControlPlane ? "control-plane" : "standalone", port };
|
|
160932
|
+
const state = { projectId, projectName, dataDir, projectRoot, projectResolved, mode: "standalone", port };
|
|
160922
160933
|
const server = createServer(async (req, res) => {
|
|
160923
160934
|
const url = req.url || "/";
|
|
160924
160935
|
if (url.startsWith("/api/set-current-project") && req.method === "POST") {
|
|
@@ -160940,54 +160951,20 @@ async function startDashboard(dataDir, port, staticDir, projectId, projectName,
|
|
|
160940
160951
|
}
|
|
160941
160952
|
return;
|
|
160942
160953
|
}
|
|
160943
|
-
|
|
160944
|
-
|
|
160945
|
-
|
|
160946
|
-
const scope = parsedUrl.searchParams.get("scope") || "project";
|
|
160947
|
-
sendJson(res, await buildTeamSnapshot(state.dataDir, state.projectId, scope, state.mode));
|
|
160948
|
-
return;
|
|
160949
|
-
}
|
|
160950
|
-
try {
|
|
160951
|
-
teamInstances.fileLocks.cleanExpired();
|
|
160952
|
-
const agents = teamInstances.registry.listAgents();
|
|
160953
|
-
const locks = teamInstances.fileLocks.listLocks();
|
|
160954
|
-
const tasks = teamInstances.taskManager.list();
|
|
160955
|
-
const available = teamInstances.taskManager.getAvailable();
|
|
160956
|
-
let roles = [];
|
|
160957
|
-
let roleOccupancy = [];
|
|
160958
|
-
let handoffs = [];
|
|
160959
|
-
try {
|
|
160960
|
-
const { getTeamStore: getTeamStore2, isTeamStoreInitialized: isTeamStoreInitialized2 } = await Promise.resolve().then(() => (init_team_store(), team_store_exports));
|
|
160961
|
-
if (isTeamStoreInitialized2()) {
|
|
160962
|
-
const teamStore = getTeamStore2();
|
|
160963
|
-
const projectId2 = state.projectId;
|
|
160964
|
-
roles = teamStore.listRoles(projectId2);
|
|
160965
|
-
roleOccupancy = teamStore.getRoleOccupancy(projectId2);
|
|
160966
|
-
handoffs = teamStore.listHandoffs(projectId2);
|
|
160967
|
-
}
|
|
160968
|
-
} catch {
|
|
160969
|
-
}
|
|
160954
|
+
const parsedUrl = new URL(url, `http://127.0.0.1:${port}`);
|
|
160955
|
+
if (parsedUrl.pathname === "/api/team") {
|
|
160956
|
+
if (req.method !== "GET") {
|
|
160970
160957
|
sendJson(res, {
|
|
160971
|
-
|
|
160972
|
-
|
|
160973
|
-
|
|
160974
|
-
|
|
160975
|
-
|
|
160976
|
-
|
|
160977
|
-
tasks,
|
|
160978
|
-
availableTasks: available.length,
|
|
160979
|
-
roles,
|
|
160980
|
-
roleOccupancy,
|
|
160981
|
-
handoffs,
|
|
160982
|
-
// Resume data for "Continue this project" area
|
|
160983
|
-
openTasks: tasks.filter((t2) => t2.status === "pending" || t2.status === "in_progress").length,
|
|
160984
|
-
openHandoffs: handoffs.filter((h2) => h2.handoff_status === "open" || h2.handoffStatus === "open").length,
|
|
160985
|
-
totalUnread: agents.reduce((sum, a) => sum + teamInstances.messageBus.getUnreadCount(a.id), 0),
|
|
160986
|
-
activeSessions: agents.filter((a) => a.status === "active").length
|
|
160987
|
-
});
|
|
160988
|
-
} catch {
|
|
160989
|
-
sendJson(res, { agents: [], activeCount: 0, locks: [], tasks: [], availableTasks: 0, roles: [], roleOccupancy: [], handoffs: [] });
|
|
160958
|
+
status: "error",
|
|
160959
|
+
readOnly: true,
|
|
160960
|
+
error: "Coordination status is read-only",
|
|
160961
|
+
errorCode: "COORDINATION_STATUS_READ_ONLY"
|
|
160962
|
+
}, 405);
|
|
160963
|
+
return;
|
|
160990
160964
|
}
|
|
160965
|
+
const scope = parsedUrl.searchParams.get("scope") || "project";
|
|
160966
|
+
const snapshot = await buildTeamSnapshot(state.dataDir, state.projectId, scope, state.mode);
|
|
160967
|
+
sendJson(res, snapshot, snapshot.status === "error" ? 503 : 200);
|
|
160991
160968
|
return;
|
|
160992
160969
|
}
|
|
160993
160970
|
if (url.startsWith("/api/")) {
|
|
@@ -161008,13 +160985,12 @@ async function startDashboard(dataDir, port, staticDir, projectId, projectName,
|
|
|
161008
160985
|
server.listen(port, "127.0.0.1", () => {
|
|
161009
160986
|
const url = `http://127.0.0.1:${port}`;
|
|
161010
160987
|
const resolvedLabel = projectResolved ? "resolved" : "unresolved";
|
|
161011
|
-
const modeLabel =
|
|
160988
|
+
const modeLabel = "Standalone";
|
|
161012
160989
|
console.error(` Memorix Dashboard [${modeLabel}]`);
|
|
161013
160990
|
console.error(` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
|
|
161014
160991
|
console.error(` Mode: ${modeLabel}`);
|
|
161015
160992
|
console.error(` Project: ${projectName} (${projectId}) [${resolvedLabel}]`);
|
|
161016
160993
|
console.error(` Local: ${url}`);
|
|
161017
|
-
if (isControlPlane) console.error(` MCP: ${url}/mcp`);
|
|
161018
160994
|
console.error(` Data dir: ${dataDir}`);
|
|
161019
160995
|
console.error(`
|
|
161020
160996
|
Press Ctrl+C to stop
|
|
@@ -168007,7 +167983,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
168007
167983
|
};
|
|
168008
167984
|
const server = existingServer ?? new McpServer({
|
|
168009
167985
|
name: "memorix",
|
|
168010
|
-
version: true ? "1.8.
|
|
167986
|
+
version: true ? "1.8.1" : "1.0.1"
|
|
168011
167987
|
});
|
|
168012
167988
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
168013
167989
|
server.registerTool = ((name, ...args) => {
|
|
@@ -171160,7 +171136,7 @@ ${json2}
|
|
|
171160
171136
|
}
|
|
171161
171137
|
}
|
|
171162
171138
|
console.error(`[memorix] Dashboard staticDir: ${staticDir}`);
|
|
171163
|
-
startDashboard2(projectDir2, portNum, staticDir, project.id, project.name, false,
|
|
171139
|
+
startDashboard2(projectDir2, portNum, staticDir, project.id, project.name, false, project.rootPath, projectResolved).then(() => {
|
|
171164
171140
|
dashboardRunning = true;
|
|
171165
171141
|
}).catch((err) => {
|
|
171166
171142
|
console.error("[memorix] Dashboard error:", err);
|
|
@@ -171502,7 +171478,7 @@ ${lines.join("\n")}` }] };
|
|
|
171502
171478
|
server.registerTool(
|
|
171503
171479
|
"team_task",
|
|
171504
171480
|
{
|
|
171505
|
-
title: "Task
|
|
171481
|
+
title: "Task Status",
|
|
171506
171482
|
description: 'Create, claim, complete, or list tasks in the team task board. Supports dependencies. Action "create": create a task. Action "claim": assign to yourself (atomic, race-safe). Action "complete": mark done with result. Action "list": show tasks.',
|
|
171507
171483
|
inputSchema: {
|
|
171508
171484
|
action: z626.enum(["create", "claim", "complete", "list"]).describe("Operation to perform"),
|
package/docs/API_REFERENCE.md
CHANGED
|
@@ -864,6 +864,8 @@ Important inputs:
|
|
|
864
864
|
|
|
865
865
|
When using HTTP mode, the main dashboard is usually served from the same port as `serve-http`.
|
|
866
866
|
|
|
867
|
+
The Dashboard's Coordination Status page is read-only. It reads the selected project's agents, tasks, locks, handoffs, messages, and poll state from the persistent SQLite `TeamStore`; it does not expose team/task write endpoints or replace task execution and orchestration tools. A coordination read failure is returned as an explicit degraded/error response rather than an empty healthy snapshot.
|
|
868
|
+
|
|
867
869
|
---
|
|
868
870
|
|
|
869
871
|
## 12. Optional Graph Compatibility Tools
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -498,7 +498,9 @@ It provides an operational view for:
|
|
|
498
498
|
- sessions
|
|
499
499
|
- retention state
|
|
500
500
|
- preview-first cleanup, consolidation, intelligent deduplication, and retention archival
|
|
501
|
-
- read-only
|
|
501
|
+
- read-only Coordination Status derived from the project-scoped SQLite `TeamStore`; the page is a projection, not a task execution surface
|
|
502
|
+
|
|
503
|
+
`TeamStore` is the real persistent coordination layer for agents, tasks, messages, locks, handoffs, and poll state. Dashboard coordination reads use that same SQLite state and return an explicit degraded/error status when it cannot be read; they must not substitute a normal-looking empty snapshot.
|
|
502
504
|
|
|
503
505
|
Dashboard maintenance is not a separate business-logic implementation. CLI, MCP, background jobs, and Dashboard routes share the same cleanup, consolidation, deduplication, and retention functions. Mutation routes issue a project-bound signed preview token and reject execution when the candidate set changed after preview.
|
|
504
506
|
|
package/docs/DASHBOARD.md
CHANGED
|
@@ -19,6 +19,12 @@ memorix dashboard
|
|
|
19
19
|
|
|
20
20
|
Both modes read the same project-scoped stores. The project switcher changes the active project filter; it does not merge projects or grant access to personal memories.
|
|
21
21
|
|
|
22
|
+
## Coordination Status
|
|
23
|
+
|
|
24
|
+
The Coordination Status page is a read-only projection of the selected project's persistent coordination state. `TeamStore` is the canonical SQLite layer for agents, tasks, messages, locks, handoffs, and poll state; the Dashboard does not keep a second in-memory coordination registry.
|
|
25
|
+
|
|
26
|
+
The page reports agents, task status, file locks, and handoffs for the selected project. It exposes no team or task write endpoints and is not a task execution or full orchestration platform. If the SQLite read fails, the API returns an explicit degraded/error status and the page shows that the status is unavailable instead of presenting an empty result as healthy.
|
|
27
|
+
|
|
22
28
|
## Maintenance Workbench
|
|
23
29
|
|
|
24
30
|
The Observations page exposes three explicit maintenance actions:
|
package/docs/DEVELOPMENT.md
CHANGED
|
@@ -13,8 +13,8 @@ Memorix is a TypeScript project built around:
|
|
|
13
13
|
|
|
14
14
|
## Current Development Baseline
|
|
15
15
|
|
|
16
|
-
The current release work targets the **1.8.
|
|
17
|
-
is kept at `1.8.
|
|
16
|
+
The current release work targets the **1.8.1 release line** and package metadata
|
|
17
|
+
is kept at `1.8.1` for this release commit.
|
|
18
18
|
|
|
19
19
|
Contributors should assume the following areas are part of the current release line:
|
|
20
20
|
|
package/docs/README.md
CHANGED
|
@@ -33,7 +33,7 @@ The public docs are organized by user intent:
|
|
|
33
33
|
| CLI commands and MCP tools | [API_REFERENCE.md](API_REFERENCE.md) |
|
|
34
34
|
| Memory Autopilot, Code State, and context packs | [API_REFERENCE.md § Memory Autopilot, Code State, and Context Packs](API_REFERENCE.md#memory-autopilot-code-state-and-context-packs), [1.2 Code State](1.2.0-CODE-STATE.md), and [1.2 Workset Retrieval](1.2.0-WORKSET-RETRIEVAL.md) |
|
|
35
35
|
| Reviewed episodic, semantic, and procedural long-term memory | [1.3 Memory Architecture](1.3-MEMORY-ARCHITECTURE.md) |
|
|
36
|
-
| Browse memory and
|
|
36
|
+
| Browse memory, maintenance, and read-only Coordination Status | [Dashboard](DASHBOARD.md) |
|
|
37
37
|
| Reviewable knowledge pages and workflow inheritance | [API_REFERENCE.md § Knowledge Workspace and Workflows](API_REFERENCE.md#knowledge-workspace-and-workflows), [1.2 Knowledge Workspace](1.2.0-KNOWLEDGE-WORKSPACE.md), and [1.2 Workflow Inheritance](1.2.0-WORKFLOW-INHERITANCE.md) |
|
|
38
38
|
| Git-derived engineering memory | [GIT_MEMORY.md](GIT_MEMORY.md) |
|
|
39
39
|
| Memory formation and quality pipeline | [MEMORY_FORMATION_PIPELINE.md](MEMORY_FORMATION_PIPELINE.md) |
|
|
@@ -121,7 +121,7 @@ Historical/deep-reference documents may describe older designs. If they conflict
|
|
|
121
121
|
|
|
122
122
|
## Current Product Line
|
|
123
123
|
|
|
124
|
-
The current product line is **1.8.
|
|
124
|
+
The current product line is **1.8.1**. The authoritative acceptance contract is
|
|
125
125
|
[1.8.0 Release Specification](1.8.0-RELEASE-CANDIDATE-SPEC.md).
|
|
126
126
|
The current baseline has:
|
|
127
127
|
|
|
@@ -130,6 +130,9 @@ The current baseline has:
|
|
|
130
130
|
- `memorix background start` runs the shared HTTP MCP service and dashboard
|
|
131
131
|
- Dashboard maintenance is preview-first, project-scoped, and uses the same
|
|
132
132
|
cleanup and deduplication planners as CLI and MCP
|
|
133
|
+
- Dashboard Coordination Status is read-only and projects the persistent SQLite
|
|
134
|
+
`TeamStore` truth; its task section is `Task Status` and failed reads are
|
|
135
|
+
explicit `error`/`degraded` states
|
|
133
136
|
- context and CodeGraph commands return bounded task receipts before detailed diagnostics
|
|
134
137
|
- HTTP MCP sessions have a bounded, explicit lifecycle and fail with a reinitialize hint after expiry
|
|
135
138
|
- `memorix integrate --agent <agent>` and `memorix hooks install --agent <agent>` remain manual/fallback generation commands
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memorix",
|
|
3
3
|
"mcpName": "io.github.AVIDS2/memorix",
|
|
4
|
-
"version": "1.8.
|
|
4
|
+
"version": "1.8.1",
|
|
5
5
|
"description": "Local-first shared memory layer for AI coding agents across MCP clients, Git history, reasoning context, and project sessions.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"sideEffects": false,
|
package/server.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"url": "https://github.com/AVIDS2/memorix",
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
|
-
"version": "1.8.
|
|
10
|
+
"version": "1.8.1",
|
|
11
11
|
"websiteUrl": "https://github.com/AVIDS2/memorix#readme",
|
|
12
12
|
"icons": [
|
|
13
13
|
{
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
{
|
|
23
23
|
"registryType": "npm",
|
|
24
24
|
"identifier": "memorix",
|
|
25
|
-
"version": "1.8.
|
|
25
|
+
"version": "1.8.1",
|
|
26
26
|
"runtimeHint": "npx",
|
|
27
27
|
"packageArguments": [
|
|
28
28
|
{
|
|
@@ -59,7 +59,7 @@ export default defineCommand({
|
|
|
59
59
|
const cliDir = path.dirname(fileURLToPath(import.meta.url));
|
|
60
60
|
const staticDir = path.join(cliDir, '..', 'dashboard', 'static');
|
|
61
61
|
|
|
62
|
-
await startDashboard(dataDir, port, staticDir, project.id, project.name, true,
|
|
62
|
+
await startDashboard(dataDir, port, staticDir, project.id, project.name, true, project.rootPath, true);
|
|
63
63
|
|
|
64
64
|
// Keep alive
|
|
65
65
|
await new Promise(() => { });
|