@massu/core 1.15.0 → 1.15.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/CHANGELOG.md +30 -0
- package/commands/massu-loop/references/loop-controller.md +54 -7
- package/dist/cli.js +930 -575
- package/dist/hooks/auto-learning-pipeline.js +90 -19
- package/dist/hooks/classify-failure.js +112 -43
- package/dist/hooks/cost-tracker.js +108 -39
- package/dist/hooks/fix-detector.js +95 -24
- package/dist/hooks/incident-pipeline.js +114 -45
- package/dist/hooks/post-edit-context.js +105 -36
- package/dist/hooks/post-tool-use.js +137 -68
- package/dist/hooks/pre-compact.js +108 -39
- package/dist/hooks/pre-delete-check.js +107 -38
- package/dist/hooks/pre-tool-use-gate.js +113 -44
- package/dist/hooks/quality-event.js +108 -39
- package/dist/hooks/rule-enforcement-pipeline.js +92 -21
- package/dist/hooks/session-end.js +126 -57
- package/dist/hooks/session-start.js +177 -99
- package/dist/hooks/user-prompt.js +124 -55
- package/package.json +7 -6
|
@@ -3,15 +3,79 @@ import{createRequire as __cr}from"module";const require=__cr(import.meta.url);
|
|
|
3
3
|
|
|
4
4
|
// src/hooks/auto-learning-pipeline.ts
|
|
5
5
|
import { execFileSync } from "child_process";
|
|
6
|
-
import { existsSync as
|
|
6
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, unlinkSync, readdirSync, statSync } from "fs";
|
|
7
7
|
import { tmpdir } from "os";
|
|
8
8
|
import { join } from "path";
|
|
9
9
|
|
|
10
10
|
// src/config.ts
|
|
11
|
-
import { resolve, dirname } from "path";
|
|
12
|
-
import { existsSync, readFileSync } from "fs";
|
|
11
|
+
import { resolve as resolve2, dirname } from "path";
|
|
12
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
13
13
|
import { parse as parseYaml } from "yaml";
|
|
14
14
|
import { z } from "zod";
|
|
15
|
+
|
|
16
|
+
// src/credentials.ts
|
|
17
|
+
import { homedir } from "os";
|
|
18
|
+
import { resolve } from "path";
|
|
19
|
+
import {
|
|
20
|
+
existsSync,
|
|
21
|
+
readFileSync,
|
|
22
|
+
writeFileSync,
|
|
23
|
+
mkdirSync,
|
|
24
|
+
rmSync,
|
|
25
|
+
chmodSync
|
|
26
|
+
} from "fs";
|
|
27
|
+
var MASSU_ENV_API_KEY = "MASSU_API_KEY";
|
|
28
|
+
var MASSU_ENV_CLOUD_ENDPOINT = "MASSU_CLOUD_ENDPOINT";
|
|
29
|
+
var DEFAULT_CLOUD_ENDPOINT = "https://api.massu.ai/v1";
|
|
30
|
+
function credentialsDir(home = homedir()) {
|
|
31
|
+
return resolve(home, ".massu");
|
|
32
|
+
}
|
|
33
|
+
function credentialsPath(home = homedir()) {
|
|
34
|
+
return resolve(credentialsDir(home), "credentials");
|
|
35
|
+
}
|
|
36
|
+
function readUserCredentials(home = homedir()) {
|
|
37
|
+
try {
|
|
38
|
+
const p = credentialsPath(home);
|
|
39
|
+
if (!existsSync(p)) return void 0;
|
|
40
|
+
const parsed = JSON.parse(readFileSync(p, "utf-8"));
|
|
41
|
+
const key = typeof parsed?.apiKey === "string" ? parsed.apiKey.trim() : "";
|
|
42
|
+
return key.length > 0 ? key : void 0;
|
|
43
|
+
} catch {
|
|
44
|
+
return void 0;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function isUnresolvedLiteral(v) {
|
|
48
|
+
return /^\$\{[^}]+\}$/.test(v);
|
|
49
|
+
}
|
|
50
|
+
function resolveApiKey(opts = {}) {
|
|
51
|
+
const env = opts.env ?? process.env;
|
|
52
|
+
const home = opts.home ?? homedir();
|
|
53
|
+
const cfg = typeof opts.configApiKey === "string" ? opts.configApiKey.trim() : "";
|
|
54
|
+
if (cfg.length > 0 && !isUnresolvedLiteral(cfg)) {
|
|
55
|
+
return { apiKey: cfg, source: "config" };
|
|
56
|
+
}
|
|
57
|
+
const envRaw = env[MASSU_ENV_API_KEY];
|
|
58
|
+
const envKey = typeof envRaw === "string" ? envRaw.trim() : "";
|
|
59
|
+
if (envKey.length > 0) {
|
|
60
|
+
return { apiKey: envKey, source: "env" };
|
|
61
|
+
}
|
|
62
|
+
const fileKey = readUserCredentials(home);
|
|
63
|
+
if (fileKey) {
|
|
64
|
+
return { apiKey: fileKey, source: "user-file" };
|
|
65
|
+
}
|
|
66
|
+
return { source: "none" };
|
|
67
|
+
}
|
|
68
|
+
function resolveEndpoint(opts = {}) {
|
|
69
|
+
const env = opts.env ?? process.env;
|
|
70
|
+
const cfg = typeof opts.configEndpoint === "string" ? opts.configEndpoint.trim() : "";
|
|
71
|
+
if (cfg.length > 0) return cfg;
|
|
72
|
+
const envRaw = env[MASSU_ENV_CLOUD_ENDPOINT];
|
|
73
|
+
const envEp = typeof envRaw === "string" ? envRaw.trim() : "";
|
|
74
|
+
if (envEp.length > 0) return envEp;
|
|
75
|
+
return DEFAULT_CLOUD_ENDPOINT;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/config.ts
|
|
15
79
|
var DomainConfigSchema = z.object({
|
|
16
80
|
name: z.string().default("Unknown"),
|
|
17
81
|
routers: z.array(z.string()).default([]),
|
|
@@ -393,12 +457,13 @@ var RawConfigSchema = z.object({
|
|
|
393
457
|
lsp: LSPConfigSchema.optional()
|
|
394
458
|
}).passthrough();
|
|
395
459
|
var _config = null;
|
|
460
|
+
var _resolvedApiKeySource = "none";
|
|
396
461
|
var _projectRoot = null;
|
|
397
462
|
function findProjectRoot() {
|
|
398
463
|
const cwd = process.cwd();
|
|
399
464
|
let dir = cwd;
|
|
400
465
|
while (true) {
|
|
401
|
-
if (
|
|
466
|
+
if (existsSync2(resolve2(dir, "massu.config.yaml"))) {
|
|
402
467
|
return dir;
|
|
403
468
|
}
|
|
404
469
|
const parent = dirname(dir);
|
|
@@ -407,10 +472,10 @@ function findProjectRoot() {
|
|
|
407
472
|
}
|
|
408
473
|
dir = cwd;
|
|
409
474
|
while (true) {
|
|
410
|
-
if (
|
|
475
|
+
if (existsSync2(resolve2(dir, "package.json"))) {
|
|
411
476
|
return dir;
|
|
412
477
|
}
|
|
413
|
-
if (
|
|
478
|
+
if (existsSync2(resolve2(dir, ".git"))) {
|
|
414
479
|
return dir;
|
|
415
480
|
}
|
|
416
481
|
const parent = dirname(dir);
|
|
@@ -428,10 +493,10 @@ function getProjectRoot() {
|
|
|
428
493
|
function getConfig() {
|
|
429
494
|
if (_config) return _config;
|
|
430
495
|
const root = getProjectRoot();
|
|
431
|
-
const configPath =
|
|
496
|
+
const configPath = resolve2(root, "massu.config.yaml");
|
|
432
497
|
let rawYaml = {};
|
|
433
|
-
if (
|
|
434
|
-
const content =
|
|
498
|
+
if (existsSync2(configPath)) {
|
|
499
|
+
const content = readFileSync2(configPath, "utf-8");
|
|
435
500
|
rawYaml = parseYaml(content) ?? {};
|
|
436
501
|
}
|
|
437
502
|
const result = RawConfigSchema.safeParse(rawYaml);
|
|
@@ -448,7 +513,7 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
448
513
|
);
|
|
449
514
|
}
|
|
450
515
|
const parsed = result.data;
|
|
451
|
-
const projectRoot = parsed.project.root === "auto" || !parsed.project.root ? root :
|
|
516
|
+
const projectRoot = parsed.project.root === "auto" || !parsed.project.root ? root : resolve2(root, parsed.project.root);
|
|
452
517
|
const fw = parsed.framework;
|
|
453
518
|
let router = fw.router;
|
|
454
519
|
let orm = fw.orm;
|
|
@@ -506,13 +571,19 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
506
571
|
telemetry: parsed.telemetry,
|
|
507
572
|
lsp: parsed.lsp
|
|
508
573
|
};
|
|
509
|
-
|
|
574
|
+
const resolvedKey = resolveApiKey({ configApiKey: _config.cloud?.apiKey });
|
|
575
|
+
_resolvedApiKeySource = resolvedKey.source;
|
|
576
|
+
const resolvedEndpoint = resolveEndpoint({ configEndpoint: _config.cloud?.endpoint });
|
|
577
|
+
if (resolvedKey.apiKey) {
|
|
510
578
|
_config.cloud = {
|
|
511
579
|
enabled: true,
|
|
512
580
|
sync: { memory: true, analytics: true, audit: true },
|
|
513
581
|
..._config.cloud,
|
|
514
|
-
apiKey:
|
|
582
|
+
apiKey: resolvedKey.apiKey,
|
|
583
|
+
endpoint: resolvedEndpoint
|
|
515
584
|
};
|
|
585
|
+
} else if (_config.cloud) {
|
|
586
|
+
_config.cloud = { ..._config.cloud, endpoint: _config.cloud.endpoint ?? resolvedEndpoint };
|
|
516
587
|
}
|
|
517
588
|
return _config;
|
|
518
589
|
}
|
|
@@ -542,9 +613,9 @@ async function main() {
|
|
|
542
613
|
const autoLearn = config.autoLearning;
|
|
543
614
|
const flagPath = getSessionFlagPath(hookInput.session_id);
|
|
544
615
|
let sessionFixes = [];
|
|
545
|
-
if (
|
|
616
|
+
if (existsSync3(flagPath)) {
|
|
546
617
|
try {
|
|
547
|
-
sessionFixes =
|
|
618
|
+
sessionFixes = readFileSync3(flagPath, "utf-8").split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
548
619
|
} catch {
|
|
549
620
|
}
|
|
550
621
|
}
|
|
@@ -649,9 +720,9 @@ async function main() {
|
|
|
649
720
|
}
|
|
650
721
|
function cleanup(flagPath) {
|
|
651
722
|
try {
|
|
652
|
-
if (
|
|
723
|
+
if (existsSync3(flagPath)) unlinkSync(flagPath);
|
|
653
724
|
const dir = join(tmpdir(), "massu-auto-learning");
|
|
654
|
-
if (
|
|
725
|
+
if (existsSync3(dir)) {
|
|
655
726
|
const now = Date.now();
|
|
656
727
|
for (const file of readdirSync(dir)) {
|
|
657
728
|
const fullPath = join(dir, file);
|
|
@@ -668,14 +739,14 @@ function cleanup(flagPath) {
|
|
|
668
739
|
}
|
|
669
740
|
}
|
|
670
741
|
function readStdin() {
|
|
671
|
-
return new Promise((
|
|
742
|
+
return new Promise((resolve3) => {
|
|
672
743
|
let data = "";
|
|
673
744
|
process.stdin.setEncoding("utf-8");
|
|
674
745
|
process.stdin.on("data", (chunk) => {
|
|
675
746
|
data += chunk;
|
|
676
747
|
});
|
|
677
|
-
process.stdin.on("end", () =>
|
|
678
|
-
setTimeout(() =>
|
|
748
|
+
process.stdin.on("end", () => resolve3(data));
|
|
749
|
+
setTimeout(() => resolve3(data), 5e3);
|
|
679
750
|
});
|
|
680
751
|
}
|
|
681
752
|
main();
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import{createRequire as __cr}from"module";const require=__cr(import.meta.url);
|
|
3
3
|
|
|
4
4
|
// src/hooks/classify-failure.ts
|
|
5
|
-
import { existsSync as
|
|
5
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
6
6
|
import { tmpdir } from "os";
|
|
7
7
|
import { join, basename as basename2 } from "path";
|
|
8
8
|
|
|
9
9
|
// src/config.ts
|
|
10
|
-
import { resolve, dirname } from "path";
|
|
11
|
-
import { existsSync, readFileSync } from "fs";
|
|
12
|
-
import { homedir } from "os";
|
|
10
|
+
import { resolve as resolve2, dirname } from "path";
|
|
11
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
12
|
+
import { homedir as homedir2 } from "os";
|
|
13
13
|
import { parse as parseYaml } from "yaml";
|
|
14
14
|
import { z } from "zod";
|
|
15
15
|
|
|
@@ -18,6 +18,68 @@ function encodeMemoryDirName(projectRoot) {
|
|
|
18
18
|
return projectRoot.replace(/\//g, "-");
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
// src/credentials.ts
|
|
22
|
+
import { homedir } from "os";
|
|
23
|
+
import { resolve } from "path";
|
|
24
|
+
import {
|
|
25
|
+
existsSync,
|
|
26
|
+
readFileSync,
|
|
27
|
+
writeFileSync,
|
|
28
|
+
mkdirSync,
|
|
29
|
+
rmSync,
|
|
30
|
+
chmodSync
|
|
31
|
+
} from "fs";
|
|
32
|
+
var MASSU_ENV_API_KEY = "MASSU_API_KEY";
|
|
33
|
+
var MASSU_ENV_CLOUD_ENDPOINT = "MASSU_CLOUD_ENDPOINT";
|
|
34
|
+
var DEFAULT_CLOUD_ENDPOINT = "https://api.massu.ai/v1";
|
|
35
|
+
function credentialsDir(home = homedir()) {
|
|
36
|
+
return resolve(home, ".massu");
|
|
37
|
+
}
|
|
38
|
+
function credentialsPath(home = homedir()) {
|
|
39
|
+
return resolve(credentialsDir(home), "credentials");
|
|
40
|
+
}
|
|
41
|
+
function readUserCredentials(home = homedir()) {
|
|
42
|
+
try {
|
|
43
|
+
const p = credentialsPath(home);
|
|
44
|
+
if (!existsSync(p)) return void 0;
|
|
45
|
+
const parsed = JSON.parse(readFileSync(p, "utf-8"));
|
|
46
|
+
const key = typeof parsed?.apiKey === "string" ? parsed.apiKey.trim() : "";
|
|
47
|
+
return key.length > 0 ? key : void 0;
|
|
48
|
+
} catch {
|
|
49
|
+
return void 0;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function isUnresolvedLiteral(v) {
|
|
53
|
+
return /^\$\{[^}]+\}$/.test(v);
|
|
54
|
+
}
|
|
55
|
+
function resolveApiKey(opts = {}) {
|
|
56
|
+
const env = opts.env ?? process.env;
|
|
57
|
+
const home = opts.home ?? homedir();
|
|
58
|
+
const cfg = typeof opts.configApiKey === "string" ? opts.configApiKey.trim() : "";
|
|
59
|
+
if (cfg.length > 0 && !isUnresolvedLiteral(cfg)) {
|
|
60
|
+
return { apiKey: cfg, source: "config" };
|
|
61
|
+
}
|
|
62
|
+
const envRaw = env[MASSU_ENV_API_KEY];
|
|
63
|
+
const envKey = typeof envRaw === "string" ? envRaw.trim() : "";
|
|
64
|
+
if (envKey.length > 0) {
|
|
65
|
+
return { apiKey: envKey, source: "env" };
|
|
66
|
+
}
|
|
67
|
+
const fileKey = readUserCredentials(home);
|
|
68
|
+
if (fileKey) {
|
|
69
|
+
return { apiKey: fileKey, source: "user-file" };
|
|
70
|
+
}
|
|
71
|
+
return { source: "none" };
|
|
72
|
+
}
|
|
73
|
+
function resolveEndpoint(opts = {}) {
|
|
74
|
+
const env = opts.env ?? process.env;
|
|
75
|
+
const cfg = typeof opts.configEndpoint === "string" ? opts.configEndpoint.trim() : "";
|
|
76
|
+
if (cfg.length > 0) return cfg;
|
|
77
|
+
const envRaw = env[MASSU_ENV_CLOUD_ENDPOINT];
|
|
78
|
+
const envEp = typeof envRaw === "string" ? envRaw.trim() : "";
|
|
79
|
+
if (envEp.length > 0) return envEp;
|
|
80
|
+
return DEFAULT_CLOUD_ENDPOINT;
|
|
81
|
+
}
|
|
82
|
+
|
|
21
83
|
// src/config.ts
|
|
22
84
|
var DomainConfigSchema = z.object({
|
|
23
85
|
name: z.string().default("Unknown"),
|
|
@@ -400,12 +462,13 @@ var RawConfigSchema = z.object({
|
|
|
400
462
|
lsp: LSPConfigSchema.optional()
|
|
401
463
|
}).passthrough();
|
|
402
464
|
var _config = null;
|
|
465
|
+
var _resolvedApiKeySource = "none";
|
|
403
466
|
var _projectRoot = null;
|
|
404
467
|
function findProjectRoot() {
|
|
405
468
|
const cwd = process.cwd();
|
|
406
469
|
let dir = cwd;
|
|
407
470
|
while (true) {
|
|
408
|
-
if (
|
|
471
|
+
if (existsSync2(resolve2(dir, "massu.config.yaml"))) {
|
|
409
472
|
return dir;
|
|
410
473
|
}
|
|
411
474
|
const parent = dirname(dir);
|
|
@@ -414,10 +477,10 @@ function findProjectRoot() {
|
|
|
414
477
|
}
|
|
415
478
|
dir = cwd;
|
|
416
479
|
while (true) {
|
|
417
|
-
if (
|
|
480
|
+
if (existsSync2(resolve2(dir, "package.json"))) {
|
|
418
481
|
return dir;
|
|
419
482
|
}
|
|
420
|
-
if (
|
|
483
|
+
if (existsSync2(resolve2(dir, ".git"))) {
|
|
421
484
|
return dir;
|
|
422
485
|
}
|
|
423
486
|
const parent = dirname(dir);
|
|
@@ -435,10 +498,10 @@ function getProjectRoot() {
|
|
|
435
498
|
function getConfig() {
|
|
436
499
|
if (_config) return _config;
|
|
437
500
|
const root = getProjectRoot();
|
|
438
|
-
const configPath =
|
|
501
|
+
const configPath = resolve2(root, "massu.config.yaml");
|
|
439
502
|
let rawYaml = {};
|
|
440
|
-
if (
|
|
441
|
-
const content =
|
|
503
|
+
if (existsSync2(configPath)) {
|
|
504
|
+
const content = readFileSync2(configPath, "utf-8");
|
|
442
505
|
rawYaml = parseYaml(content) ?? {};
|
|
443
506
|
}
|
|
444
507
|
const result = RawConfigSchema.safeParse(rawYaml);
|
|
@@ -455,7 +518,7 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
455
518
|
);
|
|
456
519
|
}
|
|
457
520
|
const parsed = result.data;
|
|
458
|
-
const projectRoot = parsed.project.root === "auto" || !parsed.project.root ? root :
|
|
521
|
+
const projectRoot = parsed.project.root === "auto" || !parsed.project.root ? root : resolve2(root, parsed.project.root);
|
|
459
522
|
const fw = parsed.framework;
|
|
460
523
|
let router = fw.router;
|
|
461
524
|
let orm = fw.orm;
|
|
@@ -513,13 +576,19 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
513
576
|
telemetry: parsed.telemetry,
|
|
514
577
|
lsp: parsed.lsp
|
|
515
578
|
};
|
|
516
|
-
|
|
579
|
+
const resolvedKey = resolveApiKey({ configApiKey: _config.cloud?.apiKey });
|
|
580
|
+
_resolvedApiKeySource = resolvedKey.source;
|
|
581
|
+
const resolvedEndpoint = resolveEndpoint({ configEndpoint: _config.cloud?.endpoint });
|
|
582
|
+
if (resolvedKey.apiKey) {
|
|
517
583
|
_config.cloud = {
|
|
518
584
|
enabled: true,
|
|
519
585
|
sync: { memory: true, analytics: true, audit: true },
|
|
520
586
|
..._config.cloud,
|
|
521
|
-
apiKey:
|
|
587
|
+
apiKey: resolvedKey.apiKey,
|
|
588
|
+
endpoint: resolvedEndpoint
|
|
522
589
|
};
|
|
590
|
+
} else if (_config.cloud) {
|
|
591
|
+
_config.cloud = { ..._config.cloud, endpoint: _config.cloud.endpoint ?? resolvedEndpoint };
|
|
523
592
|
}
|
|
524
593
|
return _config;
|
|
525
594
|
}
|
|
@@ -528,46 +597,46 @@ function getResolvedPaths() {
|
|
|
528
597
|
const root = getProjectRoot();
|
|
529
598
|
const claudeDirName = config.conventions?.claudeDirName ?? ".claude";
|
|
530
599
|
return {
|
|
531
|
-
codegraphDbPath:
|
|
532
|
-
dataDbPath:
|
|
533
|
-
prismaSchemaPath:
|
|
534
|
-
rootRouterPath:
|
|
535
|
-
routersDir:
|
|
536
|
-
srcDir:
|
|
600
|
+
codegraphDbPath: resolve2(root, ".codegraph/codegraph.db"),
|
|
601
|
+
dataDbPath: resolve2(root, ".massu/data.db"),
|
|
602
|
+
prismaSchemaPath: resolve2(root, config.paths.schema ?? "prisma/schema.prisma"),
|
|
603
|
+
rootRouterPath: resolve2(root, config.paths.routerRoot ?? "src/server/api/root.ts"),
|
|
604
|
+
routersDir: resolve2(root, config.paths.routers ?? "src/server/api/routers"),
|
|
605
|
+
srcDir: resolve2(root, config.paths.source),
|
|
537
606
|
pathAlias: Object.fromEntries(
|
|
538
607
|
Object.entries(config.paths.aliases).map(([alias, target]) => [
|
|
539
608
|
alias,
|
|
540
|
-
|
|
609
|
+
resolve2(root, target)
|
|
541
610
|
])
|
|
542
611
|
),
|
|
543
612
|
extensions: [".ts", ".tsx", ".js", ".jsx"],
|
|
544
613
|
indexFiles: ["index.ts", "index.tsx", "index.js", "index.jsx"],
|
|
545
|
-
patternsDir:
|
|
546
|
-
claudeMdPath:
|
|
547
|
-
docsMapPath:
|
|
548
|
-
helpSitePath:
|
|
549
|
-
memoryDbPath:
|
|
550
|
-
knowledgeDbPath:
|
|
551
|
-
plansDir:
|
|
552
|
-
docsDir:
|
|
553
|
-
claudeDir:
|
|
554
|
-
memoryDir:
|
|
555
|
-
sessionStatePath:
|
|
556
|
-
sessionArchivePath:
|
|
557
|
-
mcpJsonPath:
|
|
558
|
-
settingsLocalPath:
|
|
614
|
+
patternsDir: resolve2(root, claudeDirName, "patterns"),
|
|
615
|
+
claudeMdPath: resolve2(root, claudeDirName, "CLAUDE.md"),
|
|
616
|
+
docsMapPath: resolve2(root, ".massu/docs-map.json"),
|
|
617
|
+
helpSitePath: resolve2(root, "../" + config.project.name + "-help"),
|
|
618
|
+
memoryDbPath: resolve2(root, ".massu/memory.db"),
|
|
619
|
+
knowledgeDbPath: resolve2(root, ".massu/knowledge.db"),
|
|
620
|
+
plansDir: resolve2(root, "docs/plans"),
|
|
621
|
+
docsDir: resolve2(root, "docs"),
|
|
622
|
+
claudeDir: resolve2(root, claudeDirName),
|
|
623
|
+
memoryDir: resolve2(homedir2(), claudeDirName, "projects", encodeMemoryDirName(root), "memory"),
|
|
624
|
+
sessionStatePath: resolve2(root, config.conventions?.sessionStatePath ?? `${claudeDirName}/session-state/CURRENT.md`),
|
|
625
|
+
sessionArchivePath: resolve2(root, config.conventions?.sessionArchivePath ?? `${claudeDirName}/session-state/archive`),
|
|
626
|
+
mcpJsonPath: resolve2(root, ".mcp.json"),
|
|
627
|
+
settingsLocalPath: resolve2(root, claudeDirName, "settings.local.json")
|
|
559
628
|
};
|
|
560
629
|
}
|
|
561
630
|
|
|
562
631
|
// src/memory-db.ts
|
|
563
632
|
import Database from "better-sqlite3";
|
|
564
633
|
import { dirname as dirname2, basename } from "path";
|
|
565
|
-
import { existsSync as
|
|
634
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
566
635
|
function getMemoryDb() {
|
|
567
636
|
const dbPath = getResolvedPaths().memoryDbPath;
|
|
568
637
|
const dir = dirname2(dbPath);
|
|
569
|
-
if (!
|
|
570
|
-
|
|
638
|
+
if (!existsSync3(dir)) {
|
|
639
|
+
mkdirSync2(dir, { recursive: true });
|
|
571
640
|
}
|
|
572
641
|
const db = new Database(dbPath);
|
|
573
642
|
db.pragma("journal_mode = WAL");
|
|
@@ -1303,7 +1372,7 @@ function readFailureContextFiles() {
|
|
|
1303
1372
|
const files = readdirSync(dir).filter((f) => f.startsWith("massu-failure-context-"));
|
|
1304
1373
|
for (const file of files) {
|
|
1305
1374
|
try {
|
|
1306
|
-
context += " " +
|
|
1375
|
+
context += " " + readFileSync3(join(dir, file), "utf-8");
|
|
1307
1376
|
} catch {
|
|
1308
1377
|
}
|
|
1309
1378
|
}
|
|
@@ -1379,12 +1448,12 @@ async function main() {
|
|
|
1379
1448
|
return;
|
|
1380
1449
|
}
|
|
1381
1450
|
const dedupeMarker = getDedupeMarkerPath(hookInput.session_id, filePath);
|
|
1382
|
-
if (
|
|
1451
|
+
if (existsSync4(dedupeMarker)) {
|
|
1383
1452
|
process.exit(0);
|
|
1384
1453
|
return;
|
|
1385
1454
|
}
|
|
1386
1455
|
try {
|
|
1387
|
-
|
|
1456
|
+
writeFileSync2(dedupeMarker, "1");
|
|
1388
1457
|
} catch {
|
|
1389
1458
|
}
|
|
1390
1459
|
const db = getMemoryDb();
|
|
@@ -1447,14 +1516,14 @@ function outputNewPattern(fileName, match) {
|
|
|
1447
1516
|
writeHookMessage(lines.join("\n"));
|
|
1448
1517
|
}
|
|
1449
1518
|
function readStdin() {
|
|
1450
|
-
return new Promise((
|
|
1519
|
+
return new Promise((resolve4) => {
|
|
1451
1520
|
let data = "";
|
|
1452
1521
|
process.stdin.setEncoding("utf-8");
|
|
1453
1522
|
process.stdin.on("data", (chunk) => {
|
|
1454
1523
|
data += chunk;
|
|
1455
1524
|
});
|
|
1456
|
-
process.stdin.on("end", () =>
|
|
1457
|
-
setTimeout(() =>
|
|
1525
|
+
process.stdin.on("end", () => resolve4(data));
|
|
1526
|
+
setTimeout(() => resolve4(data), 3e3);
|
|
1458
1527
|
});
|
|
1459
1528
|
}
|
|
1460
1529
|
main();
|