@massu/core 0.1.1 → 0.1.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/README.md +2 -2
- package/dist/hooks/cost-tracker.js +23 -35
- package/dist/hooks/post-edit-context.js +2 -2
- package/dist/hooks/post-tool-use.js +43 -58
- package/dist/hooks/pre-compact.js +23 -38
- package/dist/hooks/pre-delete-check.js +18 -31
- package/dist/hooks/quality-event.js +23 -35
- package/dist/hooks/session-end.js +62 -78
- package/dist/hooks/session-start.js +33 -42
- package/dist/hooks/user-prompt.js +23 -38
- package/package.json +8 -14
- package/src/adr-generator.ts +9 -2
- package/src/analytics.ts +9 -3
- package/src/audit-trail.ts +10 -3
- package/src/cloud-sync.ts +14 -18
- package/src/commands/init.ts +1 -5
- package/src/cost-tracker.ts +11 -6
- package/src/dependency-scorer.ts +9 -2
- package/src/docs-tools.ts +13 -10
- package/src/hooks/post-edit-context.ts +3 -3
- package/src/hooks/session-end.ts +3 -3
- package/src/hooks/session-start.ts +2 -2
- package/src/memory-db.ts +1351 -23
- package/src/memory-tools.ts +14 -15
- package/src/observability-tools.ts +13 -2
- package/src/prompt-analyzer.ts +9 -2
- package/src/regression-detector.ts +9 -3
- package/src/security-scorer.ts +9 -2
- package/src/sentinel-db.ts +43 -88
- package/src/sentinel-tools.ts +8 -11
- package/src/server.ts +1 -2
- package/src/team-knowledge.ts +9 -2
- package/src/tools.ts +771 -35
- package/src/validate-features-runner.ts +0 -1
- package/src/validation-engine.ts +9 -2
- package/dist/cli.js +0 -7890
- package/dist/server.js +0 -7008
- package/src/__tests__/adr-generator.test.ts +0 -260
- package/src/__tests__/analytics.test.ts +0 -282
- package/src/__tests__/audit-trail.test.ts +0 -382
- package/src/__tests__/backfill-sessions.test.ts +0 -690
- package/src/__tests__/cli.test.ts +0 -290
- package/src/__tests__/cloud-sync.test.ts +0 -261
- package/src/__tests__/config-sections.test.ts +0 -359
- package/src/__tests__/config.test.ts +0 -732
- package/src/__tests__/cost-tracker.test.ts +0 -348
- package/src/__tests__/db.test.ts +0 -177
- package/src/__tests__/dependency-scorer.test.ts +0 -325
- package/src/__tests__/docs-integration.test.ts +0 -178
- package/src/__tests__/docs-tools.test.ts +0 -199
- package/src/__tests__/domains.test.ts +0 -236
- package/src/__tests__/hooks.test.ts +0 -221
- package/src/__tests__/import-resolver.test.ts +0 -95
- package/src/__tests__/integration/path-traversal.test.ts +0 -134
- package/src/__tests__/integration/pricing-consistency.test.ts +0 -88
- package/src/__tests__/integration/tool-registration.test.ts +0 -146
- package/src/__tests__/memory-db.test.ts +0 -404
- package/src/__tests__/memory-enhancements.test.ts +0 -316
- package/src/__tests__/memory-tools.test.ts +0 -199
- package/src/__tests__/middleware-tree.test.ts +0 -177
- package/src/__tests__/observability-tools.test.ts +0 -595
- package/src/__tests__/observability.test.ts +0 -437
- package/src/__tests__/observation-extractor.test.ts +0 -167
- package/src/__tests__/page-deps.test.ts +0 -60
- package/src/__tests__/prompt-analyzer.test.ts +0 -298
- package/src/__tests__/regression-detector.test.ts +0 -295
- package/src/__tests__/rules.test.ts +0 -87
- package/src/__tests__/schema-mapper.test.ts +0 -29
- package/src/__tests__/security-scorer.test.ts +0 -238
- package/src/__tests__/security-utils.test.ts +0 -175
- package/src/__tests__/sentinel-db.test.ts +0 -491
- package/src/__tests__/sentinel-scanner.test.ts +0 -750
- package/src/__tests__/sentinel-tools.test.ts +0 -324
- package/src/__tests__/sentinel-types.test.ts +0 -750
- package/src/__tests__/server.test.ts +0 -452
- package/src/__tests__/session-archiver.test.ts +0 -524
- package/src/__tests__/session-state-generator.test.ts +0 -900
- package/src/__tests__/team-knowledge.test.ts +0 -327
- package/src/__tests__/tools.test.ts +0 -340
- package/src/__tests__/transcript-parser.test.ts +0 -195
- package/src/__tests__/trpc-index.test.ts +0 -25
- package/src/__tests__/validate-features-runner.test.ts +0 -517
- package/src/__tests__/validation-engine.test.ts +0 -300
- package/src/core-tools.ts +0 -685
- package/src/memory-queries.ts +0 -804
- package/src/memory-schema.ts +0 -546
- package/src/tool-helpers.ts +0 -41
|
@@ -3,7 +3,7 @@ import{createRequire as __cr}from"module";const require=__cr(import.meta.url);
|
|
|
3
3
|
|
|
4
4
|
// src/memory-db.ts
|
|
5
5
|
import Database from "better-sqlite3";
|
|
6
|
-
import { dirname as dirname2 } from "path";
|
|
6
|
+
import { dirname as dirname2, basename } from "path";
|
|
7
7
|
import { existsSync as existsSync2, mkdirSync } from "fs";
|
|
8
8
|
|
|
9
9
|
// src/config.ts
|
|
@@ -268,14 +268,26 @@ function getResolvedPaths() {
|
|
|
268
268
|
};
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
-
// src/memory-
|
|
271
|
+
// src/memory-db.ts
|
|
272
|
+
function getMemoryDb() {
|
|
273
|
+
const dbPath = getResolvedPaths().memoryDbPath;
|
|
274
|
+
const dir = dirname2(dbPath);
|
|
275
|
+
if (!existsSync2(dir)) {
|
|
276
|
+
mkdirSync(dir, { recursive: true });
|
|
277
|
+
}
|
|
278
|
+
const db = new Database(dbPath);
|
|
279
|
+
db.pragma("journal_mode = WAL");
|
|
280
|
+
db.pragma("foreign_keys = ON");
|
|
281
|
+
initMemorySchema(db);
|
|
282
|
+
return db;
|
|
283
|
+
}
|
|
272
284
|
function initMemorySchema(db) {
|
|
273
285
|
db.exec(`
|
|
274
286
|
-- Sessions table (linked to Claude Code session IDs)
|
|
275
287
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
276
288
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
277
289
|
session_id TEXT UNIQUE NOT NULL,
|
|
278
|
-
project TEXT NOT NULL DEFAULT '
|
|
290
|
+
project TEXT NOT NULL DEFAULT 'my-project',
|
|
279
291
|
git_branch TEXT,
|
|
280
292
|
started_at TEXT NOT NULL,
|
|
281
293
|
started_at_epoch INTEGER NOT NULL,
|
|
@@ -330,9 +342,7 @@ function initMemorySchema(db) {
|
|
|
330
342
|
content_rowid='id'
|
|
331
343
|
);
|
|
332
344
|
`);
|
|
333
|
-
} catch (
|
|
334
|
-
process.stderr.write(`FTS5 setup warning: ${e instanceof Error ? e.message : String(e)}
|
|
335
|
-
`);
|
|
345
|
+
} catch (_e) {
|
|
336
346
|
}
|
|
337
347
|
db.exec(`
|
|
338
348
|
CREATE TRIGGER IF NOT EXISTS observations_ai AFTER INSERT ON observations BEGIN
|
|
@@ -392,9 +402,7 @@ function initMemorySchema(db) {
|
|
|
392
402
|
content_rowid='id'
|
|
393
403
|
);
|
|
394
404
|
`);
|
|
395
|
-
} catch (
|
|
396
|
-
process.stderr.write(`FTS5 setup warning: ${e instanceof Error ? e.message : String(e)}
|
|
397
|
-
`);
|
|
405
|
+
} catch (_e) {
|
|
398
406
|
}
|
|
399
407
|
db.exec(`
|
|
400
408
|
CREATE TRIGGER IF NOT EXISTS prompts_ai AFTER INSERT ON user_prompts BEGIN
|
|
@@ -464,9 +472,7 @@ function initMemorySchema(db) {
|
|
|
464
472
|
content_rowid=id
|
|
465
473
|
);
|
|
466
474
|
`);
|
|
467
|
-
} catch (
|
|
468
|
-
process.stderr.write(`FTS5 setup warning: ${e instanceof Error ? e.message : String(e)}
|
|
469
|
-
`);
|
|
475
|
+
} catch (_e) {
|
|
470
476
|
}
|
|
471
477
|
db.exec(`
|
|
472
478
|
CREATE TRIGGER IF NOT EXISTS ct_fts_insert AFTER INSERT ON conversation_turns BEGIN
|
|
@@ -490,7 +496,7 @@ function initMemorySchema(db) {
|
|
|
490
496
|
CREATE TABLE IF NOT EXISTS session_quality_scores (
|
|
491
497
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
492
498
|
session_id TEXT NOT NULL UNIQUE,
|
|
493
|
-
project TEXT NOT NULL DEFAULT '
|
|
499
|
+
project TEXT NOT NULL DEFAULT 'my-project',
|
|
494
500
|
score INTEGER NOT NULL DEFAULT 100,
|
|
495
501
|
security_score INTEGER NOT NULL DEFAULT 100,
|
|
496
502
|
architecture_score INTEGER NOT NULL DEFAULT 100,
|
|
@@ -513,7 +519,7 @@ function initMemorySchema(db) {
|
|
|
513
519
|
CREATE TABLE IF NOT EXISTS session_costs (
|
|
514
520
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
515
521
|
session_id TEXT NOT NULL UNIQUE,
|
|
516
|
-
project TEXT NOT NULL DEFAULT '
|
|
522
|
+
project TEXT NOT NULL DEFAULT 'my-project',
|
|
517
523
|
input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
518
524
|
output_tokens INTEGER NOT NULL DEFAULT 0,
|
|
519
525
|
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
|
@@ -741,9 +747,6 @@ function initMemorySchema(db) {
|
|
|
741
747
|
CREATE INDEX IF NOT EXISTS idx_pending_sync_created ON pending_sync(created_at ASC);
|
|
742
748
|
`);
|
|
743
749
|
}
|
|
744
|
-
|
|
745
|
-
// src/memory-queries.ts
|
|
746
|
-
import { basename } from "path";
|
|
747
750
|
function autoDetectTaskId(planFile) {
|
|
748
751
|
if (!planFile) return null;
|
|
749
752
|
const base = basename(planFile);
|
|
@@ -768,24 +771,6 @@ function linkSessionToTask(db, sessionId, taskId) {
|
|
|
768
771
|
db.prepare("UPDATE sessions SET task_id = ? WHERE session_id = ?").run(taskId, sessionId);
|
|
769
772
|
}
|
|
770
773
|
|
|
771
|
-
// src/memory-db.ts
|
|
772
|
-
var initializedPaths = /* @__PURE__ */ new Set();
|
|
773
|
-
function getMemoryDb() {
|
|
774
|
-
const dbPath = getResolvedPaths().memoryDbPath;
|
|
775
|
-
const dir = dirname2(dbPath);
|
|
776
|
-
if (!existsSync2(dir)) {
|
|
777
|
-
mkdirSync(dir, { recursive: true });
|
|
778
|
-
}
|
|
779
|
-
const db = new Database(dbPath);
|
|
780
|
-
db.pragma("journal_mode = WAL");
|
|
781
|
-
db.pragma("foreign_keys = ON");
|
|
782
|
-
if (!initializedPaths.has(dbPath)) {
|
|
783
|
-
initMemorySchema(db);
|
|
784
|
-
initializedPaths.add(dbPath);
|
|
785
|
-
}
|
|
786
|
-
return db;
|
|
787
|
-
}
|
|
788
|
-
|
|
789
774
|
// src/hooks/user-prompt.ts
|
|
790
775
|
async function main() {
|
|
791
776
|
try {
|
|
@@ -835,14 +820,14 @@ async function getGitBranch() {
|
|
|
835
820
|
}
|
|
836
821
|
}
|
|
837
822
|
function readStdin() {
|
|
838
|
-
return new Promise((
|
|
823
|
+
return new Promise((resolve3) => {
|
|
839
824
|
let data = "";
|
|
840
825
|
process.stdin.setEncoding("utf-8");
|
|
841
826
|
process.stdin.on("data", (chunk) => {
|
|
842
827
|
data += chunk;
|
|
843
828
|
});
|
|
844
|
-
process.stdin.on("end", () =>
|
|
845
|
-
setTimeout(() =>
|
|
829
|
+
process.stdin.on("end", () => resolve3(data));
|
|
830
|
+
setTimeout(() => resolve3(data), 3e3);
|
|
846
831
|
});
|
|
847
832
|
}
|
|
848
833
|
main();
|
package/package.json
CHANGED
|
@@ -1,28 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@massu/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AI Engineering Governance MCP Server - Session memory, feature registry, code intelligence, and rule enforcement",
|
|
6
|
-
"
|
|
7
|
-
"author": "Massu AI <hello@massu.ai>",
|
|
8
|
-
"main": "dist/server.js",
|
|
9
|
-
"exports": {
|
|
10
|
-
".": "./dist/server.js",
|
|
11
|
-
"./cli": "./dist/cli.js"
|
|
12
|
-
},
|
|
6
|
+
"main": "src/server.ts",
|
|
13
7
|
"bin": {
|
|
14
|
-
"massu": "
|
|
8
|
+
"massu": "./src/cli.ts"
|
|
15
9
|
},
|
|
16
10
|
"scripts": {
|
|
17
11
|
"start": "npx tsx src/server.ts",
|
|
18
12
|
"test": "vitest run",
|
|
19
|
-
"build": "tsc --noEmit && npm run build:
|
|
20
|
-
"build:server": "esbuild --bundle --platform=node --format=esm --outdir=dist --entry-names=[name] src/server.ts src/cli.ts --external:better-sqlite3 --external:yaml --external:zod --banner:js='import{createRequire as __cr}from\"module\";const require=__cr(import.meta.url);'",
|
|
13
|
+
"build": "tsc --noEmit && npm run build:hooks",
|
|
21
14
|
"build:hooks": "esbuild --bundle --platform=node --format=esm --outdir=dist/hooks src/hooks/*.ts --external:better-sqlite3 --external:yaml --external:zod --banner:js='import{createRequire as __cr}from\"module\";const require=__cr(import.meta.url);'",
|
|
22
|
-
"test:integration": "vitest run src/__tests__/integration/",
|
|
23
15
|
"prepublishOnly": "bash ../../scripts/prepublish-check.sh && npm run build"
|
|
24
16
|
},
|
|
25
17
|
"dependencies": {
|
|
18
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
26
19
|
"better-sqlite3": "^12.6.2",
|
|
27
20
|
"yaml": "^2.4.0",
|
|
28
21
|
"zod": "^3.23.0"
|
|
@@ -36,6 +29,7 @@
|
|
|
36
29
|
},
|
|
37
30
|
"files": [
|
|
38
31
|
"src/**/*",
|
|
32
|
+
"!src/__tests__/**",
|
|
39
33
|
"dist/**/*",
|
|
40
34
|
"LICENSE"
|
|
41
35
|
],
|
|
@@ -52,11 +46,11 @@
|
|
|
52
46
|
},
|
|
53
47
|
"repository": {
|
|
54
48
|
"type": "git",
|
|
55
|
-
"url": "
|
|
49
|
+
"url": "https://github.com/massu-ai/massu.git",
|
|
56
50
|
"directory": "packages/core"
|
|
57
51
|
},
|
|
58
52
|
"bugs": {
|
|
59
53
|
"url": "https://github.com/massu-ai/massu/issues"
|
|
60
54
|
},
|
|
61
|
-
"homepage": "https://massu
|
|
55
|
+
"homepage": "https://github.com/massu-ai/massu#readme"
|
|
62
56
|
}
|
package/src/adr-generator.ts
CHANGED
|
@@ -2,14 +2,18 @@
|
|
|
2
2
|
// Licensed under BSL 1.1 - see LICENSE file for details.
|
|
3
3
|
|
|
4
4
|
import type Database from 'better-sqlite3';
|
|
5
|
-
import type { ToolDefinition, ToolResult } from './
|
|
6
|
-
import { p, text } from './tool-helpers.ts';
|
|
5
|
+
import type { ToolDefinition, ToolResult } from './tools.ts';
|
|
7
6
|
import { getConfig } from './config.ts';
|
|
8
7
|
|
|
9
8
|
// ============================================================
|
|
10
9
|
// ADR (Architecture Decision Record) Auto-Generation
|
|
11
10
|
// ============================================================
|
|
12
11
|
|
|
12
|
+
/** Prefix a base tool name with the configured tool prefix. */
|
|
13
|
+
function p(baseName: string): string {
|
|
14
|
+
return `${getConfig().toolPrefix}_${baseName}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
13
17
|
/** Default decision detection phrases. Configurable via governance.adr.detection_phrases */
|
|
14
18
|
const DEFAULT_DETECTION_PHRASES = ['chose', 'decided', 'switching to', 'moving from', 'going with'];
|
|
15
19
|
|
|
@@ -283,3 +287,6 @@ function handleAdrGenerate(args: Record<string, unknown>, db: Database.Database)
|
|
|
283
287
|
return text(lines.filter(Boolean).join('\n'));
|
|
284
288
|
}
|
|
285
289
|
|
|
290
|
+
function text(content: string): ToolResult {
|
|
291
|
+
return { content: [{ type: 'text', text: content }] };
|
|
292
|
+
}
|
package/src/analytics.ts
CHANGED
|
@@ -2,14 +2,18 @@
|
|
|
2
2
|
// Licensed under BSL 1.1 - see LICENSE file for details.
|
|
3
3
|
|
|
4
4
|
import type Database from 'better-sqlite3';
|
|
5
|
-
import type { ToolDefinition, ToolResult } from './
|
|
6
|
-
import { p, text } from './tool-helpers.ts';
|
|
5
|
+
import type { ToolDefinition, ToolResult } from './tools.ts';
|
|
7
6
|
import { getConfig } from './config.ts';
|
|
8
7
|
|
|
9
8
|
// ============================================================
|
|
10
9
|
// Quality Trend Analytics
|
|
11
10
|
// ============================================================
|
|
12
11
|
|
|
12
|
+
/** Prefix a base tool name with the configured tool prefix. */
|
|
13
|
+
function p(baseName: string): string {
|
|
14
|
+
return `${getConfig().toolPrefix}_${baseName}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
13
17
|
export interface QualityBreakdown {
|
|
14
18
|
security: number;
|
|
15
19
|
architecture: number;
|
|
@@ -118,7 +122,6 @@ export function backfillQualityScores(db: Database.Database): number {
|
|
|
118
122
|
FROM sessions s
|
|
119
123
|
LEFT JOIN session_quality_scores q ON s.session_id = q.session_id
|
|
120
124
|
WHERE q.session_id IS NULL
|
|
121
|
-
LIMIT 1000
|
|
122
125
|
`).all() as Array<{ session_id: string }>;
|
|
123
126
|
|
|
124
127
|
let backfilled = 0;
|
|
@@ -365,3 +368,6 @@ function handleQualityReport(args: Record<string, unknown>, db: Database.Databas
|
|
|
365
368
|
return text(lines.join('\n'));
|
|
366
369
|
}
|
|
367
370
|
|
|
371
|
+
function text(content: string): ToolResult {
|
|
372
|
+
return { content: [{ type: 'text', text: content }] };
|
|
373
|
+
}
|
package/src/audit-trail.ts
CHANGED
|
@@ -2,14 +2,18 @@
|
|
|
2
2
|
// Licensed under BSL 1.1 - see LICENSE file for details.
|
|
3
3
|
|
|
4
4
|
import type Database from 'better-sqlite3';
|
|
5
|
-
import type { ToolDefinition, ToolResult } from './
|
|
6
|
-
import { p, text } from './tool-helpers.ts';
|
|
5
|
+
import type { ToolDefinition, ToolResult } from './tools.ts';
|
|
7
6
|
import { getConfig } from './config.ts';
|
|
8
7
|
|
|
9
8
|
// ============================================================
|
|
10
9
|
// Compliance Audit Trail
|
|
11
10
|
// ============================================================
|
|
12
11
|
|
|
12
|
+
/** Prefix a base tool name with the configured tool prefix. */
|
|
13
|
+
function p(baseName: string): string {
|
|
14
|
+
return `${getConfig().toolPrefix}_${baseName}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
13
17
|
export interface AuditEntry {
|
|
14
18
|
eventType: 'code_change' | 'rule_enforced' | 'approval' | 'review' | 'commit' | 'compaction';
|
|
15
19
|
actor: 'ai' | 'human' | 'hook' | 'agent';
|
|
@@ -129,7 +133,7 @@ export function backfillAuditLog(db: Database.Database): number {
|
|
|
129
133
|
FROM observations o
|
|
130
134
|
LEFT JOIN audit_log a ON a.evidence = o.detail AND a.session_id = o.session_id
|
|
131
135
|
WHERE a.id IS NULL
|
|
132
|
-
AND o.type IN ('bugfix', 'cr_violation', 'vr_check', '
|
|
136
|
+
AND o.type IN ('bugfix', 'cr_violation', 'vr_check', 'incident', 'decision')
|
|
133
137
|
ORDER BY o.created_at ASC
|
|
134
138
|
LIMIT 1000
|
|
135
139
|
`).all() as Array<Record<string, unknown>>;
|
|
@@ -441,3 +445,6 @@ function handleAuditChain(args: Record<string, unknown>, db: Database.Database):
|
|
|
441
445
|
return text(lines.join('\n'));
|
|
442
446
|
}
|
|
443
447
|
|
|
448
|
+
function text(content: string): ToolResult {
|
|
449
|
+
return { content: [{ type: 'text', text: content }] };
|
|
450
|
+
}
|
package/src/cloud-sync.ts
CHANGED
|
@@ -166,26 +166,22 @@ export async function syncToCloud(
|
|
|
166
166
|
* Successfully synced items are removed; failed items get their retry count incremented.
|
|
167
167
|
*/
|
|
168
168
|
export async function drainSyncQueue(db: Database.Database): Promise<void> {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
incrementRetryCount(db, item.id, result.error ?? 'Unknown error');
|
|
182
|
-
}
|
|
183
|
-
} catch (err) {
|
|
184
|
-
incrementRetryCount(db, item.id, err instanceof Error ? err.message : String(err));
|
|
169
|
+
const config = getConfig();
|
|
170
|
+
if (!config.cloud?.enabled || !config.cloud?.apiKey) return;
|
|
171
|
+
|
|
172
|
+
const pending = dequeuePendingSync(db, 10);
|
|
173
|
+
for (const item of pending) {
|
|
174
|
+
try {
|
|
175
|
+
const payload = JSON.parse(item.payload) as SyncPayload;
|
|
176
|
+
const result = await syncToCloud(db, payload);
|
|
177
|
+
if (result.success) {
|
|
178
|
+
removePendingSync(db, item.id);
|
|
179
|
+
} else {
|
|
180
|
+
incrementRetryCount(db, item.id, result.error ?? 'Unknown error');
|
|
185
181
|
}
|
|
182
|
+
} catch (err) {
|
|
183
|
+
incrementRetryCount(db, item.id, err instanceof Error ? err.message : String(err));
|
|
186
184
|
}
|
|
187
|
-
} catch (err) {
|
|
188
|
-
process.stderr.write(`massu: drainSyncQueue failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
189
185
|
}
|
|
190
186
|
}
|
|
191
187
|
|
package/src/commands/init.ts
CHANGED
|
@@ -12,11 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
15
|
-
import { resolve, basename
|
|
16
|
-
import { fileURLToPath } from 'url';
|
|
17
|
-
|
|
18
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
19
|
-
const __dirname = dirname(__filename);
|
|
15
|
+
import { resolve, basename } from 'path';
|
|
20
16
|
import { stringify as yamlStringify } from 'yaml';
|
|
21
17
|
|
|
22
18
|
// ============================================================
|
package/src/cost-tracker.ts
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
// Licensed under BSL 1.1 - see LICENSE file for details.
|
|
3
3
|
|
|
4
4
|
import type Database from 'better-sqlite3';
|
|
5
|
-
import type { ToolDefinition, ToolResult } from './
|
|
6
|
-
import { p, text } from './tool-helpers.ts';
|
|
5
|
+
import type { ToolDefinition, ToolResult } from './tools.ts';
|
|
7
6
|
import type { TranscriptEntry } from './transcript-parser.ts';
|
|
8
7
|
import { getConfig } from './config.ts';
|
|
9
8
|
|
|
@@ -11,13 +10,17 @@ import { getConfig } from './config.ts';
|
|
|
11
10
|
// Cost Attribution Tracking
|
|
12
11
|
// ============================================================
|
|
13
12
|
|
|
13
|
+
/** Prefix a base tool name with the configured tool prefix. */
|
|
14
|
+
function p(baseName: string): string {
|
|
15
|
+
return `${getConfig().toolPrefix}_${baseName}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
14
18
|
/** Default model pricing (Claude models). Can be overridden via config.analytics.cost.models */
|
|
15
19
|
const DEFAULT_MODEL_PRICING: Record<string, { input_per_million: number; output_per_million: number; cache_read_per_million?: number; cache_write_per_million?: number }> = {
|
|
16
|
-
'claude-opus-4-6': { input_per_million:
|
|
20
|
+
'claude-opus-4-6': { input_per_million: 15.00, output_per_million: 75.00, cache_read_per_million: 1.50, cache_write_per_million: 18.75 },
|
|
17
21
|
'claude-sonnet-4-6': { input_per_million: 3.00, output_per_million: 15.00, cache_read_per_million: 0.30, cache_write_per_million: 3.75 },
|
|
18
22
|
'claude-sonnet-4-5': { input_per_million: 3.00, output_per_million: 15.00, cache_read_per_million: 0.30, cache_write_per_million: 3.75 },
|
|
19
|
-
'claude-
|
|
20
|
-
'claude-haiku-4-5-20251001': { input_per_million: 1.00, output_per_million: 5.00, cache_read_per_million: 0.10, cache_write_per_million: 1.25 },
|
|
23
|
+
'claude-haiku-4-5-20251001': { input_per_million: 0.80, output_per_million: 4.00, cache_read_per_million: 0.08, cache_write_per_million: 1.00 },
|
|
21
24
|
'default': { input_per_million: 3.00, output_per_million: 15.00, cache_read_per_million: 0.30, cache_write_per_million: 3.75 },
|
|
22
25
|
};
|
|
23
26
|
|
|
@@ -134,7 +137,6 @@ export function backfillSessionCosts(db: Database.Database): number {
|
|
|
134
137
|
FROM sessions s
|
|
135
138
|
LEFT JOIN session_costs c ON s.session_id = c.session_id
|
|
136
139
|
WHERE c.session_id IS NULL
|
|
137
|
-
LIMIT 1000
|
|
138
140
|
`).all() as Array<{ session_id: string }>;
|
|
139
141
|
|
|
140
142
|
// Backfilling requires transcript data which may not be available
|
|
@@ -348,3 +350,6 @@ function handleCostFeature(args: Record<string, unknown>, db: Database.Database)
|
|
|
348
350
|
return text(lines.join('\n'));
|
|
349
351
|
}
|
|
350
352
|
|
|
353
|
+
function text(content: string): ToolResult {
|
|
354
|
+
return { content: [{ type: 'text', text: content }] };
|
|
355
|
+
}
|
package/src/dependency-scorer.ts
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
// Licensed under BSL 1.1 - see LICENSE file for details.
|
|
3
3
|
|
|
4
4
|
import type Database from 'better-sqlite3';
|
|
5
|
-
import type { ToolDefinition, ToolResult } from './
|
|
6
|
-
import { p, text } from './tool-helpers.ts';
|
|
5
|
+
import type { ToolDefinition, ToolResult } from './tools.ts';
|
|
7
6
|
import { getConfig } from './config.ts';
|
|
8
7
|
import { existsSync, readFileSync } from 'fs';
|
|
9
8
|
import { resolve } from 'path';
|
|
@@ -12,6 +11,11 @@ import { resolve } from 'path';
|
|
|
12
11
|
// Dependency Risk Scoring
|
|
13
12
|
// ============================================================
|
|
14
13
|
|
|
14
|
+
/** Prefix a base tool name with the configured tool prefix. */
|
|
15
|
+
function p(baseName: string): string {
|
|
16
|
+
return `${getConfig().toolPrefix}_${baseName}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
15
19
|
export interface DepRiskFactors {
|
|
16
20
|
vulnerabilities: number;
|
|
17
21
|
lastPublishDays: number | null;
|
|
@@ -328,3 +332,6 @@ function handleDepAlternatives(args: Record<string, unknown>, db: Database.Datab
|
|
|
328
332
|
return text(lines.filter(Boolean).join('\n'));
|
|
329
333
|
}
|
|
330
334
|
|
|
335
|
+
function text(content: string): ToolResult {
|
|
336
|
+
return { content: [{ type: 'text', text: content }] };
|
|
337
|
+
}
|
package/src/docs-tools.ts
CHANGED
|
@@ -4,22 +4,18 @@
|
|
|
4
4
|
import { readFileSync, existsSync } from 'fs';
|
|
5
5
|
import { resolve, basename } from 'path';
|
|
6
6
|
import { getConfig, getResolvedPaths } from './config.ts';
|
|
7
|
-
import type { ToolDefinition, ToolResult } from './
|
|
8
|
-
|
|
7
|
+
import type { ToolDefinition, ToolResult } from './tools.ts';
|
|
8
|
+
|
|
9
|
+
/** Prefix a base tool name with the configured tool prefix. */
|
|
10
|
+
function p(baseName: string): string {
|
|
11
|
+
return `${getConfig().toolPrefix}_${baseName}`;
|
|
12
|
+
}
|
|
9
13
|
|
|
10
14
|
// ============================================================
|
|
11
15
|
// Help Site Auto-Sync: MCP Docs Tools
|
|
12
16
|
// docs_audit + docs_coverage
|
|
13
17
|
// ============================================================
|
|
14
18
|
|
|
15
|
-
const DOCS_BASE_NAMES = new Set(['docs_audit', 'docs_coverage']);
|
|
16
|
-
|
|
17
|
-
export function isDocsTool(name: string): boolean {
|
|
18
|
-
const pfx = getConfig().toolPrefix + '_';
|
|
19
|
-
const baseName = name.startsWith(pfx) ? name.slice(pfx.length) : name;
|
|
20
|
-
return DOCS_BASE_NAMES.has(baseName);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
19
|
interface DocsMapping {
|
|
24
20
|
id: string;
|
|
25
21
|
helpPage: string;
|
|
@@ -512,3 +508,10 @@ function handleDocsCoverage(args: Record<string, unknown>): ToolResult {
|
|
|
512
508
|
return text(lines.join('\n'));
|
|
513
509
|
}
|
|
514
510
|
|
|
511
|
+
// ============================================================
|
|
512
|
+
// Utilities
|
|
513
|
+
// ============================================================
|
|
514
|
+
|
|
515
|
+
function text(content: string): ToolResult {
|
|
516
|
+
return { content: [{ type: 'text', text: content }] };
|
|
517
|
+
}
|
|
@@ -54,12 +54,12 @@ async function main(): Promise<void> {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
// 2. Check middleware tree membership
|
|
57
|
+
// 2. Check middleware tree membership
|
|
58
58
|
try {
|
|
59
59
|
const dataDb = new Database(getResolvedPaths().dataDbPath, { readonly: true });
|
|
60
60
|
try {
|
|
61
61
|
if (isInMiddlewareTree(dataDb, rel)) {
|
|
62
|
-
warnings.push('[CRITICAL]
|
|
62
|
+
warnings.push('[CRITICAL] This file is in the middleware import tree. No Node.js deps allowed.');
|
|
63
63
|
}
|
|
64
64
|
} finally {
|
|
65
65
|
dataDb.close();
|
|
@@ -70,7 +70,7 @@ async function main(): Promise<void> {
|
|
|
70
70
|
|
|
71
71
|
// 3. Output warnings if any
|
|
72
72
|
if (warnings.length > 0) {
|
|
73
|
-
console.log(`[
|
|
73
|
+
console.log(`[Massu] ${warnings.join(' | ')}`);
|
|
74
74
|
}
|
|
75
75
|
} catch (_e) {
|
|
76
76
|
// Best-effort: never block Claude Code
|
package/src/hooks/session-end.ts
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
// Dependencies: P1-002, P5-001, P5-002
|
|
9
9
|
// ============================================================
|
|
10
10
|
|
|
11
|
-
import { getMemoryDb, endSession, addSummary,
|
|
11
|
+
import { getMemoryDb, endSession, addSummary, createSession, addConversationTurn, addToolCallDetail, getLastProcessedLine, setLastProcessedLine } from '../memory-db.ts';
|
|
12
12
|
import { generateCurrentMd } from '../session-state-generator.ts';
|
|
13
13
|
import { archiveAndRegenerate } from '../session-archiver.ts';
|
|
14
|
-
import { parseTranscriptFrom,
|
|
14
|
+
import { parseTranscriptFrom, estimateTokens } from '../transcript-parser.ts';
|
|
15
15
|
import { syncToCloud, drainSyncQueue } from '../cloud-sync.ts';
|
|
16
16
|
import { calculateQualityScore, storeQualityScore, backfillQualityScores } from '../analytics.ts';
|
|
17
17
|
import { extractTokenUsage, calculateCost, storeSessionCost } from '../cost-tracker.ts';
|
|
@@ -64,7 +64,7 @@ async function main(): Promise<void> {
|
|
|
64
64
|
// 4.6. Calculate and store quality score
|
|
65
65
|
try {
|
|
66
66
|
const { score, breakdown } = calculateQualityScore(db, session_id);
|
|
67
|
-
if (score
|
|
67
|
+
if (score !== 50) {
|
|
68
68
|
storeQualityScore(db, session_id, score, breakdown);
|
|
69
69
|
}
|
|
70
70
|
backfillQualityScores(db);
|
|
@@ -153,7 +153,7 @@ function buildContext(db: Database.Database, sessionId: string, source: string,
|
|
|
153
153
|
sections.sort((a, b) => b.importance - a.importance);
|
|
154
154
|
|
|
155
155
|
let usedTokens = 0;
|
|
156
|
-
const headerTokens = estimateTokens('===
|
|
156
|
+
const headerTokens = estimateTokens('=== Massu Memory: Previous Session Context ===\n\n=== END Massu Memory ===\n');
|
|
157
157
|
usedTokens += headerTokens;
|
|
158
158
|
|
|
159
159
|
const includedSections: string[] = [];
|
|
@@ -167,7 +167,7 @@ function buildContext(db: Database.Database, sessionId: string, source: string,
|
|
|
167
167
|
|
|
168
168
|
if (includedSections.length === 0) return '';
|
|
169
169
|
|
|
170
|
-
return `===
|
|
170
|
+
return `=== Massu Memory: Previous Session Context ===\n\n${includedSections.join('\n')}\n=== END Massu Memory ===\n`;
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
function estimateTokens(text: string): number {
|