@massu/core 1.15.1 → 1.15.3
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 +25 -0
- package/dist/cli.js +977 -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
|
@@ -210,17 +210,17 @@ var init_manifest_registry = __esm({
|
|
|
210
210
|
});
|
|
211
211
|
|
|
212
212
|
// src/detect/package-detector.ts
|
|
213
|
-
import { readFileSync as
|
|
213
|
+
import { readFileSync as readFileSync4, existsSync as existsSync5, statSync, lstatSync, readdirSync } from "fs";
|
|
214
214
|
import { join as join2, relative } from "path";
|
|
215
215
|
import { parse as parseToml } from "smol-toml";
|
|
216
216
|
function safeRead(path) {
|
|
217
217
|
try {
|
|
218
|
-
if (!
|
|
218
|
+
if (!existsSync5(path)) return null;
|
|
219
219
|
const ls = lstatSync(path);
|
|
220
220
|
if (ls.isSymbolicLink()) return null;
|
|
221
221
|
const st = statSync(path);
|
|
222
222
|
if (!st.isFile()) return null;
|
|
223
|
-
return
|
|
223
|
+
return readFileSync4(path, "utf-8");
|
|
224
224
|
} catch {
|
|
225
225
|
return null;
|
|
226
226
|
}
|
|
@@ -251,7 +251,7 @@ function parsePackageJson(path, directory, root, warnings) {
|
|
|
251
251
|
const peer = Object.keys(
|
|
252
252
|
pkg.peerDependencies ?? {}
|
|
253
253
|
);
|
|
254
|
-
const hasTs = deps.includes("typescript") || devDeps.includes("typescript") ||
|
|
254
|
+
const hasTs = deps.includes("typescript") || devDeps.includes("typescript") || existsSync5(join2(directory, "tsconfig.json"));
|
|
255
255
|
const language = hasTs ? "typescript" : "javascript";
|
|
256
256
|
const scripts = Object.keys(
|
|
257
257
|
pkg.scripts ?? {}
|
|
@@ -678,7 +678,7 @@ function detectManifestsInDir(dir, root, warnings) {
|
|
|
678
678
|
for (const entry of getManifestRegistry2()) {
|
|
679
679
|
if (!entry.pattern.startsWith("*")) {
|
|
680
680
|
const path = join2(dir, entry.pattern);
|
|
681
|
-
if (!
|
|
681
|
+
if (!existsSync5(path)) continue;
|
|
682
682
|
const m = entry.parse(path, dir, root, warnings);
|
|
683
683
|
if (m !== null) out.push(m);
|
|
684
684
|
} else {
|
|
@@ -692,7 +692,7 @@ function detectManifestsInDir(dir, root, warnings) {
|
|
|
692
692
|
for (const fname of dirEntries) {
|
|
693
693
|
if (!matchManifestPattern2(fname, entry.pattern)) continue;
|
|
694
694
|
const path = join2(dir, fname);
|
|
695
|
-
if (!
|
|
695
|
+
if (!existsSync5(path)) continue;
|
|
696
696
|
const m = entry.parse(path, dir, root, warnings);
|
|
697
697
|
if (m !== null) out.push(m);
|
|
698
698
|
}
|
|
@@ -713,7 +713,7 @@ function detectPackageManifests(projectRoot) {
|
|
|
713
713
|
manifests.push(...detectManifestsInDir(projectRoot, projectRoot, warnings));
|
|
714
714
|
for (const ws of WORKSPACE_DIRS) {
|
|
715
715
|
const wsRoot = join2(projectRoot, ws);
|
|
716
|
-
if (!
|
|
716
|
+
if (!existsSync5(wsRoot)) continue;
|
|
717
717
|
for (const sub of listSubdirs(wsRoot)) {
|
|
718
718
|
manifests.push(...detectManifestsInDir(sub, projectRoot, warnings));
|
|
719
719
|
for (const sub2 of listSubdirs(sub)) {
|
|
@@ -5484,41 +5484,41 @@ var require_queue = __commonJS({
|
|
|
5484
5484
|
queue.drained = drained;
|
|
5485
5485
|
return queue;
|
|
5486
5486
|
function push(value) {
|
|
5487
|
-
var p = new Promise(function(
|
|
5487
|
+
var p = new Promise(function(resolve7, reject) {
|
|
5488
5488
|
pushCb(value, function(err, result) {
|
|
5489
5489
|
if (err) {
|
|
5490
5490
|
reject(err);
|
|
5491
5491
|
return;
|
|
5492
5492
|
}
|
|
5493
|
-
|
|
5493
|
+
resolve7(result);
|
|
5494
5494
|
});
|
|
5495
5495
|
});
|
|
5496
5496
|
p.catch(noop);
|
|
5497
5497
|
return p;
|
|
5498
5498
|
}
|
|
5499
5499
|
function unshift(value) {
|
|
5500
|
-
var p = new Promise(function(
|
|
5500
|
+
var p = new Promise(function(resolve7, reject) {
|
|
5501
5501
|
unshiftCb(value, function(err, result) {
|
|
5502
5502
|
if (err) {
|
|
5503
5503
|
reject(err);
|
|
5504
5504
|
return;
|
|
5505
5505
|
}
|
|
5506
|
-
|
|
5506
|
+
resolve7(result);
|
|
5507
5507
|
});
|
|
5508
5508
|
});
|
|
5509
5509
|
p.catch(noop);
|
|
5510
5510
|
return p;
|
|
5511
5511
|
}
|
|
5512
5512
|
function drained() {
|
|
5513
|
-
var p = new Promise(function(
|
|
5513
|
+
var p = new Promise(function(resolve7) {
|
|
5514
5514
|
process.nextTick(function() {
|
|
5515
5515
|
if (queue.idle()) {
|
|
5516
|
-
|
|
5516
|
+
resolve7();
|
|
5517
5517
|
} else {
|
|
5518
5518
|
var previousDrain = queue.drain;
|
|
5519
5519
|
queue.drain = function() {
|
|
5520
5520
|
if (typeof previousDrain === "function") previousDrain();
|
|
5521
|
-
|
|
5521
|
+
resolve7();
|
|
5522
5522
|
queue.drain = previousDrain;
|
|
5523
5523
|
};
|
|
5524
5524
|
}
|
|
@@ -6004,9 +6004,9 @@ var require_stream3 = __commonJS({
|
|
|
6004
6004
|
});
|
|
6005
6005
|
}
|
|
6006
6006
|
_getStat(filepath) {
|
|
6007
|
-
return new Promise((
|
|
6007
|
+
return new Promise((resolve7, reject) => {
|
|
6008
6008
|
this._stat(filepath, this._fsStatSettings, (error, stats) => {
|
|
6009
|
-
return error === null ?
|
|
6009
|
+
return error === null ? resolve7(stats) : reject(error);
|
|
6010
6010
|
});
|
|
6011
6011
|
});
|
|
6012
6012
|
}
|
|
@@ -6030,10 +6030,10 @@ var require_async5 = __commonJS({
|
|
|
6030
6030
|
this._readerStream = new stream_1.default(this._settings);
|
|
6031
6031
|
}
|
|
6032
6032
|
dynamic(root, options) {
|
|
6033
|
-
return new Promise((
|
|
6033
|
+
return new Promise((resolve7, reject) => {
|
|
6034
6034
|
this._walkAsync(root, options, (error, entries) => {
|
|
6035
6035
|
if (error === null) {
|
|
6036
|
-
|
|
6036
|
+
resolve7(entries);
|
|
6037
6037
|
} else {
|
|
6038
6038
|
reject(error);
|
|
6039
6039
|
}
|
|
@@ -6043,10 +6043,10 @@ var require_async5 = __commonJS({
|
|
|
6043
6043
|
async static(patterns, options) {
|
|
6044
6044
|
const entries = [];
|
|
6045
6045
|
const stream = this._readerStream.static(patterns, options);
|
|
6046
|
-
return new Promise((
|
|
6046
|
+
return new Promise((resolve7, reject) => {
|
|
6047
6047
|
stream.once("error", reject);
|
|
6048
6048
|
stream.on("data", (entry) => entries.push(entry));
|
|
6049
|
-
stream.once("end", () =>
|
|
6049
|
+
stream.once("end", () => resolve7(entries));
|
|
6050
6050
|
});
|
|
6051
6051
|
}
|
|
6052
6052
|
};
|
|
@@ -6705,7 +6705,7 @@ var require_out4 = __commonJS({
|
|
|
6705
6705
|
|
|
6706
6706
|
// src/detect/source-dir-detector.ts
|
|
6707
6707
|
import { realpathSync } from "fs";
|
|
6708
|
-
import { resolve as
|
|
6708
|
+
import { resolve as resolve4 } from "path";
|
|
6709
6709
|
function extsFor(language) {
|
|
6710
6710
|
return EXTENSIONS[language] ?? [];
|
|
6711
6711
|
}
|
|
@@ -6731,7 +6731,7 @@ function topSegment(rel) {
|
|
|
6731
6731
|
function isInsideRoot(root, candidate) {
|
|
6732
6732
|
try {
|
|
6733
6733
|
const realRoot = realpathSync(root);
|
|
6734
|
-
const realCand = realpathSync(
|
|
6734
|
+
const realCand = realpathSync(resolve4(root, candidate));
|
|
6735
6735
|
return realCand === realRoot || realCand.startsWith(realRoot + "/");
|
|
6736
6736
|
} catch {
|
|
6737
6737
|
return false;
|
|
@@ -6899,25 +6899,25 @@ var init_source_dir_detector = __esm({
|
|
|
6899
6899
|
});
|
|
6900
6900
|
|
|
6901
6901
|
// src/detect/monorepo-detector.ts
|
|
6902
|
-
import { readFileSync as
|
|
6902
|
+
import { readFileSync as readFileSync5, existsSync as existsSync6, statSync as statSync2, lstatSync as lstatSync2, readdirSync as readdirSync2 } from "fs";
|
|
6903
6903
|
import { join as join3, relative as relative2 } from "path";
|
|
6904
6904
|
import { parse as parseYaml2 } from "yaml";
|
|
6905
6905
|
import { parse as parseToml2 } from "smol-toml";
|
|
6906
6906
|
function safeReadText(path) {
|
|
6907
6907
|
try {
|
|
6908
|
-
if (!
|
|
6908
|
+
if (!existsSync6(path)) return null;
|
|
6909
6909
|
const ls = lstatSync2(path);
|
|
6910
6910
|
if (ls.isSymbolicLink()) return null;
|
|
6911
6911
|
const st = statSync2(path);
|
|
6912
6912
|
if (!st.isFile()) return null;
|
|
6913
|
-
return
|
|
6913
|
+
return readFileSync5(path, "utf-8");
|
|
6914
6914
|
} catch {
|
|
6915
6915
|
return null;
|
|
6916
6916
|
}
|
|
6917
6917
|
}
|
|
6918
6918
|
function firstManifestIn(dir) {
|
|
6919
6919
|
for (const m of MANIFEST_PRIORITY) {
|
|
6920
|
-
if (
|
|
6920
|
+
if (existsSync6(join3(dir, m))) return m;
|
|
6921
6921
|
}
|
|
6922
6922
|
return null;
|
|
6923
6923
|
}
|
|
@@ -6982,7 +6982,7 @@ function genericWorkspaces(root) {
|
|
|
6982
6982
|
const out = [];
|
|
6983
6983
|
for (const parent of CONVENTIONAL_WORKSPACE_PARENTS) {
|
|
6984
6984
|
const p = join3(root, parent);
|
|
6985
|
-
if (!
|
|
6985
|
+
if (!existsSync6(p)) continue;
|
|
6986
6986
|
for (const sub of listSubdirs2(p)) {
|
|
6987
6987
|
const pkg = pkgFromDir(root, sub);
|
|
6988
6988
|
if (pkg) out.push(pkg);
|
|
@@ -7023,7 +7023,7 @@ function expandWorkspaceGlobs(root, globs) {
|
|
|
7023
7023
|
const parts = pattern.split("/");
|
|
7024
7024
|
if (parts.length === 2 && (parts[1] === "*" || parts[1] === "**")) {
|
|
7025
7025
|
const parent = join3(root, parts[0]);
|
|
7026
|
-
if (!
|
|
7026
|
+
if (!existsSync6(parent)) continue;
|
|
7027
7027
|
for (const sub of listSubdirs2(parent)) {
|
|
7028
7028
|
const pkg = pkgFromDir(root, sub);
|
|
7029
7029
|
if (pkg && !seen.has(pkg.path)) {
|
|
@@ -7034,7 +7034,7 @@ function expandWorkspaceGlobs(root, globs) {
|
|
|
7034
7034
|
continue;
|
|
7035
7035
|
}
|
|
7036
7036
|
const direct = join3(root, pattern);
|
|
7037
|
-
if (
|
|
7037
|
+
if (existsSync6(direct)) {
|
|
7038
7038
|
const pkg = pkgFromDir(root, direct);
|
|
7039
7039
|
if (pkg && !seen.has(pkg.path)) {
|
|
7040
7040
|
seen.add(pkg.path);
|
|
@@ -7045,16 +7045,16 @@ function expandWorkspaceGlobs(root, globs) {
|
|
|
7045
7045
|
return out;
|
|
7046
7046
|
}
|
|
7047
7047
|
function hasTurbo(root) {
|
|
7048
|
-
return
|
|
7048
|
+
return existsSync6(join3(root, "turbo.json"));
|
|
7049
7049
|
}
|
|
7050
7050
|
function hasNx(root) {
|
|
7051
|
-
return
|
|
7051
|
+
return existsSync6(join3(root, "nx.json"));
|
|
7052
7052
|
}
|
|
7053
7053
|
function hasLerna(root) {
|
|
7054
|
-
return
|
|
7054
|
+
return existsSync6(join3(root, "lerna.json"));
|
|
7055
7055
|
}
|
|
7056
7056
|
function hasBazel(root) {
|
|
7057
|
-
return
|
|
7057
|
+
return existsSync6(join3(root, "WORKSPACE")) || existsSync6(join3(root, "WORKSPACE.bazel")) || existsSync6(join3(root, "MODULE.bazel"));
|
|
7058
7058
|
}
|
|
7059
7059
|
function detectMonorepo(projectRoot) {
|
|
7060
7060
|
const nested = [];
|
|
@@ -7245,7 +7245,7 @@ var init_vr_command_map = __esm({
|
|
|
7245
7245
|
});
|
|
7246
7246
|
|
|
7247
7247
|
// src/detect/domain-inferrer.ts
|
|
7248
|
-
import { existsSync as
|
|
7248
|
+
import { existsSync as existsSync7, readdirSync as readdirSync3 } from "fs";
|
|
7249
7249
|
import { join as join4 } from "path";
|
|
7250
7250
|
function titleCase(s) {
|
|
7251
7251
|
if (!s) return s;
|
|
@@ -7267,7 +7267,7 @@ function topLevelSrcSubdirs(root, sourceDirs) {
|
|
|
7267
7267
|
const seen = /* @__PURE__ */ new Set();
|
|
7268
7268
|
for (const rel of effective) {
|
|
7269
7269
|
const abs = join4(root, rel);
|
|
7270
|
-
if (!
|
|
7270
|
+
if (!existsSync7(abs)) continue;
|
|
7271
7271
|
try {
|
|
7272
7272
|
for (const e of readdirSync3(abs, { withFileTypes: true })) {
|
|
7273
7273
|
if (!e.isDirectory()) continue;
|
|
@@ -7354,8 +7354,8 @@ var init_domain_inferrer = __esm({
|
|
|
7354
7354
|
});
|
|
7355
7355
|
|
|
7356
7356
|
// src/detect/regex-fallback.ts
|
|
7357
|
-
import { existsSync as
|
|
7358
|
-
import { resolve as
|
|
7357
|
+
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync6, statSync as statSync3 } from "fs";
|
|
7358
|
+
import { resolve as resolve5, join as join5, basename as basename2 } from "path";
|
|
7359
7359
|
function introspectPython(detection, projectRoot) {
|
|
7360
7360
|
const sourceDir = resolveSourceDir(detection, "python", projectRoot);
|
|
7361
7361
|
if (!sourceDir) return null;
|
|
@@ -7521,10 +7521,10 @@ function resolveSourceDir(detection, lang, projectRoot) {
|
|
|
7521
7521
|
const list = info?.source_dirs ?? [];
|
|
7522
7522
|
if (list.length > 0) {
|
|
7523
7523
|
const first = list[0];
|
|
7524
|
-
const abs =
|
|
7525
|
-
return
|
|
7524
|
+
const abs = resolve5(projectRoot, first);
|
|
7525
|
+
return existsSync8(abs) ? abs : null;
|
|
7526
7526
|
}
|
|
7527
|
-
return
|
|
7527
|
+
return existsSync8(projectRoot) ? projectRoot : null;
|
|
7528
7528
|
}
|
|
7529
7529
|
function sampleFiles(dir, nameRegex, pathFilter) {
|
|
7530
7530
|
const out = [];
|
|
@@ -7569,7 +7569,7 @@ function readSafe(path) {
|
|
|
7569
7569
|
try {
|
|
7570
7570
|
const st = statSync3(path);
|
|
7571
7571
|
if (st.size > MAX_FILE_BYTES) return null;
|
|
7572
|
-
return
|
|
7572
|
+
return readFileSync6(path, "utf-8");
|
|
7573
7573
|
} catch {
|
|
7574
7574
|
return null;
|
|
7575
7575
|
}
|
|
@@ -7946,12 +7946,12 @@ var init_drift = __esm({
|
|
|
7946
7946
|
// src/memory-db.ts
|
|
7947
7947
|
import Database from "better-sqlite3";
|
|
7948
7948
|
import { dirname as dirname2, basename } from "path";
|
|
7949
|
-
import { existsSync as
|
|
7949
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
7950
7950
|
|
|
7951
7951
|
// src/config.ts
|
|
7952
|
-
import { resolve, dirname } from "path";
|
|
7953
|
-
import { existsSync, readFileSync } from "fs";
|
|
7954
|
-
import { homedir } from "os";
|
|
7952
|
+
import { resolve as resolve2, dirname } from "path";
|
|
7953
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
7954
|
+
import { homedir as homedir2 } from "os";
|
|
7955
7955
|
import { parse as parseYaml } from "yaml";
|
|
7956
7956
|
import { z } from "zod";
|
|
7957
7957
|
|
|
@@ -7960,6 +7960,68 @@ function encodeMemoryDirName(projectRoot) {
|
|
|
7960
7960
|
return projectRoot.replace(/\//g, "-");
|
|
7961
7961
|
}
|
|
7962
7962
|
|
|
7963
|
+
// src/credentials.ts
|
|
7964
|
+
import { homedir } from "os";
|
|
7965
|
+
import { resolve } from "path";
|
|
7966
|
+
import {
|
|
7967
|
+
existsSync,
|
|
7968
|
+
readFileSync,
|
|
7969
|
+
writeFileSync,
|
|
7970
|
+
mkdirSync,
|
|
7971
|
+
rmSync,
|
|
7972
|
+
chmodSync
|
|
7973
|
+
} from "fs";
|
|
7974
|
+
var MASSU_ENV_API_KEY = "MASSU_API_KEY";
|
|
7975
|
+
var MASSU_ENV_CLOUD_ENDPOINT = "MASSU_CLOUD_ENDPOINT";
|
|
7976
|
+
var DEFAULT_CLOUD_ENDPOINT = "https://api.massu.ai/v1";
|
|
7977
|
+
function credentialsDir(home = homedir()) {
|
|
7978
|
+
return resolve(home, ".massu");
|
|
7979
|
+
}
|
|
7980
|
+
function credentialsPath(home = homedir()) {
|
|
7981
|
+
return resolve(credentialsDir(home), "credentials");
|
|
7982
|
+
}
|
|
7983
|
+
function readUserCredentials(home = homedir()) {
|
|
7984
|
+
try {
|
|
7985
|
+
const p = credentialsPath(home);
|
|
7986
|
+
if (!existsSync(p)) return void 0;
|
|
7987
|
+
const parsed = JSON.parse(readFileSync(p, "utf-8"));
|
|
7988
|
+
const key = typeof parsed?.apiKey === "string" ? parsed.apiKey.trim() : "";
|
|
7989
|
+
return key.length > 0 ? key : void 0;
|
|
7990
|
+
} catch {
|
|
7991
|
+
return void 0;
|
|
7992
|
+
}
|
|
7993
|
+
}
|
|
7994
|
+
function isUnresolvedLiteral(v) {
|
|
7995
|
+
return /^\$\{[^}]+\}$/.test(v);
|
|
7996
|
+
}
|
|
7997
|
+
function resolveApiKey(opts = {}) {
|
|
7998
|
+
const env = opts.env ?? process.env;
|
|
7999
|
+
const home = opts.home ?? homedir();
|
|
8000
|
+
const cfg = typeof opts.configApiKey === "string" ? opts.configApiKey.trim() : "";
|
|
8001
|
+
if (cfg.length > 0 && !isUnresolvedLiteral(cfg)) {
|
|
8002
|
+
return { apiKey: cfg, source: "config" };
|
|
8003
|
+
}
|
|
8004
|
+
const envRaw = env[MASSU_ENV_API_KEY];
|
|
8005
|
+
const envKey = typeof envRaw === "string" ? envRaw.trim() : "";
|
|
8006
|
+
if (envKey.length > 0) {
|
|
8007
|
+
return { apiKey: envKey, source: "env" };
|
|
8008
|
+
}
|
|
8009
|
+
const fileKey = readUserCredentials(home);
|
|
8010
|
+
if (fileKey) {
|
|
8011
|
+
return { apiKey: fileKey, source: "user-file" };
|
|
8012
|
+
}
|
|
8013
|
+
return { source: "none" };
|
|
8014
|
+
}
|
|
8015
|
+
function resolveEndpoint(opts = {}) {
|
|
8016
|
+
const env = opts.env ?? process.env;
|
|
8017
|
+
const cfg = typeof opts.configEndpoint === "string" ? opts.configEndpoint.trim() : "";
|
|
8018
|
+
if (cfg.length > 0) return cfg;
|
|
8019
|
+
const envRaw = env[MASSU_ENV_CLOUD_ENDPOINT];
|
|
8020
|
+
const envEp = typeof envRaw === "string" ? envRaw.trim() : "";
|
|
8021
|
+
if (envEp.length > 0) return envEp;
|
|
8022
|
+
return DEFAULT_CLOUD_ENDPOINT;
|
|
8023
|
+
}
|
|
8024
|
+
|
|
7963
8025
|
// src/config.ts
|
|
7964
8026
|
var DomainConfigSchema = z.object({
|
|
7965
8027
|
name: z.string().default("Unknown"),
|
|
@@ -8342,12 +8404,13 @@ var RawConfigSchema = z.object({
|
|
|
8342
8404
|
lsp: LSPConfigSchema.optional()
|
|
8343
8405
|
}).passthrough();
|
|
8344
8406
|
var _config = null;
|
|
8407
|
+
var _resolvedApiKeySource = "none";
|
|
8345
8408
|
var _projectRoot = null;
|
|
8346
8409
|
function findProjectRoot() {
|
|
8347
8410
|
const cwd = process.cwd();
|
|
8348
8411
|
let dir = cwd;
|
|
8349
8412
|
while (true) {
|
|
8350
|
-
if (
|
|
8413
|
+
if (existsSync2(resolve2(dir, "massu.config.yaml"))) {
|
|
8351
8414
|
return dir;
|
|
8352
8415
|
}
|
|
8353
8416
|
const parent = dirname(dir);
|
|
@@ -8356,10 +8419,10 @@ function findProjectRoot() {
|
|
|
8356
8419
|
}
|
|
8357
8420
|
dir = cwd;
|
|
8358
8421
|
while (true) {
|
|
8359
|
-
if (
|
|
8422
|
+
if (existsSync2(resolve2(dir, "package.json"))) {
|
|
8360
8423
|
return dir;
|
|
8361
8424
|
}
|
|
8362
|
-
if (
|
|
8425
|
+
if (existsSync2(resolve2(dir, ".git"))) {
|
|
8363
8426
|
return dir;
|
|
8364
8427
|
}
|
|
8365
8428
|
const parent = dirname(dir);
|
|
@@ -8377,10 +8440,10 @@ function getProjectRoot() {
|
|
|
8377
8440
|
function getConfig() {
|
|
8378
8441
|
if (_config) return _config;
|
|
8379
8442
|
const root = getProjectRoot();
|
|
8380
|
-
const configPath =
|
|
8443
|
+
const configPath = resolve2(root, "massu.config.yaml");
|
|
8381
8444
|
let rawYaml = {};
|
|
8382
|
-
if (
|
|
8383
|
-
const content =
|
|
8445
|
+
if (existsSync2(configPath)) {
|
|
8446
|
+
const content = readFileSync2(configPath, "utf-8");
|
|
8384
8447
|
rawYaml = parseYaml(content) ?? {};
|
|
8385
8448
|
}
|
|
8386
8449
|
const result = RawConfigSchema.safeParse(rawYaml);
|
|
@@ -8397,7 +8460,7 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
8397
8460
|
);
|
|
8398
8461
|
}
|
|
8399
8462
|
const parsed = result.data;
|
|
8400
|
-
const projectRoot = parsed.project.root === "auto" || !parsed.project.root ? root :
|
|
8463
|
+
const projectRoot = parsed.project.root === "auto" || !parsed.project.root ? root : resolve2(root, parsed.project.root);
|
|
8401
8464
|
const fw = parsed.framework;
|
|
8402
8465
|
let router = fw.router;
|
|
8403
8466
|
let orm = fw.orm;
|
|
@@ -8455,13 +8518,19 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
8455
8518
|
telemetry: parsed.telemetry,
|
|
8456
8519
|
lsp: parsed.lsp
|
|
8457
8520
|
};
|
|
8458
|
-
|
|
8521
|
+
const resolvedKey = resolveApiKey({ configApiKey: _config.cloud?.apiKey });
|
|
8522
|
+
_resolvedApiKeySource = resolvedKey.source;
|
|
8523
|
+
const resolvedEndpoint = resolveEndpoint({ configEndpoint: _config.cloud?.endpoint });
|
|
8524
|
+
if (resolvedKey.apiKey) {
|
|
8459
8525
|
_config.cloud = {
|
|
8460
8526
|
enabled: true,
|
|
8461
8527
|
sync: { memory: true, analytics: true, audit: true },
|
|
8462
8528
|
..._config.cloud,
|
|
8463
|
-
apiKey:
|
|
8529
|
+
apiKey: resolvedKey.apiKey,
|
|
8530
|
+
endpoint: resolvedEndpoint
|
|
8464
8531
|
};
|
|
8532
|
+
} else if (_config.cloud) {
|
|
8533
|
+
_config.cloud = { ..._config.cloud, endpoint: _config.cloud.endpoint ?? resolvedEndpoint };
|
|
8465
8534
|
}
|
|
8466
8535
|
return _config;
|
|
8467
8536
|
}
|
|
@@ -8470,34 +8539,34 @@ function getResolvedPaths() {
|
|
|
8470
8539
|
const root = getProjectRoot();
|
|
8471
8540
|
const claudeDirName = config.conventions?.claudeDirName ?? ".claude";
|
|
8472
8541
|
return {
|
|
8473
|
-
codegraphDbPath:
|
|
8474
|
-
dataDbPath:
|
|
8475
|
-
prismaSchemaPath:
|
|
8476
|
-
rootRouterPath:
|
|
8477
|
-
routersDir:
|
|
8478
|
-
srcDir:
|
|
8542
|
+
codegraphDbPath: resolve2(root, ".codegraph/codegraph.db"),
|
|
8543
|
+
dataDbPath: resolve2(root, ".massu/data.db"),
|
|
8544
|
+
prismaSchemaPath: resolve2(root, config.paths.schema ?? "prisma/schema.prisma"),
|
|
8545
|
+
rootRouterPath: resolve2(root, config.paths.routerRoot ?? "src/server/api/root.ts"),
|
|
8546
|
+
routersDir: resolve2(root, config.paths.routers ?? "src/server/api/routers"),
|
|
8547
|
+
srcDir: resolve2(root, config.paths.source),
|
|
8479
8548
|
pathAlias: Object.fromEntries(
|
|
8480
8549
|
Object.entries(config.paths.aliases).map(([alias, target]) => [
|
|
8481
8550
|
alias,
|
|
8482
|
-
|
|
8551
|
+
resolve2(root, target)
|
|
8483
8552
|
])
|
|
8484
8553
|
),
|
|
8485
8554
|
extensions: [".ts", ".tsx", ".js", ".jsx"],
|
|
8486
8555
|
indexFiles: ["index.ts", "index.tsx", "index.js", "index.jsx"],
|
|
8487
|
-
patternsDir:
|
|
8488
|
-
claudeMdPath:
|
|
8489
|
-
docsMapPath:
|
|
8490
|
-
helpSitePath:
|
|
8491
|
-
memoryDbPath:
|
|
8492
|
-
knowledgeDbPath:
|
|
8493
|
-
plansDir:
|
|
8494
|
-
docsDir:
|
|
8495
|
-
claudeDir:
|
|
8496
|
-
memoryDir:
|
|
8497
|
-
sessionStatePath:
|
|
8498
|
-
sessionArchivePath:
|
|
8499
|
-
mcpJsonPath:
|
|
8500
|
-
settingsLocalPath:
|
|
8556
|
+
patternsDir: resolve2(root, claudeDirName, "patterns"),
|
|
8557
|
+
claudeMdPath: resolve2(root, claudeDirName, "CLAUDE.md"),
|
|
8558
|
+
docsMapPath: resolve2(root, ".massu/docs-map.json"),
|
|
8559
|
+
helpSitePath: resolve2(root, "../" + config.project.name + "-help"),
|
|
8560
|
+
memoryDbPath: resolve2(root, ".massu/memory.db"),
|
|
8561
|
+
knowledgeDbPath: resolve2(root, ".massu/knowledge.db"),
|
|
8562
|
+
plansDir: resolve2(root, "docs/plans"),
|
|
8563
|
+
docsDir: resolve2(root, "docs"),
|
|
8564
|
+
claudeDir: resolve2(root, claudeDirName),
|
|
8565
|
+
memoryDir: resolve2(homedir2(), claudeDirName, "projects", encodeMemoryDirName(root), "memory"),
|
|
8566
|
+
sessionStatePath: resolve2(root, config.conventions?.sessionStatePath ?? `${claudeDirName}/session-state/CURRENT.md`),
|
|
8567
|
+
sessionArchivePath: resolve2(root, config.conventions?.sessionArchivePath ?? `${claudeDirName}/session-state/archive`),
|
|
8568
|
+
mcpJsonPath: resolve2(root, ".mcp.json"),
|
|
8569
|
+
settingsLocalPath: resolve2(root, claudeDirName, "settings.local.json")
|
|
8501
8570
|
};
|
|
8502
8571
|
}
|
|
8503
8572
|
|
|
@@ -8511,8 +8580,8 @@ function sanitizeFts5Query(raw) {
|
|
|
8511
8580
|
function getMemoryDb() {
|
|
8512
8581
|
const dbPath = getResolvedPaths().memoryDbPath;
|
|
8513
8582
|
const dir = dirname2(dbPath);
|
|
8514
|
-
if (!
|
|
8515
|
-
|
|
8583
|
+
if (!existsSync3(dir)) {
|
|
8584
|
+
mkdirSync2(dir, { recursive: true });
|
|
8516
8585
|
}
|
|
8517
8586
|
const db = new Database(dbPath);
|
|
8518
8587
|
db.pragma("journal_mode = WAL");
|
|
@@ -9237,7 +9306,7 @@ function linkSessionToTask(db, sessionId, taskId) {
|
|
|
9237
9306
|
}
|
|
9238
9307
|
|
|
9239
9308
|
// src/team-rule-sync.ts
|
|
9240
|
-
import { existsSync as
|
|
9309
|
+
import { existsSync as existsSync4, writeFileSync as writeFileSync2, unlinkSync, mkdirSync as mkdirSync3 } from "fs";
|
|
9241
9310
|
import { join, dirname as dirname3 } from "path";
|
|
9242
9311
|
|
|
9243
9312
|
// src/license.ts
|
|
@@ -9583,7 +9652,7 @@ async function pullTeamPromotions(db, opts = {}) {
|
|
|
9583
9652
|
result.revoked_handled += 1;
|
|
9584
9653
|
continue;
|
|
9585
9654
|
}
|
|
9586
|
-
if (
|
|
9655
|
+
if (existsSync4(candidatePath) || alreadyApplied(db, p.prompt_hash)) {
|
|
9587
9656
|
result.skipped += 1;
|
|
9588
9657
|
continue;
|
|
9589
9658
|
}
|
|
@@ -9633,7 +9702,7 @@ function alreadyApplied(db, promptHash) {
|
|
|
9633
9702
|
}
|
|
9634
9703
|
}
|
|
9635
9704
|
function handleRevocation(db, projectRoot, candidatePath, promptHash) {
|
|
9636
|
-
if (
|
|
9705
|
+
if (existsSync4(candidatePath)) {
|
|
9637
9706
|
try {
|
|
9638
9707
|
unlinkSync(candidatePath);
|
|
9639
9708
|
} catch {
|
|
@@ -9682,8 +9751,8 @@ function materializeCandidate(db, projectRoot, candidatePath, p, orgId) {
|
|
|
9682
9751
|
...p.review_attestation !== void 0 ? { publisher_review_attestation: p.review_attestation } : {}
|
|
9683
9752
|
};
|
|
9684
9753
|
const dir = dirname3(candidatePath);
|
|
9685
|
-
if (!
|
|
9686
|
-
|
|
9754
|
+
if (!existsSync4(dir)) mkdirSync3(dir, { recursive: true });
|
|
9755
|
+
writeFileSync2(candidatePath, JSON.stringify(sidecar, null, 2), "utf-8");
|
|
9687
9756
|
try {
|
|
9688
9757
|
shareObservation(db, p.promoted_by, getProjectName(), "rule_promotion", promptText, {
|
|
9689
9758
|
filePath: void 0,
|
|
@@ -9727,8 +9796,8 @@ function emitDropTelemetry(db, eventType, data) {
|
|
|
9727
9796
|
}
|
|
9728
9797
|
|
|
9729
9798
|
// src/hooks/session-start.ts
|
|
9730
|
-
import { readFileSync as
|
|
9731
|
-
import { join as join6, resolve as
|
|
9799
|
+
import { readFileSync as readFileSync7, existsSync as existsSync9 } from "fs";
|
|
9800
|
+
import { join as join6, resolve as resolve6 } from "path";
|
|
9732
9801
|
import { parse as parseYaml3 } from "yaml";
|
|
9733
9802
|
|
|
9734
9803
|
// src/lib/pidLiveness.ts
|
|
@@ -9900,7 +9969,7 @@ async function buildContext(db, sessionId, source, tokenBudget, taskId) {
|
|
|
9900
9969
|
}
|
|
9901
9970
|
try {
|
|
9902
9971
|
const knowledgeDbPath = getResolvedPaths().knowledgeDbPath;
|
|
9903
|
-
if (
|
|
9972
|
+
if (existsSync9(knowledgeDbPath)) {
|
|
9904
9973
|
const Database2 = (await import("better-sqlite3")).default;
|
|
9905
9974
|
const kdb = new Database2(knowledgeDbPath, { readonly: true });
|
|
9906
9975
|
try {
|
|
@@ -9976,23 +10045,23 @@ async function getGitBranch() {
|
|
|
9976
10045
|
}
|
|
9977
10046
|
}
|
|
9978
10047
|
function readStdin() {
|
|
9979
|
-
return new Promise((
|
|
10048
|
+
return new Promise((resolve7) => {
|
|
9980
10049
|
let data = "";
|
|
9981
10050
|
process.stdin.setEncoding("utf-8");
|
|
9982
10051
|
process.stdin.on("data", (chunk) => {
|
|
9983
10052
|
data += chunk;
|
|
9984
10053
|
});
|
|
9985
|
-
process.stdin.on("end", () =>
|
|
9986
|
-
setTimeout(() =>
|
|
10054
|
+
process.stdin.on("end", () => resolve7(data));
|
|
10055
|
+
setTimeout(() => resolve7(data), 3e3);
|
|
9987
10056
|
});
|
|
9988
10057
|
}
|
|
9989
10058
|
async function buildDriftBanner() {
|
|
9990
10059
|
try {
|
|
9991
10060
|
if (process.env.MASSU_DRIFT_QUIET === "1") return "";
|
|
9992
10061
|
if (watcherIsLiveAndFresh()) return "";
|
|
9993
|
-
const configPath =
|
|
9994
|
-
if (!
|
|
9995
|
-
const content =
|
|
10062
|
+
const configPath = resolve6(process.cwd(), "massu.config.yaml");
|
|
10063
|
+
if (!existsSync9(configPath)) return "";
|
|
10064
|
+
const content = readFileSync7(configPath, "utf-8");
|
|
9996
10065
|
const parsed = parseYaml3(content);
|
|
9997
10066
|
if (!parsed || typeof parsed !== "object") return "";
|
|
9998
10067
|
const det = parsed.detection;
|
|
@@ -10033,8 +10102,8 @@ function loadCorrectionsPreventionRules() {
|
|
|
10033
10102
|
const claudeDirName = config.conventions?.claudeDirName ?? ".claude";
|
|
10034
10103
|
const projectDirName = cwd.replace(/[/\\]/g, "-").replace(/^-/, "");
|
|
10035
10104
|
const correctionsPath = join6(homeDir, claudeDirName, "projects", projectDirName, "memory", "corrections.md");
|
|
10036
|
-
if (!
|
|
10037
|
-
const content =
|
|
10105
|
+
if (!existsSync9(correctionsPath)) return [];
|
|
10106
|
+
const content = readFileSync7(correctionsPath, "utf-8");
|
|
10038
10107
|
const lines = content.split("\n");
|
|
10039
10108
|
const rules = [];
|
|
10040
10109
|
for (const line of lines) {
|
|
@@ -10055,9 +10124,9 @@ function loadCorrectionsPreventionRules() {
|
|
|
10055
10124
|
}
|
|
10056
10125
|
function readWatchStateRaw(cwd) {
|
|
10057
10126
|
try {
|
|
10058
|
-
const path =
|
|
10059
|
-
if (!
|
|
10060
|
-
const obj = JSON.parse(
|
|
10127
|
+
const path = resolve6(cwd, ".massu", "watch-state.json");
|
|
10128
|
+
if (!existsSync9(path)) return null;
|
|
10129
|
+
const obj = JSON.parse(readFileSync7(path, "utf-8"));
|
|
10061
10130
|
if (!obj || typeof obj !== "object") return null;
|
|
10062
10131
|
return obj;
|
|
10063
10132
|
} catch {
|