memorix 1.2.0 → 1.2.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 +14 -1
- package/README.md +4 -2
- package/README.zh-CN.md +4 -2
- package/dist/cli/index.js +677 -441
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +830 -646
- package/dist/index.js.map +1 -1
- package/dist/maintenance-runner.js +110 -5
- package/dist/maintenance-runner.js.map +1 -1
- package/dist/memcode-runtime/CHANGELOG.md +14 -1
- package/dist/sdk.js +830 -646
- package/dist/sdk.js.map +1 -1
- package/docs/API_REFERENCE.md +3 -1
- package/docs/DEVELOPMENT.md +4 -0
- package/docs/SETUP.md +7 -1
- package/docs/knowledge/workflows/memorix-release.md +57 -0
- package/package.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/src/cli/commands/codegraph.ts +2 -3
- package/src/cli/commands/knowledge.ts +40 -0
- package/src/cli/commands/serve-http.ts +14 -41
- package/src/cli/commands/setup.ts +9 -3
- package/src/codegraph/auto-context.ts +3 -15
- package/src/codegraph/current-facts.ts +19 -1
- package/src/codegraph/task-lens.ts +49 -5
- package/src/dashboard/server.ts +15 -46
- package/src/knowledge/claims.ts +51 -1
- package/src/knowledge/types.ts +1 -0
- package/src/knowledge/workflows.ts +34 -3
- package/src/memory/auto-relations.ts +21 -0
- package/src/memory/graph-scope.ts +46 -0
- package/src/orchestrate/verify-gate.ts +33 -10
- package/src/server.ts +75 -13
|
@@ -5837,6 +5837,7 @@ __export(claims_exports, {
|
|
|
5837
5837
|
buildClaimIdentity: () => buildClaimIdentity,
|
|
5838
5838
|
deriveLowRiskClaimsFromObservation: () => deriveLowRiskClaimsFromObservation,
|
|
5839
5839
|
requalifyClaimsForCodeState: () => requalifyClaimsForCodeState,
|
|
5840
|
+
reviewClaim: () => reviewClaim,
|
|
5840
5841
|
selectClaimsForTask: () => selectClaimsForTask,
|
|
5841
5842
|
supersedeClaim: () => supersedeClaim,
|
|
5842
5843
|
writeClaim: () => writeClaim
|
|
@@ -6023,6 +6024,39 @@ function writeClaim(store, input) {
|
|
|
6023
6024
|
};
|
|
6024
6025
|
});
|
|
6025
6026
|
}
|
|
6027
|
+
function reviewClaim(store, input) {
|
|
6028
|
+
if (input.reviewState !== "approved" && input.reviewState !== "rejected") {
|
|
6029
|
+
throw new Error("A claim review must approve or reject the claim");
|
|
6030
|
+
}
|
|
6031
|
+
const detail = compactText(input.detail, "review detail");
|
|
6032
|
+
return store.transaction(() => {
|
|
6033
|
+
const claim = store.getClaim(input.claimId);
|
|
6034
|
+
if (!claim) throw new Error("Claim was not found");
|
|
6035
|
+
if (input.reviewState === "approved" && claim.status === "superseded") {
|
|
6036
|
+
throw new Error("A superseded claim cannot be approved");
|
|
6037
|
+
}
|
|
6038
|
+
const now3 = (/* @__PURE__ */ new Date()).toISOString();
|
|
6039
|
+
const nextStatus = input.reviewState === "rejected" ? "unknown" : claim.status === "unknown" && claim.reviewState === "rejected" ? "active" : claim.status;
|
|
6040
|
+
const updated = {
|
|
6041
|
+
...claim,
|
|
6042
|
+
status: nextStatus,
|
|
6043
|
+
reviewState: input.reviewState,
|
|
6044
|
+
updatedAt: now3
|
|
6045
|
+
};
|
|
6046
|
+
store.updateClaim(updated);
|
|
6047
|
+
store.recordEvent({
|
|
6048
|
+
projectId: claim.projectId,
|
|
6049
|
+
claimId: claim.id,
|
|
6050
|
+
kind: "reviewed",
|
|
6051
|
+
fromStatus: claim.status,
|
|
6052
|
+
toStatus: updated.status,
|
|
6053
|
+
detail: "Review: " + claim.reviewState + " -> " + input.reviewState + ". " + detail,
|
|
6054
|
+
createdAt: now3
|
|
6055
|
+
});
|
|
6056
|
+
reconcileConflicts(store, claim.projectId, claim.conflictKey, now3);
|
|
6057
|
+
return store.getClaim(claim.id) ?? updated;
|
|
6058
|
+
});
|
|
6059
|
+
}
|
|
6026
6060
|
function supersedeClaim(store, input) {
|
|
6027
6061
|
const evidence = validateEvidence(input.evidence);
|
|
6028
6062
|
return store.transaction(() => {
|
|
@@ -6111,7 +6145,7 @@ function deriveLowRiskClaimsFromObservation(store, observation, codeStore) {
|
|
|
6111
6145
|
scope: "project",
|
|
6112
6146
|
confidence,
|
|
6113
6147
|
observedAt: observation.updatedAt ?? observation.createdAt,
|
|
6114
|
-
reviewState: "approved",
|
|
6148
|
+
reviewState: isGit ? "approved" : "needs-review",
|
|
6115
6149
|
origin: isGit ? "git" : "derived",
|
|
6116
6150
|
evidence
|
|
6117
6151
|
});
|
|
@@ -7091,6 +7125,48 @@ var init_workflow_store = __esm({
|
|
|
7091
7125
|
}
|
|
7092
7126
|
});
|
|
7093
7127
|
|
|
7128
|
+
// src/codegraph/task-lens.ts
|
|
7129
|
+
function containsTaskKeyword(text, keyword) {
|
|
7130
|
+
const matcher = /^[a-z0-9_-]+$/i.test(keyword) ? new RegExp(`(^|[^a-z0-9_-])${keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?=[^a-z0-9_-]|$)`, "gi") : new RegExp(keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "gi");
|
|
7131
|
+
let match;
|
|
7132
|
+
while ((match = matcher.exec(text)) !== null) {
|
|
7133
|
+
const keywordIndex = match.index + (match[1]?.length ?? 0);
|
|
7134
|
+
if (!isNegatedTaskKeyword(text, keywordIndex)) return true;
|
|
7135
|
+
}
|
|
7136
|
+
return false;
|
|
7137
|
+
}
|
|
7138
|
+
function isNegatedTaskKeyword(text, keywordIndex) {
|
|
7139
|
+
const boundary = Math.max(
|
|
7140
|
+
text.lastIndexOf(".", keywordIndex - 1),
|
|
7141
|
+
text.lastIndexOf("!", keywordIndex - 1),
|
|
7142
|
+
text.lastIndexOf("?", keywordIndex - 1),
|
|
7143
|
+
text.lastIndexOf(";", keywordIndex - 1),
|
|
7144
|
+
text.lastIndexOf("\n", keywordIndex - 1),
|
|
7145
|
+
text.lastIndexOf("\u3002", keywordIndex - 1),
|
|
7146
|
+
text.lastIndexOf("\uFF01", keywordIndex - 1),
|
|
7147
|
+
text.lastIndexOf("\uFF1F", keywordIndex - 1),
|
|
7148
|
+
text.lastIndexOf("\uFF1B", keywordIndex - 1)
|
|
7149
|
+
);
|
|
7150
|
+
let prefix = text.slice(boundary + 1, keywordIndex).toLowerCase();
|
|
7151
|
+
const contrast = /(?:,|\uff0c)\s*(?:but|however|instead|yet|\u4f46\u662f|\u4f46|\u800c\u662f)\s*/gi;
|
|
7152
|
+
let contrastMatch;
|
|
7153
|
+
let contrastEnd = -1;
|
|
7154
|
+
while ((contrastMatch = contrast.exec(prefix)) !== null) contrastEnd = contrast.lastIndex;
|
|
7155
|
+
if (contrastEnd >= 0) prefix = prefix.slice(contrastEnd);
|
|
7156
|
+
if (/\b(?:do|does|did|should|must|can|could|will|would|may|might)\s+not\b/.test(prefix)) return true;
|
|
7157
|
+
if (/\b(?:don't|dont|never|without|avoid|skip)\b/.test(prefix)) return true;
|
|
7158
|
+
if (/(?:^|[\s,])no\s+(?:[a-z0-9_-]+\s*){0,4}$/i.test(prefix)) return true;
|
|
7159
|
+
const chineseClauseStart = Math.max(prefix.lastIndexOf(","), prefix.lastIndexOf("\uFF0C"), prefix.lastIndexOf("\u3001"));
|
|
7160
|
+
const chineseClause = prefix.slice(chineseClauseStart + 1);
|
|
7161
|
+
return /(?:\u4e0d\u8981|\u4e0d\u5e94|\u4e0d\u53ef|\u4e0d\u80fd|\u4e0d\u4f1a|\u7981\u6b62|\u52ff|\u4e0d)\s*(?:\u7acb\u5373|\u76f4\u63a5|\u518d|\u73b0\u5728|\u64c5\u81ea|\u5148)?\s*$/.test(chineseClause);
|
|
7162
|
+
}
|
|
7163
|
+
var init_task_lens = __esm({
|
|
7164
|
+
"src/codegraph/task-lens.ts"() {
|
|
7165
|
+
"use strict";
|
|
7166
|
+
init_esm_shims();
|
|
7167
|
+
}
|
|
7168
|
+
});
|
|
7169
|
+
|
|
7094
7170
|
// src/knowledge/workflows.ts
|
|
7095
7171
|
var workflows_exports = {};
|
|
7096
7172
|
__export(workflows_exports, {
|
|
@@ -7413,20 +7489,27 @@ function taskScore(workflow, task) {
|
|
|
7413
7489
|
const text = task.toLowerCase();
|
|
7414
7490
|
let score = 0;
|
|
7415
7491
|
const reasons = [];
|
|
7492
|
+
const matchedLenses = /* @__PURE__ */ new Set();
|
|
7493
|
+
const matchedTriggers = /* @__PURE__ */ new Set();
|
|
7416
7494
|
for (const lens of workflow.taskLenses) {
|
|
7417
7495
|
const terms = LENS_TERMS[lens.toLowerCase()] ?? [lens.toLowerCase()];
|
|
7418
|
-
if (terms.some((term) =>
|
|
7496
|
+
if (terms.some((term) => containsTaskKeyword(task, term))) {
|
|
7419
7497
|
score += 20;
|
|
7420
7498
|
reasons.push("matches " + lens + " workflow");
|
|
7499
|
+
matchedLenses.add(lens.toLowerCase());
|
|
7421
7500
|
}
|
|
7422
7501
|
}
|
|
7423
7502
|
for (const trigger of workflow.triggers) {
|
|
7424
7503
|
const term = trigger.toLowerCase().trim();
|
|
7425
|
-
if (term.length >= 2 &&
|
|
7504
|
+
if (term.length >= 2 && containsTaskKeyword(task, term)) {
|
|
7426
7505
|
score += 8;
|
|
7427
7506
|
reasons.push('matches trigger "' + trigger + '"');
|
|
7507
|
+
matchedTriggers.add(term);
|
|
7428
7508
|
}
|
|
7429
7509
|
}
|
|
7510
|
+
const hasSpecificLens = workflow.taskLenses.some((lens) => !GENERIC_WORKFLOW_LENSES.has(lens.toLowerCase()));
|
|
7511
|
+
const hasSpecificMatch = [...matchedLenses].some((lens) => !GENERIC_WORKFLOW_LENSES.has(lens)) || [...matchedTriggers].some((trigger) => !GENERIC_WORKFLOW_TERMS.has(trigger));
|
|
7512
|
+
if (hasSpecificLens && !hasSpecificMatch) return { score: 0, reasons: [] };
|
|
7430
7513
|
return { score, reasons: [...new Set(reasons)] };
|
|
7431
7514
|
}
|
|
7432
7515
|
function selectWorkflows(input) {
|
|
@@ -7444,9 +7527,28 @@ function selectWorkflows(input) {
|
|
|
7444
7527
|
return selected.slice(0, Math.max(1, Math.min(input.limit ?? 2, 2)));
|
|
7445
7528
|
}
|
|
7446
7529
|
function importedWorkflowSpec(input) {
|
|
7530
|
+
let sourceMatter;
|
|
7531
|
+
try {
|
|
7532
|
+
sourceMatter = matter3(input.raw);
|
|
7533
|
+
} catch (error) {
|
|
7534
|
+
throw new Error("Malformed Windsurf workflow Markdown: " + (error instanceof Error ? error.message : String(error)));
|
|
7535
|
+
}
|
|
7536
|
+
if (sourceMatter.data.id !== void 0) {
|
|
7537
|
+
const id = requiredText(sourceMatter.data, "id");
|
|
7538
|
+
const sourcePath2 = "workflows/" + slug(id) + ".md";
|
|
7539
|
+
const canonical = parsedWorkflow(sourceMatter.data, sourceMatter.content, {
|
|
7540
|
+
workspaceId: input.workspace.id,
|
|
7541
|
+
sourcePath: sourcePath2,
|
|
7542
|
+
contentHash: hash3(input.raw)
|
|
7543
|
+
});
|
|
7544
|
+
return materializeWorkflow({
|
|
7545
|
+
...canonical,
|
|
7546
|
+
importedFrom: input.sourcePath.replace(/\\/g, "/")
|
|
7547
|
+
});
|
|
7548
|
+
}
|
|
7447
7549
|
const entry = new WorkflowSyncer().parseWindsurfWorkflow(input.sourceName, input.raw);
|
|
7448
7550
|
const content = entry.content.trim() || "## Execute\n\nFollow the imported workflow.";
|
|
7449
|
-
const lenses = inferTaskLenses(entry.name + "\n" + entry.description
|
|
7551
|
+
const lenses = inferTaskLenses(entry.name + "\n" + entry.description);
|
|
7450
7552
|
const createdAt = now2();
|
|
7451
7553
|
const sourcePath = "workflows/" + slug(entry.name) + ".md";
|
|
7452
7554
|
const spec = {
|
|
@@ -7667,7 +7769,7 @@ async function selectWorkspaceWorkflows(input) {
|
|
|
7667
7769
|
errors: synced.errors
|
|
7668
7770
|
};
|
|
7669
7771
|
}
|
|
7670
|
-
var KNOWN_AGENTS, WORKFLOW_ADAPTER_TARGETS, STATUS_VALUES, LENS_TERMS;
|
|
7772
|
+
var KNOWN_AGENTS, WORKFLOW_ADAPTER_TARGETS, STATUS_VALUES, LENS_TERMS, GENERIC_WORKFLOW_LENSES, GENERIC_WORKFLOW_TERMS;
|
|
7671
7773
|
var init_workflows = __esm({
|
|
7672
7774
|
"src/knowledge/workflows.ts"() {
|
|
7673
7775
|
"use strict";
|
|
@@ -7676,6 +7778,7 @@ var init_workflows = __esm({
|
|
|
7676
7778
|
init_workflow_sync();
|
|
7677
7779
|
init_workspace();
|
|
7678
7780
|
init_workflow_store();
|
|
7781
|
+
init_task_lens();
|
|
7679
7782
|
KNOWN_AGENTS = [
|
|
7680
7783
|
"windsurf",
|
|
7681
7784
|
"cursor",
|
|
@@ -7707,6 +7810,8 @@ var init_workflows = __esm({
|
|
|
7707
7810
|
refactor: ["refactor", "cleanup", "restructure", "\u91CD\u6784", "\u6574\u7406"],
|
|
7708
7811
|
test: ["test", "verify", "smoke", "\u6D4B\u8BD5", "\u9A8C\u8BC1"]
|
|
7709
7812
|
};
|
|
7813
|
+
GENERIC_WORKFLOW_LENSES = /* @__PURE__ */ new Set(["review", "test"]);
|
|
7814
|
+
GENERIC_WORKFLOW_TERMS = /* @__PURE__ */ new Set(["review", "audit", "test", "verify", "smoke"]);
|
|
7710
7815
|
}
|
|
7711
7816
|
});
|
|
7712
7817
|
|