@massu/core 1.15.1 → 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 +13 -0
- package/dist/cli.js +900 -572
- 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 +165 -96
- package/dist/hooks/user-prompt.js +124 -55
- package/package.json +1 -1
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
import{createRequire as __cr}from"module";const require=__cr(import.meta.url);
|
|
3
3
|
|
|
4
4
|
// src/hooks/incident-pipeline.ts
|
|
5
|
-
import { existsSync as
|
|
6
|
-
import { basename as basename2, resolve as
|
|
5
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync } from "fs";
|
|
6
|
+
import { basename as basename2, resolve as resolve4 } from "path";
|
|
7
7
|
|
|
8
8
|
// src/config.ts
|
|
9
|
-
import { resolve, dirname } from "path";
|
|
10
|
-
import { existsSync, readFileSync } from "fs";
|
|
11
|
-
import { homedir } from "os";
|
|
9
|
+
import { resolve as resolve2, dirname } from "path";
|
|
10
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
11
|
+
import { homedir as homedir2 } from "os";
|
|
12
12
|
import { parse as parseYaml } from "yaml";
|
|
13
13
|
import { z } from "zod";
|
|
14
14
|
|
|
@@ -17,6 +17,68 @@ function encodeMemoryDirName(projectRoot) {
|
|
|
17
17
|
return projectRoot.replace(/\//g, "-");
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
// src/credentials.ts
|
|
21
|
+
import { homedir } from "os";
|
|
22
|
+
import { resolve } from "path";
|
|
23
|
+
import {
|
|
24
|
+
existsSync,
|
|
25
|
+
readFileSync,
|
|
26
|
+
writeFileSync,
|
|
27
|
+
mkdirSync,
|
|
28
|
+
rmSync,
|
|
29
|
+
chmodSync
|
|
30
|
+
} from "fs";
|
|
31
|
+
var MASSU_ENV_API_KEY = "MASSU_API_KEY";
|
|
32
|
+
var MASSU_ENV_CLOUD_ENDPOINT = "MASSU_CLOUD_ENDPOINT";
|
|
33
|
+
var DEFAULT_CLOUD_ENDPOINT = "https://api.massu.ai/v1";
|
|
34
|
+
function credentialsDir(home = homedir()) {
|
|
35
|
+
return resolve(home, ".massu");
|
|
36
|
+
}
|
|
37
|
+
function credentialsPath(home = homedir()) {
|
|
38
|
+
return resolve(credentialsDir(home), "credentials");
|
|
39
|
+
}
|
|
40
|
+
function readUserCredentials(home = homedir()) {
|
|
41
|
+
try {
|
|
42
|
+
const p = credentialsPath(home);
|
|
43
|
+
if (!existsSync(p)) return void 0;
|
|
44
|
+
const parsed = JSON.parse(readFileSync(p, "utf-8"));
|
|
45
|
+
const key = typeof parsed?.apiKey === "string" ? parsed.apiKey.trim() : "";
|
|
46
|
+
return key.length > 0 ? key : void 0;
|
|
47
|
+
} catch {
|
|
48
|
+
return void 0;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function isUnresolvedLiteral(v) {
|
|
52
|
+
return /^\$\{[^}]+\}$/.test(v);
|
|
53
|
+
}
|
|
54
|
+
function resolveApiKey(opts = {}) {
|
|
55
|
+
const env = opts.env ?? process.env;
|
|
56
|
+
const home = opts.home ?? homedir();
|
|
57
|
+
const cfg = typeof opts.configApiKey === "string" ? opts.configApiKey.trim() : "";
|
|
58
|
+
if (cfg.length > 0 && !isUnresolvedLiteral(cfg)) {
|
|
59
|
+
return { apiKey: cfg, source: "config" };
|
|
60
|
+
}
|
|
61
|
+
const envRaw = env[MASSU_ENV_API_KEY];
|
|
62
|
+
const envKey = typeof envRaw === "string" ? envRaw.trim() : "";
|
|
63
|
+
if (envKey.length > 0) {
|
|
64
|
+
return { apiKey: envKey, source: "env" };
|
|
65
|
+
}
|
|
66
|
+
const fileKey = readUserCredentials(home);
|
|
67
|
+
if (fileKey) {
|
|
68
|
+
return { apiKey: fileKey, source: "user-file" };
|
|
69
|
+
}
|
|
70
|
+
return { source: "none" };
|
|
71
|
+
}
|
|
72
|
+
function resolveEndpoint(opts = {}) {
|
|
73
|
+
const env = opts.env ?? process.env;
|
|
74
|
+
const cfg = typeof opts.configEndpoint === "string" ? opts.configEndpoint.trim() : "";
|
|
75
|
+
if (cfg.length > 0) return cfg;
|
|
76
|
+
const envRaw = env[MASSU_ENV_CLOUD_ENDPOINT];
|
|
77
|
+
const envEp = typeof envRaw === "string" ? envRaw.trim() : "";
|
|
78
|
+
if (envEp.length > 0) return envEp;
|
|
79
|
+
return DEFAULT_CLOUD_ENDPOINT;
|
|
80
|
+
}
|
|
81
|
+
|
|
20
82
|
// src/config.ts
|
|
21
83
|
var DomainConfigSchema = z.object({
|
|
22
84
|
name: z.string().default("Unknown"),
|
|
@@ -399,12 +461,13 @@ var RawConfigSchema = z.object({
|
|
|
399
461
|
lsp: LSPConfigSchema.optional()
|
|
400
462
|
}).passthrough();
|
|
401
463
|
var _config = null;
|
|
464
|
+
var _resolvedApiKeySource = "none";
|
|
402
465
|
var _projectRoot = null;
|
|
403
466
|
function findProjectRoot() {
|
|
404
467
|
const cwd = process.cwd();
|
|
405
468
|
let dir = cwd;
|
|
406
469
|
while (true) {
|
|
407
|
-
if (
|
|
470
|
+
if (existsSync2(resolve2(dir, "massu.config.yaml"))) {
|
|
408
471
|
return dir;
|
|
409
472
|
}
|
|
410
473
|
const parent = dirname(dir);
|
|
@@ -413,10 +476,10 @@ function findProjectRoot() {
|
|
|
413
476
|
}
|
|
414
477
|
dir = cwd;
|
|
415
478
|
while (true) {
|
|
416
|
-
if (
|
|
479
|
+
if (existsSync2(resolve2(dir, "package.json"))) {
|
|
417
480
|
return dir;
|
|
418
481
|
}
|
|
419
|
-
if (
|
|
482
|
+
if (existsSync2(resolve2(dir, ".git"))) {
|
|
420
483
|
return dir;
|
|
421
484
|
}
|
|
422
485
|
const parent = dirname(dir);
|
|
@@ -434,10 +497,10 @@ function getProjectRoot() {
|
|
|
434
497
|
function getConfig() {
|
|
435
498
|
if (_config) return _config;
|
|
436
499
|
const root = getProjectRoot();
|
|
437
|
-
const configPath =
|
|
500
|
+
const configPath = resolve2(root, "massu.config.yaml");
|
|
438
501
|
let rawYaml = {};
|
|
439
|
-
if (
|
|
440
|
-
const content =
|
|
502
|
+
if (existsSync2(configPath)) {
|
|
503
|
+
const content = readFileSync2(configPath, "utf-8");
|
|
441
504
|
rawYaml = parseYaml(content) ?? {};
|
|
442
505
|
}
|
|
443
506
|
const result = RawConfigSchema.safeParse(rawYaml);
|
|
@@ -454,7 +517,7 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
454
517
|
);
|
|
455
518
|
}
|
|
456
519
|
const parsed = result.data;
|
|
457
|
-
const projectRoot = parsed.project.root === "auto" || !parsed.project.root ? root :
|
|
520
|
+
const projectRoot = parsed.project.root === "auto" || !parsed.project.root ? root : resolve2(root, parsed.project.root);
|
|
458
521
|
const fw = parsed.framework;
|
|
459
522
|
let router = fw.router;
|
|
460
523
|
let orm = fw.orm;
|
|
@@ -512,13 +575,19 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
512
575
|
telemetry: parsed.telemetry,
|
|
513
576
|
lsp: parsed.lsp
|
|
514
577
|
};
|
|
515
|
-
|
|
578
|
+
const resolvedKey = resolveApiKey({ configApiKey: _config.cloud?.apiKey });
|
|
579
|
+
_resolvedApiKeySource = resolvedKey.source;
|
|
580
|
+
const resolvedEndpoint = resolveEndpoint({ configEndpoint: _config.cloud?.endpoint });
|
|
581
|
+
if (resolvedKey.apiKey) {
|
|
516
582
|
_config.cloud = {
|
|
517
583
|
enabled: true,
|
|
518
584
|
sync: { memory: true, analytics: true, audit: true },
|
|
519
585
|
..._config.cloud,
|
|
520
|
-
apiKey:
|
|
586
|
+
apiKey: resolvedKey.apiKey,
|
|
587
|
+
endpoint: resolvedEndpoint
|
|
521
588
|
};
|
|
589
|
+
} else if (_config.cloud) {
|
|
590
|
+
_config.cloud = { ..._config.cloud, endpoint: _config.cloud.endpoint ?? resolvedEndpoint };
|
|
522
591
|
}
|
|
523
592
|
return _config;
|
|
524
593
|
}
|
|
@@ -527,46 +596,46 @@ function getResolvedPaths() {
|
|
|
527
596
|
const root = getProjectRoot();
|
|
528
597
|
const claudeDirName = config.conventions?.claudeDirName ?? ".claude";
|
|
529
598
|
return {
|
|
530
|
-
codegraphDbPath:
|
|
531
|
-
dataDbPath:
|
|
532
|
-
prismaSchemaPath:
|
|
533
|
-
rootRouterPath:
|
|
534
|
-
routersDir:
|
|
535
|
-
srcDir:
|
|
599
|
+
codegraphDbPath: resolve2(root, ".codegraph/codegraph.db"),
|
|
600
|
+
dataDbPath: resolve2(root, ".massu/data.db"),
|
|
601
|
+
prismaSchemaPath: resolve2(root, config.paths.schema ?? "prisma/schema.prisma"),
|
|
602
|
+
rootRouterPath: resolve2(root, config.paths.routerRoot ?? "src/server/api/root.ts"),
|
|
603
|
+
routersDir: resolve2(root, config.paths.routers ?? "src/server/api/routers"),
|
|
604
|
+
srcDir: resolve2(root, config.paths.source),
|
|
536
605
|
pathAlias: Object.fromEntries(
|
|
537
606
|
Object.entries(config.paths.aliases).map(([alias, target]) => [
|
|
538
607
|
alias,
|
|
539
|
-
|
|
608
|
+
resolve2(root, target)
|
|
540
609
|
])
|
|
541
610
|
),
|
|
542
611
|
extensions: [".ts", ".tsx", ".js", ".jsx"],
|
|
543
612
|
indexFiles: ["index.ts", "index.tsx", "index.js", "index.jsx"],
|
|
544
|
-
patternsDir:
|
|
545
|
-
claudeMdPath:
|
|
546
|
-
docsMapPath:
|
|
547
|
-
helpSitePath:
|
|
548
|
-
memoryDbPath:
|
|
549
|
-
knowledgeDbPath:
|
|
550
|
-
plansDir:
|
|
551
|
-
docsDir:
|
|
552
|
-
claudeDir:
|
|
553
|
-
memoryDir:
|
|
554
|
-
sessionStatePath:
|
|
555
|
-
sessionArchivePath:
|
|
556
|
-
mcpJsonPath:
|
|
557
|
-
settingsLocalPath:
|
|
613
|
+
patternsDir: resolve2(root, claudeDirName, "patterns"),
|
|
614
|
+
claudeMdPath: resolve2(root, claudeDirName, "CLAUDE.md"),
|
|
615
|
+
docsMapPath: resolve2(root, ".massu/docs-map.json"),
|
|
616
|
+
helpSitePath: resolve2(root, "../" + config.project.name + "-help"),
|
|
617
|
+
memoryDbPath: resolve2(root, ".massu/memory.db"),
|
|
618
|
+
knowledgeDbPath: resolve2(root, ".massu/knowledge.db"),
|
|
619
|
+
plansDir: resolve2(root, "docs/plans"),
|
|
620
|
+
docsDir: resolve2(root, "docs"),
|
|
621
|
+
claudeDir: resolve2(root, claudeDirName),
|
|
622
|
+
memoryDir: resolve2(homedir2(), claudeDirName, "projects", encodeMemoryDirName(root), "memory"),
|
|
623
|
+
sessionStatePath: resolve2(root, config.conventions?.sessionStatePath ?? `${claudeDirName}/session-state/CURRENT.md`),
|
|
624
|
+
sessionArchivePath: resolve2(root, config.conventions?.sessionArchivePath ?? `${claudeDirName}/session-state/archive`),
|
|
625
|
+
mcpJsonPath: resolve2(root, ".mcp.json"),
|
|
626
|
+
settingsLocalPath: resolve2(root, claudeDirName, "settings.local.json")
|
|
558
627
|
};
|
|
559
628
|
}
|
|
560
629
|
|
|
561
630
|
// src/memory-db.ts
|
|
562
631
|
import Database from "better-sqlite3";
|
|
563
632
|
import { dirname as dirname2, basename } from "path";
|
|
564
|
-
import { existsSync as
|
|
633
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
565
634
|
function getMemoryDb() {
|
|
566
635
|
const dbPath = getResolvedPaths().memoryDbPath;
|
|
567
636
|
const dir = dirname2(dbPath);
|
|
568
|
-
if (!
|
|
569
|
-
|
|
637
|
+
if (!existsSync3(dir)) {
|
|
638
|
+
mkdirSync2(dir, { recursive: true });
|
|
570
639
|
}
|
|
571
640
|
const db = new Database(dbPath);
|
|
572
641
|
db.pragma("journal_mode = WAL");
|
|
@@ -1328,17 +1397,17 @@ async function main() {
|
|
|
1328
1397
|
process.exit(0);
|
|
1329
1398
|
return;
|
|
1330
1399
|
}
|
|
1331
|
-
if (!
|
|
1400
|
+
if (!existsSync4(filePath)) {
|
|
1332
1401
|
process.exit(0);
|
|
1333
1402
|
return;
|
|
1334
1403
|
}
|
|
1335
|
-
const content =
|
|
1404
|
+
const content = readFileSync3(filePath, "utf-8");
|
|
1336
1405
|
const titleMatch = content.match(/^#\s+(.+)/m);
|
|
1337
1406
|
const title = titleMatch?.[1] ?? basename2(filePath, ".md");
|
|
1338
1407
|
const slug = basename2(filePath, ".md").replace(/^\d{4}-\d{2}-\d{2}-?/, "").toLowerCase();
|
|
1339
|
-
const memoryDirAbs =
|
|
1408
|
+
const memoryDirAbs = resolve4(root, memoryDir);
|
|
1340
1409
|
let hasExistingRule = false;
|
|
1341
|
-
if (
|
|
1410
|
+
if (existsSync4(memoryDirAbs)) {
|
|
1342
1411
|
const ruleFiles = readdirSync(memoryDirAbs).filter((f) => f.startsWith("feedback_"));
|
|
1343
1412
|
for (const ruleFile of ruleFiles) {
|
|
1344
1413
|
if (ruleFile.toLowerCase().includes(slug.slice(0, 20))) {
|
|
@@ -1421,14 +1490,14 @@ async function main() {
|
|
|
1421
1490
|
process.exit(0);
|
|
1422
1491
|
}
|
|
1423
1492
|
function readStdin() {
|
|
1424
|
-
return new Promise((
|
|
1493
|
+
return new Promise((resolve5) => {
|
|
1425
1494
|
let data = "";
|
|
1426
1495
|
process.stdin.setEncoding("utf-8");
|
|
1427
1496
|
process.stdin.on("data", (chunk) => {
|
|
1428
1497
|
data += chunk;
|
|
1429
1498
|
});
|
|
1430
|
-
process.stdin.on("end", () =>
|
|
1431
|
-
setTimeout(() =>
|
|
1499
|
+
process.stdin.on("end", () => resolve5(data));
|
|
1500
|
+
setTimeout(() => resolve5(data), 3e3);
|
|
1432
1501
|
});
|
|
1433
1502
|
}
|
|
1434
1503
|
main();
|
|
@@ -5,9 +5,9 @@ import{createRequire as __cr}from"module";const require=__cr(import.meta.url);
|
|
|
5
5
|
import Database from "better-sqlite3";
|
|
6
6
|
|
|
7
7
|
// src/config.ts
|
|
8
|
-
import { resolve, dirname } from "path";
|
|
9
|
-
import { existsSync, readFileSync } from "fs";
|
|
10
|
-
import { homedir } from "os";
|
|
8
|
+
import { resolve as resolve2, dirname } from "path";
|
|
9
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
10
|
+
import { homedir as homedir2 } from "os";
|
|
11
11
|
import { parse as parseYaml } from "yaml";
|
|
12
12
|
import { z } from "zod";
|
|
13
13
|
|
|
@@ -16,6 +16,68 @@ function encodeMemoryDirName(projectRoot) {
|
|
|
16
16
|
return projectRoot.replace(/\//g, "-");
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
// src/credentials.ts
|
|
20
|
+
import { homedir } from "os";
|
|
21
|
+
import { resolve } from "path";
|
|
22
|
+
import {
|
|
23
|
+
existsSync,
|
|
24
|
+
readFileSync,
|
|
25
|
+
writeFileSync,
|
|
26
|
+
mkdirSync,
|
|
27
|
+
rmSync,
|
|
28
|
+
chmodSync
|
|
29
|
+
} from "fs";
|
|
30
|
+
var MASSU_ENV_API_KEY = "MASSU_API_KEY";
|
|
31
|
+
var MASSU_ENV_CLOUD_ENDPOINT = "MASSU_CLOUD_ENDPOINT";
|
|
32
|
+
var DEFAULT_CLOUD_ENDPOINT = "https://api.massu.ai/v1";
|
|
33
|
+
function credentialsDir(home = homedir()) {
|
|
34
|
+
return resolve(home, ".massu");
|
|
35
|
+
}
|
|
36
|
+
function credentialsPath(home = homedir()) {
|
|
37
|
+
return resolve(credentialsDir(home), "credentials");
|
|
38
|
+
}
|
|
39
|
+
function readUserCredentials(home = homedir()) {
|
|
40
|
+
try {
|
|
41
|
+
const p = credentialsPath(home);
|
|
42
|
+
if (!existsSync(p)) return void 0;
|
|
43
|
+
const parsed = JSON.parse(readFileSync(p, "utf-8"));
|
|
44
|
+
const key = typeof parsed?.apiKey === "string" ? parsed.apiKey.trim() : "";
|
|
45
|
+
return key.length > 0 ? key : void 0;
|
|
46
|
+
} catch {
|
|
47
|
+
return void 0;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function isUnresolvedLiteral(v) {
|
|
51
|
+
return /^\$\{[^}]+\}$/.test(v);
|
|
52
|
+
}
|
|
53
|
+
function resolveApiKey(opts = {}) {
|
|
54
|
+
const env = opts.env ?? process.env;
|
|
55
|
+
const home = opts.home ?? homedir();
|
|
56
|
+
const cfg = typeof opts.configApiKey === "string" ? opts.configApiKey.trim() : "";
|
|
57
|
+
if (cfg.length > 0 && !isUnresolvedLiteral(cfg)) {
|
|
58
|
+
return { apiKey: cfg, source: "config" };
|
|
59
|
+
}
|
|
60
|
+
const envRaw = env[MASSU_ENV_API_KEY];
|
|
61
|
+
const envKey = typeof envRaw === "string" ? envRaw.trim() : "";
|
|
62
|
+
if (envKey.length > 0) {
|
|
63
|
+
return { apiKey: envKey, source: "env" };
|
|
64
|
+
}
|
|
65
|
+
const fileKey = readUserCredentials(home);
|
|
66
|
+
if (fileKey) {
|
|
67
|
+
return { apiKey: fileKey, source: "user-file" };
|
|
68
|
+
}
|
|
69
|
+
return { source: "none" };
|
|
70
|
+
}
|
|
71
|
+
function resolveEndpoint(opts = {}) {
|
|
72
|
+
const env = opts.env ?? process.env;
|
|
73
|
+
const cfg = typeof opts.configEndpoint === "string" ? opts.configEndpoint.trim() : "";
|
|
74
|
+
if (cfg.length > 0) return cfg;
|
|
75
|
+
const envRaw = env[MASSU_ENV_CLOUD_ENDPOINT];
|
|
76
|
+
const envEp = typeof envRaw === "string" ? envRaw.trim() : "";
|
|
77
|
+
if (envEp.length > 0) return envEp;
|
|
78
|
+
return DEFAULT_CLOUD_ENDPOINT;
|
|
79
|
+
}
|
|
80
|
+
|
|
19
81
|
// src/config.ts
|
|
20
82
|
var DomainConfigSchema = z.object({
|
|
21
83
|
name: z.string().default("Unknown"),
|
|
@@ -398,12 +460,13 @@ var RawConfigSchema = z.object({
|
|
|
398
460
|
lsp: LSPConfigSchema.optional()
|
|
399
461
|
}).passthrough();
|
|
400
462
|
var _config = null;
|
|
463
|
+
var _resolvedApiKeySource = "none";
|
|
401
464
|
var _projectRoot = null;
|
|
402
465
|
function findProjectRoot() {
|
|
403
466
|
const cwd = process.cwd();
|
|
404
467
|
let dir = cwd;
|
|
405
468
|
while (true) {
|
|
406
|
-
if (
|
|
469
|
+
if (existsSync2(resolve2(dir, "massu.config.yaml"))) {
|
|
407
470
|
return dir;
|
|
408
471
|
}
|
|
409
472
|
const parent = dirname(dir);
|
|
@@ -412,10 +475,10 @@ function findProjectRoot() {
|
|
|
412
475
|
}
|
|
413
476
|
dir = cwd;
|
|
414
477
|
while (true) {
|
|
415
|
-
if (
|
|
478
|
+
if (existsSync2(resolve2(dir, "package.json"))) {
|
|
416
479
|
return dir;
|
|
417
480
|
}
|
|
418
|
-
if (
|
|
481
|
+
if (existsSync2(resolve2(dir, ".git"))) {
|
|
419
482
|
return dir;
|
|
420
483
|
}
|
|
421
484
|
const parent = dirname(dir);
|
|
@@ -433,10 +496,10 @@ function getProjectRoot() {
|
|
|
433
496
|
function getConfig() {
|
|
434
497
|
if (_config) return _config;
|
|
435
498
|
const root = getProjectRoot();
|
|
436
|
-
const configPath =
|
|
499
|
+
const configPath = resolve2(root, "massu.config.yaml");
|
|
437
500
|
let rawYaml = {};
|
|
438
|
-
if (
|
|
439
|
-
const content =
|
|
501
|
+
if (existsSync2(configPath)) {
|
|
502
|
+
const content = readFileSync2(configPath, "utf-8");
|
|
440
503
|
rawYaml = parseYaml(content) ?? {};
|
|
441
504
|
}
|
|
442
505
|
const result = RawConfigSchema.safeParse(rawYaml);
|
|
@@ -453,7 +516,7 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
453
516
|
);
|
|
454
517
|
}
|
|
455
518
|
const parsed = result.data;
|
|
456
|
-
const projectRoot = parsed.project.root === "auto" || !parsed.project.root ? root :
|
|
519
|
+
const projectRoot = parsed.project.root === "auto" || !parsed.project.root ? root : resolve2(root, parsed.project.root);
|
|
457
520
|
const fw = parsed.framework;
|
|
458
521
|
let router = fw.router;
|
|
459
522
|
let orm = fw.orm;
|
|
@@ -511,13 +574,19 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
511
574
|
telemetry: parsed.telemetry,
|
|
512
575
|
lsp: parsed.lsp
|
|
513
576
|
};
|
|
514
|
-
|
|
577
|
+
const resolvedKey = resolveApiKey({ configApiKey: _config.cloud?.apiKey });
|
|
578
|
+
_resolvedApiKeySource = resolvedKey.source;
|
|
579
|
+
const resolvedEndpoint = resolveEndpoint({ configEndpoint: _config.cloud?.endpoint });
|
|
580
|
+
if (resolvedKey.apiKey) {
|
|
515
581
|
_config.cloud = {
|
|
516
582
|
enabled: true,
|
|
517
583
|
sync: { memory: true, analytics: true, audit: true },
|
|
518
584
|
..._config.cloud,
|
|
519
|
-
apiKey:
|
|
585
|
+
apiKey: resolvedKey.apiKey,
|
|
586
|
+
endpoint: resolvedEndpoint
|
|
520
587
|
};
|
|
588
|
+
} else if (_config.cloud) {
|
|
589
|
+
_config.cloud = { ..._config.cloud, endpoint: _config.cloud.endpoint ?? resolvedEndpoint };
|
|
521
590
|
}
|
|
522
591
|
return _config;
|
|
523
592
|
}
|
|
@@ -526,34 +595,34 @@ function getResolvedPaths() {
|
|
|
526
595
|
const root = getProjectRoot();
|
|
527
596
|
const claudeDirName = config.conventions?.claudeDirName ?? ".claude";
|
|
528
597
|
return {
|
|
529
|
-
codegraphDbPath:
|
|
530
|
-
dataDbPath:
|
|
531
|
-
prismaSchemaPath:
|
|
532
|
-
rootRouterPath:
|
|
533
|
-
routersDir:
|
|
534
|
-
srcDir:
|
|
598
|
+
codegraphDbPath: resolve2(root, ".codegraph/codegraph.db"),
|
|
599
|
+
dataDbPath: resolve2(root, ".massu/data.db"),
|
|
600
|
+
prismaSchemaPath: resolve2(root, config.paths.schema ?? "prisma/schema.prisma"),
|
|
601
|
+
rootRouterPath: resolve2(root, config.paths.routerRoot ?? "src/server/api/root.ts"),
|
|
602
|
+
routersDir: resolve2(root, config.paths.routers ?? "src/server/api/routers"),
|
|
603
|
+
srcDir: resolve2(root, config.paths.source),
|
|
535
604
|
pathAlias: Object.fromEntries(
|
|
536
605
|
Object.entries(config.paths.aliases).map(([alias, target]) => [
|
|
537
606
|
alias,
|
|
538
|
-
|
|
607
|
+
resolve2(root, target)
|
|
539
608
|
])
|
|
540
609
|
),
|
|
541
610
|
extensions: [".ts", ".tsx", ".js", ".jsx"],
|
|
542
611
|
indexFiles: ["index.ts", "index.tsx", "index.js", "index.jsx"],
|
|
543
|
-
patternsDir:
|
|
544
|
-
claudeMdPath:
|
|
545
|
-
docsMapPath:
|
|
546
|
-
helpSitePath:
|
|
547
|
-
memoryDbPath:
|
|
548
|
-
knowledgeDbPath:
|
|
549
|
-
plansDir:
|
|
550
|
-
docsDir:
|
|
551
|
-
claudeDir:
|
|
552
|
-
memoryDir:
|
|
553
|
-
sessionStatePath:
|
|
554
|
-
sessionArchivePath:
|
|
555
|
-
mcpJsonPath:
|
|
556
|
-
settingsLocalPath:
|
|
612
|
+
patternsDir: resolve2(root, claudeDirName, "patterns"),
|
|
613
|
+
claudeMdPath: resolve2(root, claudeDirName, "CLAUDE.md"),
|
|
614
|
+
docsMapPath: resolve2(root, ".massu/docs-map.json"),
|
|
615
|
+
helpSitePath: resolve2(root, "../" + config.project.name + "-help"),
|
|
616
|
+
memoryDbPath: resolve2(root, ".massu/memory.db"),
|
|
617
|
+
knowledgeDbPath: resolve2(root, ".massu/knowledge.db"),
|
|
618
|
+
plansDir: resolve2(root, "docs/plans"),
|
|
619
|
+
docsDir: resolve2(root, "docs"),
|
|
620
|
+
claudeDir: resolve2(root, claudeDirName),
|
|
621
|
+
memoryDir: resolve2(homedir2(), claudeDirName, "projects", encodeMemoryDirName(root), "memory"),
|
|
622
|
+
sessionStatePath: resolve2(root, config.conventions?.sessionStatePath ?? `${claudeDirName}/session-state/CURRENT.md`),
|
|
623
|
+
sessionArchivePath: resolve2(root, config.conventions?.sessionArchivePath ?? `${claudeDirName}/session-state/archive`),
|
|
624
|
+
mcpJsonPath: resolve2(root, ".mcp.json"),
|
|
625
|
+
settingsLocalPath: resolve2(root, claudeDirName, "settings.local.json")
|
|
557
626
|
};
|
|
558
627
|
}
|
|
559
628
|
|
|
@@ -635,14 +704,14 @@ async function main() {
|
|
|
635
704
|
process.exit(0);
|
|
636
705
|
}
|
|
637
706
|
function readStdin() {
|
|
638
|
-
return new Promise((
|
|
707
|
+
return new Promise((resolve3) => {
|
|
639
708
|
let data = "";
|
|
640
709
|
process.stdin.setEncoding("utf-8");
|
|
641
710
|
process.stdin.on("data", (chunk) => {
|
|
642
711
|
data += chunk;
|
|
643
712
|
});
|
|
644
|
-
process.stdin.on("end", () =>
|
|
645
|
-
setTimeout(() =>
|
|
713
|
+
process.stdin.on("end", () => resolve3(data));
|
|
714
|
+
setTimeout(() => resolve3(data), 3e3);
|
|
646
715
|
});
|
|
647
716
|
}
|
|
648
717
|
main();
|