@massu/core 0.8.0 → 0.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/dist/cli.js +12 -16
- package/dist/hooks/post-tool-use.js +9 -4
- package/package.json +1 -1
- package/src/commands/init.ts +8 -15
- package/src/mcp-bridge-tools.ts +0 -1
- package/src/memory-file-ingest.ts +13 -6
package/dist/cli.js
CHANGED
|
@@ -1485,7 +1485,6 @@ var init_memory_db = __esm({
|
|
|
1485
1485
|
// src/memory-file-ingest.ts
|
|
1486
1486
|
import { readFileSync as readFileSync2, existsSync as existsSync3, readdirSync } from "fs";
|
|
1487
1487
|
import { join } from "path";
|
|
1488
|
-
import { parse as parseYaml2 } from "yaml";
|
|
1489
1488
|
function ingestMemoryFile(db, sessionId, filePath) {
|
|
1490
1489
|
if (!existsSync3(filePath)) return "skipped";
|
|
1491
1490
|
const content = readFileSync2(filePath, "utf-8");
|
|
@@ -1497,7 +1496,13 @@ function ingestMemoryFile(db, sessionId, filePath) {
|
|
|
1497
1496
|
let confidence;
|
|
1498
1497
|
if (frontmatterMatch) {
|
|
1499
1498
|
try {
|
|
1500
|
-
const fm =
|
|
1499
|
+
const fm = {};
|
|
1500
|
+
for (const line of frontmatterMatch[1].split("\n")) {
|
|
1501
|
+
const sep = line.indexOf(":");
|
|
1502
|
+
if (sep > 0) {
|
|
1503
|
+
fm[line.slice(0, sep).trim()] = line.slice(sep + 1).trim();
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1501
1506
|
name = fm.name ?? basename8;
|
|
1502
1507
|
description = fm.description ?? "";
|
|
1503
1508
|
type = fm.type ?? "discovery";
|
|
@@ -1924,19 +1929,11 @@ function registerMcpServer(projectRoot) {
|
|
|
1924
1929
|
return true;
|
|
1925
1930
|
}
|
|
1926
1931
|
function resolveHooksDir() {
|
|
1927
|
-
const cwd = process.cwd();
|
|
1928
|
-
const nodeModulesPath = resolve4(cwd, "node_modules/@massu/core/dist/hooks");
|
|
1929
|
-
if (existsSync5(nodeModulesPath)) {
|
|
1930
|
-
return "node_modules/@massu/core/dist/hooks";
|
|
1931
|
-
}
|
|
1932
|
-
const localPath = resolve4(__dirname2, "../dist/hooks");
|
|
1933
|
-
if (existsSync5(localPath)) {
|
|
1934
|
-
return localPath;
|
|
1935
|
-
}
|
|
1936
1932
|
return "node_modules/@massu/core/dist/hooks";
|
|
1937
1933
|
}
|
|
1938
1934
|
function hookCmd(hooksDir, hookFile) {
|
|
1939
|
-
|
|
1935
|
+
const hookPath = `${hooksDir}/${hookFile}`;
|
|
1936
|
+
return `d="$PWD"; while [ "$d" != "/" ] && [ ! -f "$d/${hookPath}" ]; do d="$(dirname "$d")"; done; cd "$d" && node ${hookPath}`;
|
|
1940
1937
|
}
|
|
1941
1938
|
function buildHooksConfig(hooksDir) {
|
|
1942
1939
|
return {
|
|
@@ -2475,7 +2472,7 @@ __export(doctor_exports, {
|
|
|
2475
2472
|
import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync4 } from "fs";
|
|
2476
2473
|
import { resolve as resolve5, dirname as dirname5 } from "path";
|
|
2477
2474
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2478
|
-
import { parse as
|
|
2475
|
+
import { parse as parseYaml2 } from "yaml";
|
|
2479
2476
|
function checkConfig(projectRoot) {
|
|
2480
2477
|
const configPath = resolve5(projectRoot, "massu.config.yaml");
|
|
2481
2478
|
if (!existsSync6(configPath)) {
|
|
@@ -2483,7 +2480,7 @@ function checkConfig(projectRoot) {
|
|
|
2483
2480
|
}
|
|
2484
2481
|
try {
|
|
2485
2482
|
const content = readFileSync5(configPath, "utf-8");
|
|
2486
|
-
const parsed =
|
|
2483
|
+
const parsed = parseYaml2(content);
|
|
2487
2484
|
if (!parsed || typeof parsed !== "object") {
|
|
2488
2485
|
return { name: "Configuration", status: "fail", detail: "massu.config.yaml is empty or invalid YAML" };
|
|
2489
2486
|
}
|
|
@@ -2801,7 +2798,7 @@ async function runValidateConfig() {
|
|
|
2801
2798
|
}
|
|
2802
2799
|
try {
|
|
2803
2800
|
const content = readFileSync5(configPath, "utf-8");
|
|
2804
|
-
const parsed =
|
|
2801
|
+
const parsed = parseYaml2(content);
|
|
2805
2802
|
if (!parsed || typeof parsed !== "object") {
|
|
2806
2803
|
console.error("Error: massu.config.yaml is empty or not a valid YAML object");
|
|
2807
2804
|
process.exit(1);
|
|
@@ -12241,7 +12238,6 @@ var init_mcp_bridge_tools = __esm({
|
|
|
12241
12238
|
});
|
|
12242
12239
|
process.on("SIGTERM", () => {
|
|
12243
12240
|
for (const [name] of connections) disconnectServer(name);
|
|
12244
|
-
process.exit(0);
|
|
12245
12241
|
});
|
|
12246
12242
|
ENV_ALLOW_LIST = /* @__PURE__ */ new Set([
|
|
12247
12243
|
"PATH",
|
|
@@ -1666,11 +1666,10 @@ function storeSecurityScore(db, sessionId, filePath, riskScore, findings) {
|
|
|
1666
1666
|
// src/hooks/post-tool-use.ts
|
|
1667
1667
|
import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
|
|
1668
1668
|
import { join as join2 } from "path";
|
|
1669
|
-
import { parse as
|
|
1669
|
+
import { parse as parseYaml2 } from "yaml";
|
|
1670
1670
|
|
|
1671
1671
|
// src/memory-file-ingest.ts
|
|
1672
1672
|
import { readFileSync as readFileSync5, existsSync as existsSync6, readdirSync } from "fs";
|
|
1673
|
-
import { parse as parseYaml2 } from "yaml";
|
|
1674
1673
|
function ingestMemoryFile(db, sessionId, filePath) {
|
|
1675
1674
|
if (!existsSync6(filePath)) return "skipped";
|
|
1676
1675
|
const content = readFileSync5(filePath, "utf-8");
|
|
@@ -1682,7 +1681,13 @@ function ingestMemoryFile(db, sessionId, filePath) {
|
|
|
1682
1681
|
let confidence;
|
|
1683
1682
|
if (frontmatterMatch) {
|
|
1684
1683
|
try {
|
|
1685
|
-
const fm =
|
|
1684
|
+
const fm = {};
|
|
1685
|
+
for (const line of frontmatterMatch[1].split("\n")) {
|
|
1686
|
+
const sep = line.indexOf(":");
|
|
1687
|
+
if (sep > 0) {
|
|
1688
|
+
fm[line.slice(0, sep).trim()] = line.slice(sep + 1).trim();
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1686
1691
|
name = fm.name ?? basename2;
|
|
1687
1692
|
description = fm.description ?? "";
|
|
1688
1693
|
type = fm.type ?? "discovery";
|
|
@@ -1897,7 +1902,7 @@ function readConventions(cwd) {
|
|
|
1897
1902
|
const configPath = join2(projectRoot, "massu.config.yaml");
|
|
1898
1903
|
if (!existsSync7(configPath)) return defaults;
|
|
1899
1904
|
const content = readFileSync6(configPath, "utf-8");
|
|
1900
|
-
const parsed =
|
|
1905
|
+
const parsed = parseYaml2(content);
|
|
1901
1906
|
if (!parsed || typeof parsed !== "object") return defaults;
|
|
1902
1907
|
const conventions = parsed.conventions;
|
|
1903
1908
|
if (!conventions || typeof conventions !== "object") return defaults;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@massu/core",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AI Engineering Governance MCP Server - Session memory, knowledge system, feature registry, code intelligence, rule enforcement, auto-learning pipeline, tiered tooling (12 free / 72 total), 55+ workflow commands, 15 agents, 20+ patterns",
|
|
6
6
|
"main": "src/server.ts",
|
package/src/commands/init.ts
CHANGED
|
@@ -346,25 +346,18 @@ type HooksConfig = Record<string, HookGroup[]>;
|
|
|
346
346
|
* Handles both local development and npm-installed scenarios.
|
|
347
347
|
*/
|
|
348
348
|
export function resolveHooksDir(): string {
|
|
349
|
-
//
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
if (existsSync(nodeModulesPath)) {
|
|
353
|
-
return 'node_modules/@massu/core/dist/hooks';
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// Fall back to finding relative to this source file
|
|
357
|
-
const localPath = resolve(__dirname, '../dist/hooks');
|
|
358
|
-
if (existsSync(localPath)) {
|
|
359
|
-
return localPath;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// Default to node_modules path (will be created on npm install)
|
|
349
|
+
// Always use node_modules/@massu/core/dist/hooks relative to project root.
|
|
350
|
+
// hookCmd() wraps each command with a parent-directory walk to find the
|
|
351
|
+
// project root, so hooks resolve correctly even from subdirectories.
|
|
363
352
|
return 'node_modules/@massu/core/dist/hooks';
|
|
364
353
|
}
|
|
365
354
|
|
|
366
355
|
function hookCmd(hooksDir: string, hookFile: string): string {
|
|
367
|
-
|
|
356
|
+
// Walk up from cwd to find the directory containing node_modules/@massu/core,
|
|
357
|
+
// then cd there before running the hook. This handles subdirectories like
|
|
358
|
+
// website/, packages/foo/, etc. where node_modules doesn't exist.
|
|
359
|
+
const hookPath = `${hooksDir}/${hookFile}`;
|
|
360
|
+
return `d="$PWD"; while [ "$d" != "/" ] && [ ! -f "$d/${hookPath}" ]; do d="$(dirname "$d")"; done; cd "$d" && node ${hookPath}`;
|
|
368
361
|
}
|
|
369
362
|
|
|
370
363
|
export function buildHooksConfig(hooksDir: string): HooksConfig {
|
package/src/mcp-bridge-tools.ts
CHANGED
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
import type Database from 'better-sqlite3';
|
|
12
12
|
import { readFileSync, existsSync, readdirSync } from 'fs';
|
|
13
13
|
import { join } from 'path';
|
|
14
|
-
import { parse as parseYaml } from 'yaml';
|
|
15
14
|
import { addObservation } from './memory-db.ts';
|
|
16
15
|
|
|
17
16
|
export type IngestResult = 'inserted' | 'updated' | 'skipped';
|
|
@@ -42,13 +41,21 @@ export function ingestMemoryFile(
|
|
|
42
41
|
|
|
43
42
|
if (frontmatterMatch) {
|
|
44
43
|
try {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
// Simple key: value parser for memory file frontmatter
|
|
45
|
+
// (avoids importing yaml library — frontmatter is flat key-value pairs)
|
|
46
|
+
const fm: Record<string, string> = {};
|
|
47
|
+
for (const line of frontmatterMatch[1].split('\n')) {
|
|
48
|
+
const sep = line.indexOf(':');
|
|
49
|
+
if (sep > 0) {
|
|
50
|
+
fm[line.slice(0, sep).trim()] = line.slice(sep + 1).trim();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
name = fm.name ?? basename;
|
|
54
|
+
description = fm.description ?? '';
|
|
55
|
+
type = fm.type ?? 'discovery';
|
|
49
56
|
confidence = fm.confidence != null ? Number(fm.confidence) : undefined;
|
|
50
57
|
} catch {
|
|
51
|
-
// Use defaults if
|
|
58
|
+
// Use defaults if frontmatter parsing fails
|
|
52
59
|
}
|
|
53
60
|
}
|
|
54
61
|
|