@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
package/dist/cli.js
CHANGED
|
@@ -58,17 +58,136 @@ var init_memory_path = __esm({
|
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
// src/
|
|
62
|
-
import { resolve, dirname } from "path";
|
|
63
|
-
import { existsSync, readFileSync } from "fs";
|
|
61
|
+
// src/credentials.ts
|
|
64
62
|
import { homedir } from "os";
|
|
63
|
+
import { resolve } from "path";
|
|
64
|
+
import {
|
|
65
|
+
existsSync,
|
|
66
|
+
readFileSync,
|
|
67
|
+
writeFileSync,
|
|
68
|
+
mkdirSync,
|
|
69
|
+
rmSync,
|
|
70
|
+
chmodSync
|
|
71
|
+
} from "fs";
|
|
72
|
+
function credentialsDir(home = homedir()) {
|
|
73
|
+
return resolve(home, ".massu");
|
|
74
|
+
}
|
|
75
|
+
function credentialsPath(home = homedir()) {
|
|
76
|
+
return resolve(credentialsDir(home), "credentials");
|
|
77
|
+
}
|
|
78
|
+
function readUserCredentials(home = homedir()) {
|
|
79
|
+
try {
|
|
80
|
+
const p19 = credentialsPath(home);
|
|
81
|
+
if (!existsSync(p19)) return void 0;
|
|
82
|
+
const parsed = JSON.parse(readFileSync(p19, "utf-8"));
|
|
83
|
+
const key = typeof parsed?.apiKey === "string" ? parsed.apiKey.trim() : "";
|
|
84
|
+
return key.length > 0 ? key : void 0;
|
|
85
|
+
} catch {
|
|
86
|
+
return void 0;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function writeUserCredentials(apiKey, home = homedir()) {
|
|
90
|
+
const dir = credentialsDir(home);
|
|
91
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
92
|
+
try {
|
|
93
|
+
chmodSync(dir, 448);
|
|
94
|
+
} catch {
|
|
95
|
+
}
|
|
96
|
+
const p19 = credentialsPath(home);
|
|
97
|
+
writeFileSync(p19, JSON.stringify({ apiKey: apiKey.trim() }, null, 2) + "\n", {
|
|
98
|
+
mode: 384
|
|
99
|
+
});
|
|
100
|
+
try {
|
|
101
|
+
chmodSync(p19, 384);
|
|
102
|
+
} catch {
|
|
103
|
+
}
|
|
104
|
+
return p19;
|
|
105
|
+
}
|
|
106
|
+
function removeUserCredentials(home = homedir()) {
|
|
107
|
+
const p19 = credentialsPath(home);
|
|
108
|
+
if (!existsSync(p19)) return false;
|
|
109
|
+
try {
|
|
110
|
+
rmSync(p19);
|
|
111
|
+
return true;
|
|
112
|
+
} catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function isUnresolvedLiteral(v3) {
|
|
117
|
+
return /^\$\{[^}]+\}$/.test(v3);
|
|
118
|
+
}
|
|
119
|
+
function resolveApiKey(opts = {}) {
|
|
120
|
+
const env = opts.env ?? process.env;
|
|
121
|
+
const home = opts.home ?? homedir();
|
|
122
|
+
const cfg = typeof opts.configApiKey === "string" ? opts.configApiKey.trim() : "";
|
|
123
|
+
if (cfg.length > 0 && !isUnresolvedLiteral(cfg)) {
|
|
124
|
+
return { apiKey: cfg, source: "config" };
|
|
125
|
+
}
|
|
126
|
+
const envRaw = env[MASSU_ENV_API_KEY];
|
|
127
|
+
const envKey = typeof envRaw === "string" ? envRaw.trim() : "";
|
|
128
|
+
if (envKey.length > 0) {
|
|
129
|
+
return { apiKey: envKey, source: "env" };
|
|
130
|
+
}
|
|
131
|
+
const fileKey = readUserCredentials(home);
|
|
132
|
+
if (fileKey) {
|
|
133
|
+
return { apiKey: fileKey, source: "user-file" };
|
|
134
|
+
}
|
|
135
|
+
return { source: "none" };
|
|
136
|
+
}
|
|
137
|
+
function resolveEndpoint(opts = {}) {
|
|
138
|
+
const env = opts.env ?? process.env;
|
|
139
|
+
const cfg = typeof opts.configEndpoint === "string" ? opts.configEndpoint.trim() : "";
|
|
140
|
+
if (cfg.length > 0) return cfg;
|
|
141
|
+
const envRaw = env[MASSU_ENV_CLOUD_ENDPOINT];
|
|
142
|
+
const envEp = typeof envRaw === "string" ? envRaw.trim() : "";
|
|
143
|
+
if (envEp.length > 0) return envEp;
|
|
144
|
+
return DEFAULT_CLOUD_ENDPOINT;
|
|
145
|
+
}
|
|
146
|
+
function apiKeySourceLabel(source) {
|
|
147
|
+
switch (source) {
|
|
148
|
+
case "config":
|
|
149
|
+
return "explicit cloud.apiKey";
|
|
150
|
+
case "env":
|
|
151
|
+
return "MASSU_API_KEY env";
|
|
152
|
+
case "user-file":
|
|
153
|
+
return "~/.massu/credentials";
|
|
154
|
+
case "none":
|
|
155
|
+
default:
|
|
156
|
+
return "no source";
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
var MASSU_ENV_API_KEY, MASSU_ENV_CLOUD_ENDPOINT, DEFAULT_CLOUD_ENDPOINT, API_KEY_PREFIX;
|
|
160
|
+
var init_credentials = __esm({
|
|
161
|
+
"src/credentials.ts"() {
|
|
162
|
+
"use strict";
|
|
163
|
+
MASSU_ENV_API_KEY = "MASSU_API_KEY";
|
|
164
|
+
MASSU_ENV_CLOUD_ENDPOINT = "MASSU_CLOUD_ENDPOINT";
|
|
165
|
+
DEFAULT_CLOUD_ENDPOINT = "https://api.massu.ai/v1";
|
|
166
|
+
API_KEY_PREFIX = "ms_live_";
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// src/config.ts
|
|
171
|
+
var config_exports = {};
|
|
172
|
+
__export(config_exports, {
|
|
173
|
+
AdapterLocalPathSchema: () => AdapterLocalPathSchema,
|
|
174
|
+
LSPConfigSchema: () => LSPConfigSchema,
|
|
175
|
+
getConfig: () => getConfig,
|
|
176
|
+
getProjectRoot: () => getProjectRoot,
|
|
177
|
+
getResolvedApiKeySource: () => getResolvedApiKeySource,
|
|
178
|
+
getResolvedPaths: () => getResolvedPaths,
|
|
179
|
+
resetConfig: () => resetConfig
|
|
180
|
+
});
|
|
181
|
+
import { resolve as resolve2, dirname } from "path";
|
|
182
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
183
|
+
import { homedir as homedir2 } from "os";
|
|
65
184
|
import { parse as parseYaml } from "yaml";
|
|
66
185
|
import { z } from "zod";
|
|
67
186
|
function findProjectRoot() {
|
|
68
187
|
const cwd = process.cwd();
|
|
69
188
|
let dir = cwd;
|
|
70
189
|
while (true) {
|
|
71
|
-
if (
|
|
190
|
+
if (existsSync2(resolve2(dir, "massu.config.yaml"))) {
|
|
72
191
|
return dir;
|
|
73
192
|
}
|
|
74
193
|
const parent = dirname(dir);
|
|
@@ -77,10 +196,10 @@ function findProjectRoot() {
|
|
|
77
196
|
}
|
|
78
197
|
dir = cwd;
|
|
79
198
|
while (true) {
|
|
80
|
-
if (
|
|
199
|
+
if (existsSync2(resolve2(dir, "package.json"))) {
|
|
81
200
|
return dir;
|
|
82
201
|
}
|
|
83
|
-
if (
|
|
202
|
+
if (existsSync2(resolve2(dir, ".git"))) {
|
|
84
203
|
return dir;
|
|
85
204
|
}
|
|
86
205
|
const parent = dirname(dir);
|
|
@@ -98,10 +217,10 @@ function getProjectRoot() {
|
|
|
98
217
|
function getConfig() {
|
|
99
218
|
if (_config) return _config;
|
|
100
219
|
const root = getProjectRoot();
|
|
101
|
-
const configPath =
|
|
220
|
+
const configPath = resolve2(root, "massu.config.yaml");
|
|
102
221
|
let rawYaml = {};
|
|
103
|
-
if (
|
|
104
|
-
const content =
|
|
222
|
+
if (existsSync2(configPath)) {
|
|
223
|
+
const content = readFileSync2(configPath, "utf-8");
|
|
105
224
|
rawYaml = parseYaml(content) ?? {};
|
|
106
225
|
}
|
|
107
226
|
const result = RawConfigSchema.safeParse(rawYaml);
|
|
@@ -118,7 +237,7 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
118
237
|
);
|
|
119
238
|
}
|
|
120
239
|
const parsed = result.data;
|
|
121
|
-
const projectRoot = parsed.project.root === "auto" || !parsed.project.root ? root :
|
|
240
|
+
const projectRoot = parsed.project.root === "auto" || !parsed.project.root ? root : resolve2(root, parsed.project.root);
|
|
122
241
|
const fw = parsed.framework;
|
|
123
242
|
let router = fw.router;
|
|
124
243
|
let orm = fw.orm;
|
|
@@ -176,60 +295,72 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
176
295
|
telemetry: parsed.telemetry,
|
|
177
296
|
lsp: parsed.lsp
|
|
178
297
|
};
|
|
179
|
-
|
|
298
|
+
const resolvedKey = resolveApiKey({ configApiKey: _config.cloud?.apiKey });
|
|
299
|
+
_resolvedApiKeySource = resolvedKey.source;
|
|
300
|
+
const resolvedEndpoint = resolveEndpoint({ configEndpoint: _config.cloud?.endpoint });
|
|
301
|
+
if (resolvedKey.apiKey) {
|
|
180
302
|
_config.cloud = {
|
|
181
303
|
enabled: true,
|
|
182
304
|
sync: { memory: true, analytics: true, audit: true },
|
|
183
305
|
..._config.cloud,
|
|
184
|
-
apiKey:
|
|
306
|
+
apiKey: resolvedKey.apiKey,
|
|
307
|
+
endpoint: resolvedEndpoint
|
|
185
308
|
};
|
|
309
|
+
} else if (_config.cloud) {
|
|
310
|
+
_config.cloud = { ..._config.cloud, endpoint: _config.cloud.endpoint ?? resolvedEndpoint };
|
|
186
311
|
}
|
|
187
312
|
return _config;
|
|
188
313
|
}
|
|
314
|
+
function getResolvedApiKeySource() {
|
|
315
|
+
getConfig();
|
|
316
|
+
return _resolvedApiKeySource;
|
|
317
|
+
}
|
|
189
318
|
function getResolvedPaths() {
|
|
190
319
|
const config = getConfig();
|
|
191
320
|
const root = getProjectRoot();
|
|
192
321
|
const claudeDirName = config.conventions?.claudeDirName ?? ".claude";
|
|
193
322
|
return {
|
|
194
|
-
codegraphDbPath:
|
|
195
|
-
dataDbPath:
|
|
196
|
-
prismaSchemaPath:
|
|
197
|
-
rootRouterPath:
|
|
198
|
-
routersDir:
|
|
199
|
-
srcDir:
|
|
323
|
+
codegraphDbPath: resolve2(root, ".codegraph/codegraph.db"),
|
|
324
|
+
dataDbPath: resolve2(root, ".massu/data.db"),
|
|
325
|
+
prismaSchemaPath: resolve2(root, config.paths.schema ?? "prisma/schema.prisma"),
|
|
326
|
+
rootRouterPath: resolve2(root, config.paths.routerRoot ?? "src/server/api/root.ts"),
|
|
327
|
+
routersDir: resolve2(root, config.paths.routers ?? "src/server/api/routers"),
|
|
328
|
+
srcDir: resolve2(root, config.paths.source),
|
|
200
329
|
pathAlias: Object.fromEntries(
|
|
201
330
|
Object.entries(config.paths.aliases).map(([alias, target]) => [
|
|
202
331
|
alias,
|
|
203
|
-
|
|
332
|
+
resolve2(root, target)
|
|
204
333
|
])
|
|
205
334
|
),
|
|
206
335
|
extensions: [".ts", ".tsx", ".js", ".jsx"],
|
|
207
336
|
indexFiles: ["index.ts", "index.tsx", "index.js", "index.jsx"],
|
|
208
|
-
patternsDir:
|
|
209
|
-
claudeMdPath:
|
|
210
|
-
docsMapPath:
|
|
211
|
-
helpSitePath:
|
|
212
|
-
memoryDbPath:
|
|
213
|
-
knowledgeDbPath:
|
|
214
|
-
plansDir:
|
|
215
|
-
docsDir:
|
|
216
|
-
claudeDir:
|
|
217
|
-
memoryDir:
|
|
218
|
-
sessionStatePath:
|
|
219
|
-
sessionArchivePath:
|
|
220
|
-
mcpJsonPath:
|
|
221
|
-
settingsLocalPath:
|
|
337
|
+
patternsDir: resolve2(root, claudeDirName, "patterns"),
|
|
338
|
+
claudeMdPath: resolve2(root, claudeDirName, "CLAUDE.md"),
|
|
339
|
+
docsMapPath: resolve2(root, ".massu/docs-map.json"),
|
|
340
|
+
helpSitePath: resolve2(root, "../" + config.project.name + "-help"),
|
|
341
|
+
memoryDbPath: resolve2(root, ".massu/memory.db"),
|
|
342
|
+
knowledgeDbPath: resolve2(root, ".massu/knowledge.db"),
|
|
343
|
+
plansDir: resolve2(root, "docs/plans"),
|
|
344
|
+
docsDir: resolve2(root, "docs"),
|
|
345
|
+
claudeDir: resolve2(root, claudeDirName),
|
|
346
|
+
memoryDir: resolve2(homedir2(), claudeDirName, "projects", encodeMemoryDirName(root), "memory"),
|
|
347
|
+
sessionStatePath: resolve2(root, config.conventions?.sessionStatePath ?? `${claudeDirName}/session-state/CURRENT.md`),
|
|
348
|
+
sessionArchivePath: resolve2(root, config.conventions?.sessionArchivePath ?? `${claudeDirName}/session-state/archive`),
|
|
349
|
+
mcpJsonPath: resolve2(root, ".mcp.json"),
|
|
350
|
+
settingsLocalPath: resolve2(root, claudeDirName, "settings.local.json")
|
|
222
351
|
};
|
|
223
352
|
}
|
|
224
353
|
function resetConfig() {
|
|
225
354
|
_config = null;
|
|
226
355
|
_projectRoot = null;
|
|
356
|
+
_resolvedApiKeySource = "none";
|
|
227
357
|
}
|
|
228
|
-
var DomainConfigSchema, PatternRuleConfigSchema, CostModelSchema, AnalyticsConfigSchema, CustomPatternSchema, GovernanceConfigSchema, SecurityPatternSchema, SecurityConfigSchema, TeamConfigSchema, RegressionConfigSchema, AutoLearningConfigSchema, CloudConfigSchema, ConventionsConfigSchema, PythonDomainConfigSchema, PythonConfigSchema, PathsConfigSchema, LanguageFrameworkEntrySchema, FrameworkConfigSchema, DetectedConfigSchema, VerificationEntrySchema, VerificationConfigSchema, CanonicalPathsSchema, VerificationTypesSchema, DetectionRuleEntrySchema, DetectionConfigSchema, WatchConfigSchema, AdapterLocalPathSchema, AdaptersConfigSchema, TelemetryConfigSchema, LSPConfigSchema, RawConfigSchema, _config, _projectRoot;
|
|
358
|
+
var DomainConfigSchema, PatternRuleConfigSchema, CostModelSchema, AnalyticsConfigSchema, CustomPatternSchema, GovernanceConfigSchema, SecurityPatternSchema, SecurityConfigSchema, TeamConfigSchema, RegressionConfigSchema, AutoLearningConfigSchema, CloudConfigSchema, ConventionsConfigSchema, PythonDomainConfigSchema, PythonConfigSchema, PathsConfigSchema, LanguageFrameworkEntrySchema, FrameworkConfigSchema, DetectedConfigSchema, VerificationEntrySchema, VerificationConfigSchema, CanonicalPathsSchema, VerificationTypesSchema, DetectionRuleEntrySchema, DetectionConfigSchema, WatchConfigSchema, AdapterLocalPathSchema, AdaptersConfigSchema, TelemetryConfigSchema, LSPConfigSchema, RawConfigSchema, _config, _resolvedApiKeySource, _projectRoot;
|
|
229
359
|
var init_config = __esm({
|
|
230
360
|
"src/config.ts"() {
|
|
231
361
|
"use strict";
|
|
232
362
|
init_memory_path();
|
|
363
|
+
init_credentials();
|
|
233
364
|
DomainConfigSchema = z.object({
|
|
234
365
|
name: z.string().default("Unknown"),
|
|
235
366
|
routers: z.array(z.string()).default([]),
|
|
@@ -611,6 +742,7 @@ var init_config = __esm({
|
|
|
611
742
|
lsp: LSPConfigSchema.optional()
|
|
612
743
|
}).passthrough();
|
|
613
744
|
_config = null;
|
|
745
|
+
_resolvedApiKeySource = "none";
|
|
614
746
|
_projectRoot = null;
|
|
615
747
|
}
|
|
616
748
|
});
|
|
@@ -673,7 +805,7 @@ __export(memory_db_exports, {
|
|
|
673
805
|
});
|
|
674
806
|
import Database from "better-sqlite3";
|
|
675
807
|
import { dirname as dirname2, basename } from "path";
|
|
676
|
-
import { existsSync as
|
|
808
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
677
809
|
function sanitizeFts5Query(raw) {
|
|
678
810
|
const trimmed = raw.trim();
|
|
679
811
|
if (!trimmed) return '""';
|
|
@@ -683,8 +815,8 @@ function sanitizeFts5Query(raw) {
|
|
|
683
815
|
function getMemoryDb() {
|
|
684
816
|
const dbPath = getResolvedPaths().memoryDbPath;
|
|
685
817
|
const dir = dirname2(dbPath);
|
|
686
|
-
if (!
|
|
687
|
-
|
|
818
|
+
if (!existsSync3(dir)) {
|
|
819
|
+
mkdirSync2(dir, { recursive: true });
|
|
688
820
|
}
|
|
689
821
|
const db = new Database(dbPath);
|
|
690
822
|
db.pragma("journal_mode = WAL");
|
|
@@ -2017,12 +2149,12 @@ var init_memory_db = __esm({
|
|
|
2017
2149
|
});
|
|
2018
2150
|
|
|
2019
2151
|
// src/memory-file-ingest.ts
|
|
2020
|
-
import { readFileSync as
|
|
2152
|
+
import { readFileSync as readFileSync3, existsSync as existsSync4, readdirSync } from "fs";
|
|
2021
2153
|
import { join } from "path";
|
|
2022
2154
|
import { parse as parseYaml2 } from "yaml";
|
|
2023
2155
|
function ingestMemoryFile(db, sessionId, filePath) {
|
|
2024
|
-
if (!
|
|
2025
|
-
const content =
|
|
2156
|
+
if (!existsSync4(filePath)) return "skipped";
|
|
2157
|
+
const content = readFileSync3(filePath, "utf-8");
|
|
2026
2158
|
const basename11 = (filePath.split("/").pop() ?? "").replace(".md", "");
|
|
2027
2159
|
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
2028
2160
|
let name = basename11;
|
|
@@ -2060,7 +2192,7 @@ ${body}` : body;
|
|
|
2060
2192
|
}
|
|
2061
2193
|
function backfillMemoryFiles(db, memoryDir, sessionId) {
|
|
2062
2194
|
const stats = { inserted: 0, updated: 0, skipped: 0, total: 0 };
|
|
2063
|
-
if (!
|
|
2195
|
+
if (!existsSync4(memoryDir)) return stats;
|
|
2064
2196
|
const files = readdirSync(memoryDir).filter(
|
|
2065
2197
|
(f2) => f2.endsWith(".md") && f2 !== "MEMORY.md"
|
|
2066
2198
|
);
|
|
@@ -2273,16 +2405,16 @@ var init_template_engine = __esm({
|
|
|
2273
2405
|
// src/lib/settings-local.ts
|
|
2274
2406
|
import {
|
|
2275
2407
|
closeSync,
|
|
2276
|
-
existsSync as
|
|
2408
|
+
existsSync as existsSync5,
|
|
2277
2409
|
fsyncSync,
|
|
2278
|
-
mkdirSync as
|
|
2410
|
+
mkdirSync as mkdirSync3,
|
|
2279
2411
|
openSync,
|
|
2280
|
-
readFileSync as
|
|
2412
|
+
readFileSync as readFileSync4,
|
|
2281
2413
|
renameSync,
|
|
2282
|
-
rmSync,
|
|
2414
|
+
rmSync as rmSync2,
|
|
2283
2415
|
writeSync
|
|
2284
2416
|
} from "fs";
|
|
2285
|
-
import { dirname as dirname3, resolve as
|
|
2417
|
+
import { dirname as dirname3, resolve as resolve4 } from "path";
|
|
2286
2418
|
function atomicWriteFile(targetPath, content, mode = 420) {
|
|
2287
2419
|
const tmpPath = `${targetPath}.${process.pid}.tmp`;
|
|
2288
2420
|
try {
|
|
@@ -2296,9 +2428,9 @@ function atomicWriteFile(targetPath, content, mode = 420) {
|
|
|
2296
2428
|
}
|
|
2297
2429
|
renameSync(tmpPath, targetPath);
|
|
2298
2430
|
} catch (err) {
|
|
2299
|
-
if (
|
|
2431
|
+
if (existsSync5(tmpPath)) {
|
|
2300
2432
|
try {
|
|
2301
|
-
|
|
2433
|
+
rmSync2(tmpPath, { force: true });
|
|
2302
2434
|
} catch {
|
|
2303
2435
|
}
|
|
2304
2436
|
}
|
|
@@ -2306,11 +2438,11 @@ function atomicWriteFile(targetPath, content, mode = 420) {
|
|
|
2306
2438
|
}
|
|
2307
2439
|
}
|
|
2308
2440
|
function readSettingsAtPath(absolutePath) {
|
|
2309
|
-
if (!
|
|
2441
|
+
if (!existsSync5(absolutePath)) {
|
|
2310
2442
|
return {};
|
|
2311
2443
|
}
|
|
2312
2444
|
try {
|
|
2313
|
-
const raw =
|
|
2445
|
+
const raw = readFileSync4(absolutePath, "utf-8");
|
|
2314
2446
|
const parsed = JSON.parse(raw);
|
|
2315
2447
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
2316
2448
|
return {};
|
|
@@ -2321,13 +2453,13 @@ function readSettingsAtPath(absolutePath) {
|
|
|
2321
2453
|
}
|
|
2322
2454
|
}
|
|
2323
2455
|
function readSettingsLocal(claudeDir) {
|
|
2324
|
-
return readSettingsAtPath(
|
|
2456
|
+
return readSettingsAtPath(resolve4(claudeDir, "settings.local.json"));
|
|
2325
2457
|
}
|
|
2326
2458
|
function writeSettingsLocalAtomic(claudeDir, settings) {
|
|
2327
|
-
const targetPath =
|
|
2459
|
+
const targetPath = resolve4(claudeDir, "settings.local.json");
|
|
2328
2460
|
const dir = dirname3(targetPath);
|
|
2329
|
-
if (!
|
|
2330
|
-
|
|
2461
|
+
if (!existsSync5(dir)) {
|
|
2462
|
+
mkdirSync3(dir, { recursive: true });
|
|
2331
2463
|
}
|
|
2332
2464
|
const content = JSON.stringify(settings, null, 2) + "\n";
|
|
2333
2465
|
atomicWriteFile(targetPath, content);
|
|
@@ -2340,7 +2472,7 @@ var init_settings_local = __esm({
|
|
|
2340
2472
|
|
|
2341
2473
|
// src/permissions.ts
|
|
2342
2474
|
import { createHash } from "crypto";
|
|
2343
|
-
import { homedir as
|
|
2475
|
+
import { homedir as homedir3 } from "os";
|
|
2344
2476
|
import { join as join2 } from "path";
|
|
2345
2477
|
function canonicalJson(value) {
|
|
2346
2478
|
if (value === null || typeof value !== "object") {
|
|
@@ -2380,7 +2512,7 @@ function detectInvalidDefaultMode(settings) {
|
|
|
2380
2512
|
return { invalid: false };
|
|
2381
2513
|
}
|
|
2382
2514
|
function readGlobalSettings() {
|
|
2383
|
-
return readSettingsAtPath(join2(
|
|
2515
|
+
return readSettingsAtPath(join2(homedir3(), ".claude", "settings.json"));
|
|
2384
2516
|
}
|
|
2385
2517
|
function mergedPermissionState(global2, local, canonical) {
|
|
2386
2518
|
const globalPerm = global2.permissions ?? {};
|
|
@@ -2564,27 +2696,27 @@ __export(install_commands_exports, {
|
|
|
2564
2696
|
syncDirectory: () => syncDirectory
|
|
2565
2697
|
});
|
|
2566
2698
|
import {
|
|
2567
|
-
existsSync as
|
|
2568
|
-
readFileSync as
|
|
2569
|
-
mkdirSync as
|
|
2699
|
+
existsSync as existsSync6,
|
|
2700
|
+
readFileSync as readFileSync5,
|
|
2701
|
+
mkdirSync as mkdirSync4,
|
|
2570
2702
|
readdirSync as readdirSync2,
|
|
2571
2703
|
statSync
|
|
2572
2704
|
} from "fs";
|
|
2573
|
-
import { resolve as
|
|
2705
|
+
import { resolve as resolve5, dirname as dirname4, join as join3 } from "path";
|
|
2574
2706
|
import { fileURLToPath } from "url";
|
|
2575
2707
|
import { createHash as createHash2 } from "crypto";
|
|
2576
2708
|
function resolveAssetDir(assetName) {
|
|
2577
2709
|
const cwd = process.cwd();
|
|
2578
|
-
const nodeModulesPath =
|
|
2579
|
-
if (
|
|
2710
|
+
const nodeModulesPath = resolve5(cwd, "node_modules/@massu/core", assetName);
|
|
2711
|
+
if (existsSync6(nodeModulesPath)) {
|
|
2580
2712
|
return nodeModulesPath;
|
|
2581
2713
|
}
|
|
2582
|
-
const distRelPath =
|
|
2583
|
-
if (
|
|
2714
|
+
const distRelPath = resolve5(__dirname, "..", assetName);
|
|
2715
|
+
if (existsSync6(distRelPath)) {
|
|
2584
2716
|
return distRelPath;
|
|
2585
2717
|
}
|
|
2586
|
-
const srcRelPath =
|
|
2587
|
-
if (
|
|
2718
|
+
const srcRelPath = resolve5(__dirname, "../..", assetName);
|
|
2719
|
+
if (existsSync6(srcRelPath)) {
|
|
2588
2720
|
return srcRelPath;
|
|
2589
2721
|
}
|
|
2590
2722
|
return null;
|
|
@@ -2596,12 +2728,12 @@ function hashContent(content) {
|
|
|
2596
2728
|
return createHash2("sha256").update(content, "utf-8").digest("hex");
|
|
2597
2729
|
}
|
|
2598
2730
|
function loadManifest(claudeDir) {
|
|
2599
|
-
const path =
|
|
2600
|
-
if (!
|
|
2731
|
+
const path = resolve5(claudeDir, MANIFEST_RELPATH);
|
|
2732
|
+
if (!existsSync6(path)) {
|
|
2601
2733
|
return emptyManifest();
|
|
2602
2734
|
}
|
|
2603
2735
|
try {
|
|
2604
|
-
const raw =
|
|
2736
|
+
const raw = readFileSync5(path, "utf-8");
|
|
2605
2737
|
const parsed = JSON.parse(raw);
|
|
2606
2738
|
if (!parsed || typeof parsed !== "object" || !parsed.entries) {
|
|
2607
2739
|
return emptyManifest();
|
|
@@ -2612,11 +2744,11 @@ function loadManifest(claudeDir) {
|
|
|
2612
2744
|
}
|
|
2613
2745
|
}
|
|
2614
2746
|
function saveManifest(claudeDir, manifest) {
|
|
2615
|
-
const dir =
|
|
2616
|
-
if (!
|
|
2617
|
-
|
|
2747
|
+
const dir = resolve5(claudeDir, ".massu");
|
|
2748
|
+
if (!existsSync6(dir)) {
|
|
2749
|
+
mkdirSync4(dir, { recursive: true });
|
|
2618
2750
|
}
|
|
2619
|
-
const finalPath =
|
|
2751
|
+
const finalPath = resolve5(dir, "install-manifest.json");
|
|
2620
2752
|
manifest.generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2621
2753
|
atomicWriteFile(finalPath, JSON.stringify(manifest, null, 2));
|
|
2622
2754
|
}
|
|
@@ -2678,18 +2810,18 @@ function pickVariant(baseName, sourceDir, framework) {
|
|
|
2678
2810
|
}
|
|
2679
2811
|
for (const cand of candidates) {
|
|
2680
2812
|
if (cand.subFramework) {
|
|
2681
|
-
const subPath =
|
|
2682
|
-
if (
|
|
2813
|
+
const subPath = resolve5(sourceDir, `${baseName}.${cand.lang}-${cand.subFramework}.md`);
|
|
2814
|
+
if (existsSync6(subPath)) {
|
|
2683
2815
|
return { kind: "hit", suffix: `.${cand.lang}-${cand.subFramework}` };
|
|
2684
2816
|
}
|
|
2685
2817
|
}
|
|
2686
|
-
const langPath =
|
|
2687
|
-
if (
|
|
2818
|
+
const langPath = resolve5(sourceDir, `${baseName}.${cand.lang}.md`);
|
|
2819
|
+
if (existsSync6(langPath)) {
|
|
2688
2820
|
return { kind: "hit", suffix: `.${cand.lang}` };
|
|
2689
2821
|
}
|
|
2690
2822
|
}
|
|
2691
|
-
const defaultPath =
|
|
2692
|
-
if (
|
|
2823
|
+
const defaultPath = resolve5(sourceDir, `${baseName}.md`);
|
|
2824
|
+
if (existsSync6(defaultPath)) {
|
|
2693
2825
|
return { kind: "hit", suffix: "" };
|
|
2694
2826
|
}
|
|
2695
2827
|
if (framework.type === "multi" && !framework.primary) {
|
|
@@ -2705,15 +2837,15 @@ function isVariantFilename(entry) {
|
|
|
2705
2837
|
}
|
|
2706
2838
|
function syncDirectory(sourceDir, targetDir, framework, manifest, manifestKeyPrefix, topLevel = true, templateVars = {}) {
|
|
2707
2839
|
const stats = { installed: 0, updated: 0, skipped: 0, kept: 0 };
|
|
2708
|
-
if (!
|
|
2709
|
-
|
|
2840
|
+
if (!existsSync6(targetDir)) {
|
|
2841
|
+
mkdirSync4(targetDir, { recursive: true });
|
|
2710
2842
|
}
|
|
2711
2843
|
const entries = readdirSync2(sourceDir);
|
|
2712
2844
|
for (const entry of entries) {
|
|
2713
|
-
const sourcePath =
|
|
2845
|
+
const sourcePath = resolve5(sourceDir, entry);
|
|
2714
2846
|
const entryStat = statSync(sourcePath);
|
|
2715
2847
|
if (entryStat.isDirectory()) {
|
|
2716
|
-
const subTargetDir =
|
|
2848
|
+
const subTargetDir = resolve5(targetDir, entry);
|
|
2717
2849
|
const subPrefix = manifestKeyPrefix === "" ? entry : `${manifestKeyPrefix}/${entry}`;
|
|
2718
2850
|
const subStats = syncDirectory(
|
|
2719
2851
|
sourcePath,
|
|
@@ -2742,13 +2874,13 @@ function syncDirectory(sourceDir, targetDir, framework, manifest, manifestKeyPre
|
|
|
2742
2874
|
const suffix = choice.kind === "hit" ? choice.suffix : "";
|
|
2743
2875
|
sourceFilename = suffix === "" ? `${baseName}.md` : `${baseName}${suffix}.md`;
|
|
2744
2876
|
}
|
|
2745
|
-
const resolvedSourcePath =
|
|
2746
|
-
if (!
|
|
2877
|
+
const resolvedSourcePath = resolve5(sourceDir, sourceFilename);
|
|
2878
|
+
if (!existsSync6(resolvedSourcePath)) {
|
|
2747
2879
|
continue;
|
|
2748
2880
|
}
|
|
2749
2881
|
const targetFilename = topLevel ? `${baseName}.md` : entry;
|
|
2750
|
-
const targetPath =
|
|
2751
|
-
const rawContent =
|
|
2882
|
+
const targetPath = resolve5(targetDir, targetFilename);
|
|
2883
|
+
const rawContent = readFileSync5(resolvedSourcePath, "utf-8");
|
|
2752
2884
|
let sourceContent;
|
|
2753
2885
|
try {
|
|
2754
2886
|
sourceContent = renderTemplate(rawContent, templateVars);
|
|
@@ -2766,8 +2898,8 @@ function syncDirectory(sourceDir, targetDir, framework, manifest, manifestKeyPre
|
|
|
2766
2898
|
const sourceHash = hashContent(sourceContent);
|
|
2767
2899
|
const manifestKey = manifestKeyPrefix === "" ? targetFilename : `${manifestKeyPrefix}/${targetFilename}`;
|
|
2768
2900
|
const lastInstalledHash = manifest.entries[manifestKey];
|
|
2769
|
-
if (
|
|
2770
|
-
const existingContent =
|
|
2901
|
+
if (existsSync6(targetPath)) {
|
|
2902
|
+
const existingContent = readFileSync5(targetPath, "utf-8");
|
|
2771
2903
|
const existingHash = hashContent(existingContent);
|
|
2772
2904
|
if (existingHash === sourceHash) {
|
|
2773
2905
|
manifest.entries[manifestKey] = sourceHash;
|
|
@@ -2826,10 +2958,10 @@ function buildTemplateVars() {
|
|
|
2826
2958
|
}
|
|
2827
2959
|
function installCommands(projectRoot, opts = {}) {
|
|
2828
2960
|
const claudeDirName = getConfig().conventions?.claudeDirName ?? ".claude";
|
|
2829
|
-
const claudeDir =
|
|
2830
|
-
const targetDir =
|
|
2831
|
-
if (!
|
|
2832
|
-
|
|
2961
|
+
const claudeDir = resolve5(projectRoot, claudeDirName);
|
|
2962
|
+
const targetDir = resolve5(claudeDir, "commands");
|
|
2963
|
+
if (!existsSync6(targetDir)) {
|
|
2964
|
+
mkdirSync4(targetDir, { recursive: true });
|
|
2833
2965
|
}
|
|
2834
2966
|
const sourceDir = resolveAssetDir("commands");
|
|
2835
2967
|
if (!sourceDir) {
|
|
@@ -2858,7 +2990,7 @@ function installCommands(projectRoot, opts = {}) {
|
|
|
2858
2990
|
}
|
|
2859
2991
|
function installAll(projectRoot, opts = {}) {
|
|
2860
2992
|
const claudeDirName = getConfig().conventions?.claudeDirName ?? ".claude";
|
|
2861
|
-
const claudeDir =
|
|
2993
|
+
const claudeDir = resolve5(projectRoot, claudeDirName);
|
|
2862
2994
|
const assets = {};
|
|
2863
2995
|
let totalInstalled = 0;
|
|
2864
2996
|
let totalUpdated = 0;
|
|
@@ -2871,7 +3003,7 @@ function installAll(projectRoot, opts = {}) {
|
|
|
2871
3003
|
for (const assetType of ASSET_TYPES) {
|
|
2872
3004
|
const sourceDir = resolveAssetDir(assetType.name);
|
|
2873
3005
|
if (!sourceDir) continue;
|
|
2874
|
-
const targetDir =
|
|
3006
|
+
const targetDir = resolve5(claudeDir, assetType.targetSubdir);
|
|
2875
3007
|
const stats = syncDirectory(
|
|
2876
3008
|
sourceDir,
|
|
2877
3009
|
targetDir,
|
|
@@ -3175,17 +3307,17 @@ var init_manifest_registry = __esm({
|
|
|
3175
3307
|
});
|
|
3176
3308
|
|
|
3177
3309
|
// src/detect/package-detector.ts
|
|
3178
|
-
import { readFileSync as
|
|
3310
|
+
import { readFileSync as readFileSync6, existsSync as existsSync7, statSync as statSync2, lstatSync, readdirSync as readdirSync3 } from "fs";
|
|
3179
3311
|
import { join as join4, relative as relative2 } from "path";
|
|
3180
3312
|
import { parse as parseToml } from "smol-toml";
|
|
3181
3313
|
function safeRead(path) {
|
|
3182
3314
|
try {
|
|
3183
|
-
if (!
|
|
3315
|
+
if (!existsSync7(path)) return null;
|
|
3184
3316
|
const ls = lstatSync(path);
|
|
3185
3317
|
if (ls.isSymbolicLink()) return null;
|
|
3186
3318
|
const st = statSync2(path);
|
|
3187
3319
|
if (!st.isFile()) return null;
|
|
3188
|
-
return
|
|
3320
|
+
return readFileSync6(path, "utf-8");
|
|
3189
3321
|
} catch {
|
|
3190
3322
|
return null;
|
|
3191
3323
|
}
|
|
@@ -3216,7 +3348,7 @@ function parsePackageJson(path, directory, root, warnings) {
|
|
|
3216
3348
|
const peer = Object.keys(
|
|
3217
3349
|
pkg.peerDependencies ?? {}
|
|
3218
3350
|
);
|
|
3219
|
-
const hasTs = deps.includes("typescript") || devDeps.includes("typescript") ||
|
|
3351
|
+
const hasTs = deps.includes("typescript") || devDeps.includes("typescript") || existsSync7(join4(directory, "tsconfig.json"));
|
|
3220
3352
|
const language = hasTs ? "typescript" : "javascript";
|
|
3221
3353
|
const scripts = Object.keys(
|
|
3222
3354
|
pkg.scripts ?? {}
|
|
@@ -3643,7 +3775,7 @@ function detectManifestsInDir(dir, root, warnings) {
|
|
|
3643
3775
|
for (const entry of getManifestRegistry2()) {
|
|
3644
3776
|
if (!entry.pattern.startsWith("*")) {
|
|
3645
3777
|
const path = join4(dir, entry.pattern);
|
|
3646
|
-
if (!
|
|
3778
|
+
if (!existsSync7(path)) continue;
|
|
3647
3779
|
const m3 = entry.parse(path, dir, root, warnings);
|
|
3648
3780
|
if (m3 !== null) out.push(m3);
|
|
3649
3781
|
} else {
|
|
@@ -3657,7 +3789,7 @@ function detectManifestsInDir(dir, root, warnings) {
|
|
|
3657
3789
|
for (const fname of dirEntries) {
|
|
3658
3790
|
if (!matchManifestPattern2(fname, entry.pattern)) continue;
|
|
3659
3791
|
const path = join4(dir, fname);
|
|
3660
|
-
if (!
|
|
3792
|
+
if (!existsSync7(path)) continue;
|
|
3661
3793
|
const m3 = entry.parse(path, dir, root, warnings);
|
|
3662
3794
|
if (m3 !== null) out.push(m3);
|
|
3663
3795
|
}
|
|
@@ -3678,7 +3810,7 @@ function detectPackageManifests(projectRoot) {
|
|
|
3678
3810
|
manifests.push(...detectManifestsInDir(projectRoot, projectRoot, warnings));
|
|
3679
3811
|
for (const ws of WORKSPACE_DIRS) {
|
|
3680
3812
|
const wsRoot = join4(projectRoot, ws);
|
|
3681
|
-
if (!
|
|
3813
|
+
if (!existsSync7(wsRoot)) continue;
|
|
3682
3814
|
for (const sub of listSubdirs(wsRoot)) {
|
|
3683
3815
|
manifests.push(...detectManifestsInDir(sub, projectRoot, warnings));
|
|
3684
3816
|
for (const sub2 of listSubdirs(sub)) {
|
|
@@ -8449,41 +8581,41 @@ var require_queue = __commonJS({
|
|
|
8449
8581
|
queue.drained = drained;
|
|
8450
8582
|
return queue;
|
|
8451
8583
|
function push(value) {
|
|
8452
|
-
var p19 = new Promise(function(
|
|
8584
|
+
var p19 = new Promise(function(resolve42, reject) {
|
|
8453
8585
|
pushCb(value, function(err, result) {
|
|
8454
8586
|
if (err) {
|
|
8455
8587
|
reject(err);
|
|
8456
8588
|
return;
|
|
8457
8589
|
}
|
|
8458
|
-
|
|
8590
|
+
resolve42(result);
|
|
8459
8591
|
});
|
|
8460
8592
|
});
|
|
8461
8593
|
p19.catch(noop);
|
|
8462
8594
|
return p19;
|
|
8463
8595
|
}
|
|
8464
8596
|
function unshift(value) {
|
|
8465
|
-
var p19 = new Promise(function(
|
|
8597
|
+
var p19 = new Promise(function(resolve42, reject) {
|
|
8466
8598
|
unshiftCb(value, function(err, result) {
|
|
8467
8599
|
if (err) {
|
|
8468
8600
|
reject(err);
|
|
8469
8601
|
return;
|
|
8470
8602
|
}
|
|
8471
|
-
|
|
8603
|
+
resolve42(result);
|
|
8472
8604
|
});
|
|
8473
8605
|
});
|
|
8474
8606
|
p19.catch(noop);
|
|
8475
8607
|
return p19;
|
|
8476
8608
|
}
|
|
8477
8609
|
function drained() {
|
|
8478
|
-
var p19 = new Promise(function(
|
|
8610
|
+
var p19 = new Promise(function(resolve42) {
|
|
8479
8611
|
process.nextTick(function() {
|
|
8480
8612
|
if (queue.idle()) {
|
|
8481
|
-
|
|
8613
|
+
resolve42();
|
|
8482
8614
|
} else {
|
|
8483
8615
|
var previousDrain = queue.drain;
|
|
8484
8616
|
queue.drain = function() {
|
|
8485
8617
|
if (typeof previousDrain === "function") previousDrain();
|
|
8486
|
-
|
|
8618
|
+
resolve42();
|
|
8487
8619
|
queue.drain = previousDrain;
|
|
8488
8620
|
};
|
|
8489
8621
|
}
|
|
@@ -8969,9 +9101,9 @@ var require_stream3 = __commonJS({
|
|
|
8969
9101
|
});
|
|
8970
9102
|
}
|
|
8971
9103
|
_getStat(filepath) {
|
|
8972
|
-
return new Promise((
|
|
9104
|
+
return new Promise((resolve42, reject) => {
|
|
8973
9105
|
this._stat(filepath, this._fsStatSettings, (error, stats) => {
|
|
8974
|
-
return error === null ?
|
|
9106
|
+
return error === null ? resolve42(stats) : reject(error);
|
|
8975
9107
|
});
|
|
8976
9108
|
});
|
|
8977
9109
|
}
|
|
@@ -8995,10 +9127,10 @@ var require_async5 = __commonJS({
|
|
|
8995
9127
|
this._readerStream = new stream_1.default(this._settings);
|
|
8996
9128
|
}
|
|
8997
9129
|
dynamic(root, options) {
|
|
8998
|
-
return new Promise((
|
|
9130
|
+
return new Promise((resolve42, reject) => {
|
|
8999
9131
|
this._walkAsync(root, options, (error, entries) => {
|
|
9000
9132
|
if (error === null) {
|
|
9001
|
-
|
|
9133
|
+
resolve42(entries);
|
|
9002
9134
|
} else {
|
|
9003
9135
|
reject(error);
|
|
9004
9136
|
}
|
|
@@ -9008,10 +9140,10 @@ var require_async5 = __commonJS({
|
|
|
9008
9140
|
async static(patterns, options) {
|
|
9009
9141
|
const entries = [];
|
|
9010
9142
|
const stream = this._readerStream.static(patterns, options);
|
|
9011
|
-
return new Promise((
|
|
9143
|
+
return new Promise((resolve42, reject) => {
|
|
9012
9144
|
stream.once("error", reject);
|
|
9013
9145
|
stream.on("data", (entry) => entries.push(entry));
|
|
9014
|
-
stream.once("end", () =>
|
|
9146
|
+
stream.once("end", () => resolve42(entries));
|
|
9015
9147
|
});
|
|
9016
9148
|
}
|
|
9017
9149
|
};
|
|
@@ -9670,7 +9802,7 @@ var require_out4 = __commonJS({
|
|
|
9670
9802
|
|
|
9671
9803
|
// src/detect/source-dir-detector.ts
|
|
9672
9804
|
import { realpathSync } from "fs";
|
|
9673
|
-
import { resolve as
|
|
9805
|
+
import { resolve as resolve6 } from "path";
|
|
9674
9806
|
function extsFor(language) {
|
|
9675
9807
|
return EXTENSIONS[language] ?? [];
|
|
9676
9808
|
}
|
|
@@ -9696,7 +9828,7 @@ function topSegment(rel) {
|
|
|
9696
9828
|
function isInsideRoot(root, candidate) {
|
|
9697
9829
|
try {
|
|
9698
9830
|
const realRoot = realpathSync(root);
|
|
9699
|
-
const realCand = realpathSync(
|
|
9831
|
+
const realCand = realpathSync(resolve6(root, candidate));
|
|
9700
9832
|
return realCand === realRoot || realCand.startsWith(realRoot + "/");
|
|
9701
9833
|
} catch {
|
|
9702
9834
|
return false;
|
|
@@ -9864,25 +9996,25 @@ var init_source_dir_detector = __esm({
|
|
|
9864
9996
|
});
|
|
9865
9997
|
|
|
9866
9998
|
// src/detect/monorepo-detector.ts
|
|
9867
|
-
import { readFileSync as
|
|
9999
|
+
import { readFileSync as readFileSync7, existsSync as existsSync8, statSync as statSync3, lstatSync as lstatSync2, readdirSync as readdirSync4 } from "fs";
|
|
9868
10000
|
import { join as join5, relative as relative3 } from "path";
|
|
9869
10001
|
import { parse as parseYaml3 } from "yaml";
|
|
9870
10002
|
import { parse as parseToml2 } from "smol-toml";
|
|
9871
10003
|
function safeReadText(path) {
|
|
9872
10004
|
try {
|
|
9873
|
-
if (!
|
|
10005
|
+
if (!existsSync8(path)) return null;
|
|
9874
10006
|
const ls = lstatSync2(path);
|
|
9875
10007
|
if (ls.isSymbolicLink()) return null;
|
|
9876
10008
|
const st = statSync3(path);
|
|
9877
10009
|
if (!st.isFile()) return null;
|
|
9878
|
-
return
|
|
10010
|
+
return readFileSync7(path, "utf-8");
|
|
9879
10011
|
} catch {
|
|
9880
10012
|
return null;
|
|
9881
10013
|
}
|
|
9882
10014
|
}
|
|
9883
10015
|
function firstManifestIn(dir) {
|
|
9884
10016
|
for (const m3 of MANIFEST_PRIORITY) {
|
|
9885
|
-
if (
|
|
10017
|
+
if (existsSync8(join5(dir, m3))) return m3;
|
|
9886
10018
|
}
|
|
9887
10019
|
return null;
|
|
9888
10020
|
}
|
|
@@ -9947,7 +10079,7 @@ function genericWorkspaces(root) {
|
|
|
9947
10079
|
const out = [];
|
|
9948
10080
|
for (const parent of CONVENTIONAL_WORKSPACE_PARENTS) {
|
|
9949
10081
|
const p19 = join5(root, parent);
|
|
9950
|
-
if (!
|
|
10082
|
+
if (!existsSync8(p19)) continue;
|
|
9951
10083
|
for (const sub of listSubdirs2(p19)) {
|
|
9952
10084
|
const pkg = pkgFromDir(root, sub);
|
|
9953
10085
|
if (pkg) out.push(pkg);
|
|
@@ -9988,7 +10120,7 @@ function expandWorkspaceGlobs(root, globs) {
|
|
|
9988
10120
|
const parts = pattern.split("/");
|
|
9989
10121
|
if (parts.length === 2 && (parts[1] === "*" || parts[1] === "**")) {
|
|
9990
10122
|
const parent = join5(root, parts[0]);
|
|
9991
|
-
if (!
|
|
10123
|
+
if (!existsSync8(parent)) continue;
|
|
9992
10124
|
for (const sub of listSubdirs2(parent)) {
|
|
9993
10125
|
const pkg = pkgFromDir(root, sub);
|
|
9994
10126
|
if (pkg && !seen.has(pkg.path)) {
|
|
@@ -9999,7 +10131,7 @@ function expandWorkspaceGlobs(root, globs) {
|
|
|
9999
10131
|
continue;
|
|
10000
10132
|
}
|
|
10001
10133
|
const direct = join5(root, pattern);
|
|
10002
|
-
if (
|
|
10134
|
+
if (existsSync8(direct)) {
|
|
10003
10135
|
const pkg = pkgFromDir(root, direct);
|
|
10004
10136
|
if (pkg && !seen.has(pkg.path)) {
|
|
10005
10137
|
seen.add(pkg.path);
|
|
@@ -10010,16 +10142,16 @@ function expandWorkspaceGlobs(root, globs) {
|
|
|
10010
10142
|
return out;
|
|
10011
10143
|
}
|
|
10012
10144
|
function hasTurbo(root) {
|
|
10013
|
-
return
|
|
10145
|
+
return existsSync8(join5(root, "turbo.json"));
|
|
10014
10146
|
}
|
|
10015
10147
|
function hasNx(root) {
|
|
10016
|
-
return
|
|
10148
|
+
return existsSync8(join5(root, "nx.json"));
|
|
10017
10149
|
}
|
|
10018
10150
|
function hasLerna(root) {
|
|
10019
|
-
return
|
|
10151
|
+
return existsSync8(join5(root, "lerna.json"));
|
|
10020
10152
|
}
|
|
10021
10153
|
function hasBazel(root) {
|
|
10022
|
-
return
|
|
10154
|
+
return existsSync8(join5(root, "WORKSPACE")) || existsSync8(join5(root, "WORKSPACE.bazel")) || existsSync8(join5(root, "MODULE.bazel"));
|
|
10023
10155
|
}
|
|
10024
10156
|
function detectMonorepo(projectRoot) {
|
|
10025
10157
|
const nested = [];
|
|
@@ -10210,7 +10342,7 @@ var init_vr_command_map = __esm({
|
|
|
10210
10342
|
});
|
|
10211
10343
|
|
|
10212
10344
|
// src/detect/domain-inferrer.ts
|
|
10213
|
-
import { existsSync as
|
|
10345
|
+
import { existsSync as existsSync9, readdirSync as readdirSync5 } from "fs";
|
|
10214
10346
|
import { join as join6 } from "path";
|
|
10215
10347
|
function titleCase(s) {
|
|
10216
10348
|
if (!s) return s;
|
|
@@ -10232,7 +10364,7 @@ function topLevelSrcSubdirs(root, sourceDirs) {
|
|
|
10232
10364
|
const seen = /* @__PURE__ */ new Set();
|
|
10233
10365
|
for (const rel of effective) {
|
|
10234
10366
|
const abs = join6(root, rel);
|
|
10235
|
-
if (!
|
|
10367
|
+
if (!existsSync9(abs)) continue;
|
|
10236
10368
|
try {
|
|
10237
10369
|
for (const e2 of readdirSync5(abs, { withFileTypes: true })) {
|
|
10238
10370
|
if (!e2.isDirectory()) continue;
|
|
@@ -10319,8 +10451,8 @@ var init_domain_inferrer = __esm({
|
|
|
10319
10451
|
});
|
|
10320
10452
|
|
|
10321
10453
|
// src/detect/regex-fallback.ts
|
|
10322
|
-
import { existsSync as
|
|
10323
|
-
import { resolve as
|
|
10454
|
+
import { existsSync as existsSync10, readdirSync as readdirSync6, readFileSync as readFileSync8, statSync as statSync4 } from "fs";
|
|
10455
|
+
import { resolve as resolve7, join as join7, basename as basename2 } from "path";
|
|
10324
10456
|
function introspectPython(detection, projectRoot) {
|
|
10325
10457
|
const sourceDir = resolveSourceDir(detection, "python", projectRoot);
|
|
10326
10458
|
if (!sourceDir) return null;
|
|
@@ -10486,10 +10618,10 @@ function resolveSourceDir(detection, lang, projectRoot) {
|
|
|
10486
10618
|
const list = info?.source_dirs ?? [];
|
|
10487
10619
|
if (list.length > 0) {
|
|
10488
10620
|
const first = list[0];
|
|
10489
|
-
const abs =
|
|
10490
|
-
return
|
|
10621
|
+
const abs = resolve7(projectRoot, first);
|
|
10622
|
+
return existsSync10(abs) ? abs : null;
|
|
10491
10623
|
}
|
|
10492
|
-
return
|
|
10624
|
+
return existsSync10(projectRoot) ? projectRoot : null;
|
|
10493
10625
|
}
|
|
10494
10626
|
function sampleFiles(dir, nameRegex, pathFilter) {
|
|
10495
10627
|
const out = [];
|
|
@@ -10534,7 +10666,7 @@ function readSafe(path) {
|
|
|
10534
10666
|
try {
|
|
10535
10667
|
const st = statSync4(path);
|
|
10536
10668
|
if (st.size > MAX_FILE_BYTES) return null;
|
|
10537
|
-
return
|
|
10669
|
+
return readFileSync8(path, "utf-8");
|
|
10538
10670
|
} catch {
|
|
10539
10671
|
return null;
|
|
10540
10672
|
}
|
|
@@ -10615,7 +10747,7 @@ var init_parse_guard = __esm({
|
|
|
10615
10747
|
|
|
10616
10748
|
// src/detect/adapters/runner.ts
|
|
10617
10749
|
import { basename as basename3, relative as relative4 } from "path";
|
|
10618
|
-
import { existsSync as
|
|
10750
|
+
import { existsSync as existsSync11, readdirSync as readdirSync7, readFileSync as readFileSync9, statSync as statSync5 } from "fs";
|
|
10619
10751
|
import { join as join8 } from "path";
|
|
10620
10752
|
async function runAdapters(adapters, rootDir, signals, options = {}) {
|
|
10621
10753
|
const out = {
|
|
@@ -10750,9 +10882,9 @@ function tryReadGradleBuild(rootDir, presentFiles) {
|
|
|
10750
10882
|
return void 0;
|
|
10751
10883
|
}
|
|
10752
10884
|
function tryReadString(path) {
|
|
10753
|
-
if (!
|
|
10885
|
+
if (!existsSync11(path)) return void 0;
|
|
10754
10886
|
try {
|
|
10755
|
-
return
|
|
10887
|
+
return readFileSync9(path, "utf-8");
|
|
10756
10888
|
} catch {
|
|
10757
10889
|
return void 0;
|
|
10758
10890
|
}
|
|
@@ -10869,21 +11001,21 @@ ${querySource}`
|
|
|
10869
11001
|
// src/detect/adapters/tree-sitter-loader.ts
|
|
10870
11002
|
import { createHash as createHash3 } from "crypto";
|
|
10871
11003
|
import {
|
|
10872
|
-
mkdirSync as
|
|
11004
|
+
mkdirSync as mkdirSync5,
|
|
10873
11005
|
readdirSync as readdirSync8,
|
|
10874
|
-
readFileSync as
|
|
10875
|
-
writeFileSync,
|
|
11006
|
+
readFileSync as readFileSync10,
|
|
11007
|
+
writeFileSync as writeFileSync2,
|
|
10876
11008
|
renameSync as renameSync2,
|
|
10877
11009
|
unlinkSync,
|
|
10878
11010
|
lstatSync as lstatSync3,
|
|
10879
|
-
chmodSync,
|
|
11011
|
+
chmodSync as chmodSync2,
|
|
10880
11012
|
utimesSync
|
|
10881
11013
|
} from "fs";
|
|
10882
|
-
import { homedir as
|
|
11014
|
+
import { homedir as homedir4 } from "os";
|
|
10883
11015
|
import { dirname as dirname5, join as join9 } from "path";
|
|
10884
11016
|
import { Language, Parser } from "web-tree-sitter";
|
|
10885
11017
|
function getCacheDir() {
|
|
10886
|
-
return process.env.MASSU_WASM_CACHE_DIR ?? join9(
|
|
11018
|
+
return process.env.MASSU_WASM_CACHE_DIR ?? join9(homedir4(), ".massu", "wasm-cache");
|
|
10887
11019
|
}
|
|
10888
11020
|
function getCachedPath(language, sha) {
|
|
10889
11021
|
return join9(getCacheDir(), `${language}-${sha}.wasm`);
|
|
@@ -10971,7 +11103,7 @@ async function loadGrammar(language, options = {}) {
|
|
|
10971
11103
|
}
|
|
10972
11104
|
let bytes;
|
|
10973
11105
|
try {
|
|
10974
|
-
bytes =
|
|
11106
|
+
bytes = readFileSync10(cachePath);
|
|
10975
11107
|
} catch (e2) {
|
|
10976
11108
|
bytes = new Uint8Array(0);
|
|
10977
11109
|
}
|
|
@@ -11011,21 +11143,21 @@ async function loadGrammar(language, options = {}) {
|
|
|
11011
11143
|
throw new GrammarSHAMismatchError(language, manifest.sha256, downloadedSha);
|
|
11012
11144
|
}
|
|
11013
11145
|
try {
|
|
11014
|
-
|
|
11146
|
+
mkdirSync5(dirname5(cachePath), { recursive: true, mode: 448 });
|
|
11015
11147
|
try {
|
|
11016
|
-
|
|
11148
|
+
chmodSync2(dirname5(cachePath), 448);
|
|
11017
11149
|
} catch {
|
|
11018
11150
|
}
|
|
11019
11151
|
const tmpPath = `${cachePath}.tmp.${process.pid}`;
|
|
11020
|
-
|
|
11152
|
+
writeFileSync2(tmpPath, body, { mode: 384 });
|
|
11021
11153
|
try {
|
|
11022
|
-
|
|
11154
|
+
chmodSync2(tmpPath, 384);
|
|
11023
11155
|
} catch {
|
|
11024
11156
|
}
|
|
11025
11157
|
try {
|
|
11026
11158
|
renameSync2(tmpPath, cachePath);
|
|
11027
11159
|
try {
|
|
11028
|
-
|
|
11160
|
+
chmodSync2(cachePath, 384);
|
|
11029
11161
|
} catch {
|
|
11030
11162
|
}
|
|
11031
11163
|
} catch (e2) {
|
|
@@ -11889,7 +12021,7 @@ __export(file_sampler_exports, {
|
|
|
11889
12021
|
SAMPLE_TEST_FILE_PATTERNS: () => SAMPLE_TEST_FILE_PATTERNS,
|
|
11890
12022
|
sampleFilesForAdapter: () => sampleFilesForAdapter
|
|
11891
12023
|
});
|
|
11892
|
-
import { readdirSync as readdirSync9, readFileSync as
|
|
12024
|
+
import { readdirSync as readdirSync9, readFileSync as readFileSync11, lstatSync as lstatSync4 } from "node:fs";
|
|
11893
12025
|
import { join as join10, extname } from "node:path";
|
|
11894
12026
|
function sampleFilesForAdapter(adapter, projectRoot, detection, options = {}) {
|
|
11895
12027
|
const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
|
|
@@ -11950,7 +12082,7 @@ function walkDir(dir, exts, testPatterns, lang, maxDepth, curDepth, out, seen, m
|
|
|
11950
12082
|
seen.add(fullPath);
|
|
11951
12083
|
let content;
|
|
11952
12084
|
try {
|
|
11953
|
-
content =
|
|
12085
|
+
content = readFileSync11(fullPath, "utf-8");
|
|
11954
12086
|
} catch {
|
|
11955
12087
|
continue;
|
|
11956
12088
|
}
|
|
@@ -13374,10 +13506,10 @@ __export(init_exports, {
|
|
|
13374
13506
|
validateWrittenConfig: () => validateWrittenConfig,
|
|
13375
13507
|
writeConfigAtomic: () => writeConfigAtomic
|
|
13376
13508
|
});
|
|
13377
|
-
import { closeSync as closeSync2, existsSync as
|
|
13378
|
-
import { resolve as
|
|
13509
|
+
import { closeSync as closeSync2, existsSync as existsSync12, fsyncSync as fsyncSync2, openSync as openSync2, readFileSync as readFileSync12, writeFileSync as writeFileSync3, writeSync as writeSync2, mkdirSync as mkdirSync6, readdirSync as readdirSync10, renameSync as renameSync3, rmSync as rmSync3, statSync as statSync7, chmodSync as chmodSync3 } from "fs";
|
|
13510
|
+
import { resolve as resolve8, basename as basename4, dirname as dirname6 } from "path";
|
|
13379
13511
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
13380
|
-
import { homedir as
|
|
13512
|
+
import { homedir as homedir5 } from "os";
|
|
13381
13513
|
import { stringify as yamlStringify, parse as yamlParse } from "yaml";
|
|
13382
13514
|
function detectFramework(projectRoot) {
|
|
13383
13515
|
const result = {
|
|
@@ -13386,10 +13518,10 @@ function detectFramework(projectRoot) {
|
|
|
13386
13518
|
orm: "none",
|
|
13387
13519
|
ui: "none"
|
|
13388
13520
|
};
|
|
13389
|
-
const pkgPath =
|
|
13390
|
-
if (!
|
|
13521
|
+
const pkgPath = resolve8(projectRoot, "package.json");
|
|
13522
|
+
if (!existsSync12(pkgPath)) return result;
|
|
13391
13523
|
try {
|
|
13392
|
-
const pkg = JSON.parse(
|
|
13524
|
+
const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
13393
13525
|
const allDeps = {
|
|
13394
13526
|
...pkg.dependencies,
|
|
13395
13527
|
...pkg.devDependencies
|
|
@@ -13423,7 +13555,7 @@ function detectPython(projectRoot) {
|
|
|
13423
13555
|
alembicDir: null
|
|
13424
13556
|
};
|
|
13425
13557
|
const markers = ["pyproject.toml", "setup.py", "requirements.txt", "Pipfile"];
|
|
13426
|
-
const hasMarker = markers.some((m3) =>
|
|
13558
|
+
const hasMarker = markers.some((m3) => existsSync12(resolve8(projectRoot, m3)));
|
|
13427
13559
|
if (!hasMarker) return result;
|
|
13428
13560
|
result.detected = true;
|
|
13429
13561
|
const depFiles = [
|
|
@@ -13433,33 +13565,33 @@ function detectPython(projectRoot) {
|
|
|
13433
13565
|
{ file: "Pipfile" }
|
|
13434
13566
|
];
|
|
13435
13567
|
for (const { file } of depFiles) {
|
|
13436
|
-
const filePath =
|
|
13437
|
-
if (
|
|
13568
|
+
const filePath = resolve8(projectRoot, file);
|
|
13569
|
+
if (existsSync12(filePath)) {
|
|
13438
13570
|
try {
|
|
13439
|
-
const content =
|
|
13571
|
+
const content = readFileSync12(filePath, "utf-8").toLowerCase();
|
|
13440
13572
|
if (content.includes("fastapi")) result.hasFastapi = true;
|
|
13441
13573
|
if (content.includes("sqlalchemy")) result.hasSqlalchemy = true;
|
|
13442
13574
|
} catch {
|
|
13443
13575
|
}
|
|
13444
13576
|
}
|
|
13445
13577
|
}
|
|
13446
|
-
if (
|
|
13578
|
+
if (existsSync12(resolve8(projectRoot, "alembic.ini"))) {
|
|
13447
13579
|
result.hasAlembic = true;
|
|
13448
|
-
if (
|
|
13580
|
+
if (existsSync12(resolve8(projectRoot, "alembic"))) {
|
|
13449
13581
|
result.alembicDir = "alembic";
|
|
13450
13582
|
}
|
|
13451
|
-
} else if (
|
|
13583
|
+
} else if (existsSync12(resolve8(projectRoot, "alembic"))) {
|
|
13452
13584
|
result.hasAlembic = true;
|
|
13453
13585
|
result.alembicDir = "alembic";
|
|
13454
13586
|
}
|
|
13455
13587
|
const candidateRoots = ["app", "src", "backend", "api"];
|
|
13456
13588
|
for (const candidate of candidateRoots) {
|
|
13457
|
-
const candidatePath =
|
|
13458
|
-
if (
|
|
13589
|
+
const candidatePath = resolve8(projectRoot, candidate);
|
|
13590
|
+
if (existsSync12(candidatePath) && existsSync12(resolve8(candidatePath, "__init__.py"))) {
|
|
13459
13591
|
result.root = candidate;
|
|
13460
13592
|
break;
|
|
13461
13593
|
}
|
|
13462
|
-
if (
|
|
13594
|
+
if (existsSync12(candidatePath)) {
|
|
13463
13595
|
try {
|
|
13464
13596
|
const files = readdirSync10(candidatePath);
|
|
13465
13597
|
if (files.some((f2) => f2.endsWith(".py"))) {
|
|
@@ -13479,8 +13611,8 @@ function generateConfig(projectRoot, framework) {
|
|
|
13479
13611
|
console.warn(
|
|
13480
13612
|
"[@massu/core] generateConfig() is deprecated since 1.2.1 \u2014 use buildConfigFromDetection instead. It cannot produce valid configs for monorepos."
|
|
13481
13613
|
);
|
|
13482
|
-
const configPath =
|
|
13483
|
-
if (
|
|
13614
|
+
const configPath = resolve8(projectRoot, "massu.config.yaml");
|
|
13615
|
+
if (existsSync12(configPath)) {
|
|
13484
13616
|
return false;
|
|
13485
13617
|
}
|
|
13486
13618
|
const projectName = basename4(projectRoot);
|
|
@@ -13526,7 +13658,7 @@ function generateConfig(projectRoot, framework) {
|
|
|
13526
13658
|
# Documentation: https://massu.ai/docs/getting-started/configuration
|
|
13527
13659
|
|
|
13528
13660
|
${yamlStringify(config)}`;
|
|
13529
|
-
|
|
13661
|
+
writeFileSync3(configPath, yamlContent, "utf-8");
|
|
13530
13662
|
return true;
|
|
13531
13663
|
}
|
|
13532
13664
|
function monorepoCommonRoot(packages) {
|
|
@@ -13591,10 +13723,10 @@ function buildConfigFromDetection(opts) {
|
|
|
13591
13723
|
pathsSource = monorepoCommonRoot(detection.monorepo.packages);
|
|
13592
13724
|
}
|
|
13593
13725
|
}
|
|
13594
|
-
if (pathsSource === "src" && !
|
|
13726
|
+
if (pathsSource === "src" && !existsSync12(resolve8(projectRoot, "src"))) {
|
|
13595
13727
|
const fallbacks = ["app", "pages", "."];
|
|
13596
13728
|
for (const fallback of fallbacks) {
|
|
13597
|
-
if (fallback === "." ||
|
|
13729
|
+
if (fallback === "." || existsSync12(resolve8(projectRoot, fallback))) {
|
|
13598
13730
|
pathsSource = fallback;
|
|
13599
13731
|
break;
|
|
13600
13732
|
}
|
|
@@ -13678,7 +13810,7 @@ function buildConfigFromDetection(opts) {
|
|
|
13678
13810
|
};
|
|
13679
13811
|
if (pyFw?.framework) pythonBlock.framework = pyFw.framework;
|
|
13680
13812
|
if (pyFw?.orm) pythonBlock.orm = pyFw.orm;
|
|
13681
|
-
if (
|
|
13813
|
+
if (existsSync12(resolve8(projectRoot, "alembic.ini")) || existsSync12(resolve8(projectRoot, "alembic"))) {
|
|
13682
13814
|
pythonBlock.alembic_dir = "alembic";
|
|
13683
13815
|
}
|
|
13684
13816
|
config.python = pythonBlock;
|
|
@@ -13702,11 +13834,11 @@ function applyVariantTemplate(config, templatesDir) {
|
|
|
13702
13834
|
}
|
|
13703
13835
|
}
|
|
13704
13836
|
if (templateId === null) return config;
|
|
13705
|
-
const templatePath =
|
|
13706
|
-
if (!
|
|
13837
|
+
const templatePath = resolve8(templatesDir, templateId, "massu.config.yaml");
|
|
13838
|
+
if (!existsSync12(templatePath)) return config;
|
|
13707
13839
|
let template;
|
|
13708
13840
|
try {
|
|
13709
|
-
template = yamlParse(
|
|
13841
|
+
template = yamlParse(readFileSync12(templatePath, "utf-8"));
|
|
13710
13842
|
} catch {
|
|
13711
13843
|
return config;
|
|
13712
13844
|
}
|
|
@@ -13765,7 +13897,7 @@ ${yamlStringify(config)}`;
|
|
|
13765
13897
|
function writeConfigAtomic(configPath, content) {
|
|
13766
13898
|
const tmpPath = `${configPath}.tmp`;
|
|
13767
13899
|
let existingMode;
|
|
13768
|
-
if (
|
|
13900
|
+
if (existsSync12(configPath)) {
|
|
13769
13901
|
try {
|
|
13770
13902
|
existingMode = statSync7(configPath).mode;
|
|
13771
13903
|
} catch {
|
|
@@ -13773,7 +13905,7 @@ function writeConfigAtomic(configPath, content) {
|
|
|
13773
13905
|
}
|
|
13774
13906
|
}
|
|
13775
13907
|
try {
|
|
13776
|
-
|
|
13908
|
+
mkdirSync6(dirname6(configPath), { recursive: true });
|
|
13777
13909
|
const fd = openSync2(tmpPath, "w", 420);
|
|
13778
13910
|
try {
|
|
13779
13911
|
const buf = Buffer.from(content, "utf-8");
|
|
@@ -13789,15 +13921,15 @@ function writeConfigAtomic(configPath, content) {
|
|
|
13789
13921
|
renameSync3(tmpPath, configPath);
|
|
13790
13922
|
if (existingMode !== void 0) {
|
|
13791
13923
|
try {
|
|
13792
|
-
|
|
13924
|
+
chmodSync3(configPath, existingMode);
|
|
13793
13925
|
} catch {
|
|
13794
13926
|
}
|
|
13795
13927
|
}
|
|
13796
13928
|
return { validated: true };
|
|
13797
13929
|
} catch (err) {
|
|
13798
|
-
if (
|
|
13930
|
+
if (existsSync12(tmpPath)) {
|
|
13799
13931
|
try {
|
|
13800
|
-
|
|
13932
|
+
rmSync3(tmpPath, { force: true });
|
|
13801
13933
|
} catch {
|
|
13802
13934
|
}
|
|
13803
13935
|
}
|
|
@@ -13806,8 +13938,8 @@ function writeConfigAtomic(configPath, content) {
|
|
|
13806
13938
|
}
|
|
13807
13939
|
function validateWrittenConfig(configPath, projectRoot, checkPaths = true) {
|
|
13808
13940
|
try {
|
|
13809
|
-
if (!
|
|
13810
|
-
const content =
|
|
13941
|
+
if (!existsSync12(configPath)) return "Config file does not exist after write";
|
|
13942
|
+
const content = readFileSync12(configPath, "utf-8");
|
|
13811
13943
|
const parsed = yamlParse(content);
|
|
13812
13944
|
if (parsed === null || typeof parsed !== "object") {
|
|
13813
13945
|
return "Config is not a valid YAML object";
|
|
@@ -13827,8 +13959,8 @@ function validateWrittenConfig(configPath, projectRoot, checkPaths = true) {
|
|
|
13827
13959
|
if (checkPaths) {
|
|
13828
13960
|
const src = cfg.paths.source;
|
|
13829
13961
|
if (src && src !== ".") {
|
|
13830
|
-
const srcAbs =
|
|
13831
|
-
if (!
|
|
13962
|
+
const srcAbs = resolve8(projectRoot, src);
|
|
13963
|
+
if (!existsSync12(srcAbs)) {
|
|
13832
13964
|
return `paths.source '${src}' does not exist on disk`;
|
|
13833
13965
|
}
|
|
13834
13966
|
}
|
|
@@ -13838,8 +13970,8 @@ function validateWrittenConfig(configPath, projectRoot, checkPaths = true) {
|
|
|
13838
13970
|
if (!Array.isArray(rawDirs)) continue;
|
|
13839
13971
|
for (const d2 of rawDirs) {
|
|
13840
13972
|
if (typeof d2 !== "string" || d2 === ".") continue;
|
|
13841
|
-
const abs =
|
|
13842
|
-
if (!
|
|
13973
|
+
const abs = resolve8(projectRoot, d2);
|
|
13974
|
+
if (!existsSync12(abs)) {
|
|
13843
13975
|
return `framework.languages.${lang}.source_dirs '${d2}' does not exist on disk`;
|
|
13844
13976
|
}
|
|
13845
13977
|
}
|
|
@@ -13848,7 +13980,7 @@ function validateWrittenConfig(configPath, projectRoot, checkPaths = true) {
|
|
|
13848
13980
|
if (Array.isArray(mRoots)) {
|
|
13849
13981
|
for (const r2 of mRoots) {
|
|
13850
13982
|
if (typeof r2 !== "string" || r2 === ".") continue;
|
|
13851
|
-
if (!
|
|
13983
|
+
if (!existsSync12(resolve8(projectRoot, r2))) {
|
|
13852
13984
|
return `paths.monorepo_roots '${r2}' does not exist on disk`;
|
|
13853
13985
|
}
|
|
13854
13986
|
}
|
|
@@ -13880,21 +14012,21 @@ function resolveTemplatesDir() {
|
|
|
13880
14012
|
const cwd = process.cwd();
|
|
13881
14013
|
const candidates = [
|
|
13882
14014
|
// Project-local install: `<project>/node_modules/@massu/core/templates`.
|
|
13883
|
-
|
|
14015
|
+
resolve8(cwd, "node_modules/@massu/core/templates"),
|
|
13884
14016
|
// Bundled cli.js layout: cli.js sits at `<package>/dist/cli.js`, so
|
|
13885
14017
|
// templates live one level up at `<package>/templates`. (Plan 1.5.1
|
|
13886
14018
|
// bug discovery: pre-existing layout assumed `dist/commands/init.js`
|
|
13887
14019
|
// depth which never matched the bundled cli, so resolveTemplatesDir
|
|
13888
14020
|
// returned null in production for both `--template` mode AND the
|
|
13889
14021
|
// applyVariantTemplate path.)
|
|
13890
|
-
|
|
14022
|
+
resolve8(__dirname2, "../templates"),
|
|
13891
14023
|
// Legacy nested layouts retained as fallbacks (in case a future
|
|
13892
14024
|
// build moves cli.js back into a subdirectory).
|
|
13893
|
-
|
|
13894
|
-
|
|
14025
|
+
resolve8(__dirname2, "../../templates"),
|
|
14026
|
+
resolve8(__dirname2, "../../../templates")
|
|
13895
14027
|
];
|
|
13896
14028
|
for (const c2 of candidates) {
|
|
13897
|
-
if (
|
|
14029
|
+
if (existsSync12(c2)) return c2;
|
|
13898
14030
|
}
|
|
13899
14031
|
return null;
|
|
13900
14032
|
}
|
|
@@ -13903,14 +14035,14 @@ function copyTemplateConfig(templateName, targetPath, projectName) {
|
|
|
13903
14035
|
if (!templatesDir) {
|
|
13904
14036
|
return { success: false, error: `Templates directory not found (looked in node_modules and dist/src)` };
|
|
13905
14037
|
}
|
|
13906
|
-
const srcPath =
|
|
13907
|
-
if (!
|
|
14038
|
+
const srcPath = resolve8(templatesDir, templateName, "massu.config.yaml");
|
|
14039
|
+
if (!existsSync12(srcPath)) {
|
|
13908
14040
|
return { success: false, error: `Template '${templateName}' not found at ${srcPath}` };
|
|
13909
14041
|
}
|
|
13910
14042
|
try {
|
|
13911
|
-
let content =
|
|
14043
|
+
let content = readFileSync12(srcPath, "utf-8");
|
|
13912
14044
|
content = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
|
|
13913
|
-
|
|
14045
|
+
writeFileSync3(targetPath, content, "utf-8");
|
|
13914
14046
|
return { success: true };
|
|
13915
14047
|
} catch (err) {
|
|
13916
14048
|
return { success: false, error: err instanceof Error ? err.message : String(err) };
|
|
@@ -13918,13 +14050,13 @@ function copyTemplateConfig(templateName, targetPath, projectName) {
|
|
|
13918
14050
|
}
|
|
13919
14051
|
function getInstallerVersion() {
|
|
13920
14052
|
const candidates = [
|
|
13921
|
-
|
|
13922
|
-
|
|
14053
|
+
resolve8(__dirname2, "../package.json"),
|
|
14054
|
+
resolve8(__dirname2, "../../package.json")
|
|
13923
14055
|
];
|
|
13924
14056
|
for (const candidate of candidates) {
|
|
13925
|
-
if (
|
|
14057
|
+
if (existsSync12(candidate)) {
|
|
13926
14058
|
try {
|
|
13927
|
-
const pkg = JSON.parse(
|
|
14059
|
+
const pkg = JSON.parse(readFileSync12(candidate, "utf-8"));
|
|
13928
14060
|
if (typeof pkg.version === "string" && pkg.version.length > 0 && pkg.name === "@massu/core") {
|
|
13929
14061
|
return pkg.version;
|
|
13930
14062
|
}
|
|
@@ -13937,11 +14069,11 @@ function getInstallerVersion() {
|
|
|
13937
14069
|
);
|
|
13938
14070
|
}
|
|
13939
14071
|
function registerMcpServer(projectRoot) {
|
|
13940
|
-
const mcpPath =
|
|
14072
|
+
const mcpPath = resolve8(projectRoot, ".mcp.json");
|
|
13941
14073
|
let existing = {};
|
|
13942
|
-
if (
|
|
14074
|
+
if (existsSync12(mcpPath)) {
|
|
13943
14075
|
try {
|
|
13944
|
-
existing = JSON.parse(
|
|
14076
|
+
existing = JSON.parse(readFileSync12(mcpPath, "utf-8"));
|
|
13945
14077
|
} catch {
|
|
13946
14078
|
existing = {};
|
|
13947
14079
|
}
|
|
@@ -13957,17 +14089,17 @@ function registerMcpServer(projectRoot) {
|
|
|
13957
14089
|
args: ["-y", `@massu/core@${version}`]
|
|
13958
14090
|
};
|
|
13959
14091
|
existing.mcpServers = servers;
|
|
13960
|
-
|
|
14092
|
+
writeFileSync3(mcpPath, JSON.stringify(existing, null, 2) + "\n", "utf-8");
|
|
13961
14093
|
return true;
|
|
13962
14094
|
}
|
|
13963
14095
|
function resolveHooksDir() {
|
|
13964
14096
|
const cwd = process.cwd();
|
|
13965
|
-
const nodeModulesPath =
|
|
13966
|
-
if (
|
|
14097
|
+
const nodeModulesPath = resolve8(cwd, "node_modules/@massu/core/dist/hooks");
|
|
14098
|
+
if (existsSync12(nodeModulesPath)) {
|
|
13967
14099
|
return "node_modules/@massu/core/dist/hooks";
|
|
13968
14100
|
}
|
|
13969
|
-
const localPath =
|
|
13970
|
-
if (
|
|
14101
|
+
const localPath = resolve8(__dirname2, "../dist/hooks");
|
|
14102
|
+
if (existsSync12(localPath)) {
|
|
13971
14103
|
return localPath;
|
|
13972
14104
|
}
|
|
13973
14105
|
return "node_modules/@massu/core/dist/hooks";
|
|
@@ -14113,9 +14245,9 @@ function installHooks(projectRoot) {
|
|
|
14113
14245
|
} catch {
|
|
14114
14246
|
claudeDirName = ".claude";
|
|
14115
14247
|
}
|
|
14116
|
-
const claudeDir =
|
|
14117
|
-
if (!
|
|
14118
|
-
|
|
14248
|
+
const claudeDir = resolve8(projectRoot, claudeDirName);
|
|
14249
|
+
if (!existsSync12(claudeDir)) {
|
|
14250
|
+
mkdirSync6(claudeDir, { recursive: true });
|
|
14119
14251
|
}
|
|
14120
14252
|
const settings = readSettingsLocal(claudeDir);
|
|
14121
14253
|
const hooksConfig = buildHooksConfig(resolveHooksDir());
|
|
@@ -14133,17 +14265,17 @@ function installHooks(projectRoot) {
|
|
|
14133
14265
|
}
|
|
14134
14266
|
function initMemoryDir(projectRoot) {
|
|
14135
14267
|
const encodedRoot = encodeMemoryDirName(projectRoot);
|
|
14136
|
-
const memoryDir =
|
|
14268
|
+
const memoryDir = resolve8(homedir5(), `.claude/projects/${encodedRoot}/memory`);
|
|
14137
14269
|
let migratedFromLegacy = false;
|
|
14138
|
-
const legacyDir =
|
|
14139
|
-
if (
|
|
14270
|
+
const legacyDir = resolve8(homedir5(), `.claude/projects/-${encodedRoot}/memory`);
|
|
14271
|
+
if (existsSync12(legacyDir) && !existsSync12(memoryDir)) {
|
|
14140
14272
|
try {
|
|
14141
|
-
|
|
14273
|
+
mkdirSync6(resolve8(memoryDir, ".."), { recursive: true });
|
|
14142
14274
|
renameSync3(legacyDir, memoryDir);
|
|
14143
14275
|
try {
|
|
14144
|
-
const legacyParent =
|
|
14145
|
-
if (
|
|
14146
|
-
|
|
14276
|
+
const legacyParent = resolve8(legacyDir, "..");
|
|
14277
|
+
if (existsSync12(legacyParent) && readdirSync10(legacyParent).length === 0) {
|
|
14278
|
+
rmSync3(legacyParent, { recursive: false });
|
|
14147
14279
|
}
|
|
14148
14280
|
} catch {
|
|
14149
14281
|
}
|
|
@@ -14152,13 +14284,13 @@ function initMemoryDir(projectRoot) {
|
|
|
14152
14284
|
}
|
|
14153
14285
|
}
|
|
14154
14286
|
let created = false;
|
|
14155
|
-
if (!
|
|
14156
|
-
|
|
14287
|
+
if (!existsSync12(memoryDir)) {
|
|
14288
|
+
mkdirSync6(memoryDir, { recursive: true });
|
|
14157
14289
|
created = true;
|
|
14158
14290
|
}
|
|
14159
|
-
const memoryMdPath =
|
|
14291
|
+
const memoryMdPath = resolve8(memoryDir, "MEMORY.md");
|
|
14160
14292
|
let memoryMdCreated = false;
|
|
14161
|
-
if (!
|
|
14293
|
+
if (!existsSync12(memoryMdPath)) {
|
|
14162
14294
|
const projectName = basename4(projectRoot);
|
|
14163
14295
|
const memoryContent = `# ${projectName} - Massu Memory
|
|
14164
14296
|
|
|
@@ -14174,7 +14306,7 @@ function initMemoryDir(projectRoot) {
|
|
|
14174
14306
|
## File Index
|
|
14175
14307
|
<!-- Significant files and directories -->
|
|
14176
14308
|
`;
|
|
14177
|
-
|
|
14309
|
+
writeFileSync3(memoryMdPath, memoryContent, "utf-8");
|
|
14178
14310
|
memoryMdCreated = true;
|
|
14179
14311
|
}
|
|
14180
14312
|
return { created, memoryMdCreated, migratedFromLegacy };
|
|
@@ -14272,8 +14404,8 @@ async function runInit(argv, overrides) {
|
|
|
14272
14404
|
log("Massu AI - Project Setup");
|
|
14273
14405
|
log("========================");
|
|
14274
14406
|
log("");
|
|
14275
|
-
const configPath =
|
|
14276
|
-
if (
|
|
14407
|
+
const configPath = resolve8(projectRoot, "massu.config.yaml");
|
|
14408
|
+
if (existsSync12(configPath)) {
|
|
14277
14409
|
if (opts.ci && !opts.force) {
|
|
14278
14410
|
errLog(`error: massu.config.yaml already exists at ${configPath}`);
|
|
14279
14411
|
errLog(" rerun with --force to overwrite, or remove the file first");
|
|
@@ -14301,7 +14433,7 @@ async function runInit(argv, overrides) {
|
|
|
14301
14433
|
const validation2 = validateWrittenConfig(configPath, projectRoot, false);
|
|
14302
14434
|
if (validation2 !== null) {
|
|
14303
14435
|
try {
|
|
14304
|
-
|
|
14436
|
+
rmSync3(configPath, { force: true });
|
|
14305
14437
|
} catch {
|
|
14306
14438
|
}
|
|
14307
14439
|
errLog(`error: template config failed validation: ${validation2}`);
|
|
@@ -14379,7 +14511,7 @@ async function runInit(argv, overrides) {
|
|
|
14379
14511
|
const validation = validateWrittenConfig(configPath, projectRoot, !emptyStack);
|
|
14380
14512
|
if (validation !== null) {
|
|
14381
14513
|
try {
|
|
14382
|
-
|
|
14514
|
+
rmSync3(configPath, { force: true });
|
|
14383
14515
|
} catch {
|
|
14384
14516
|
}
|
|
14385
14517
|
errLog(`error: generated config failed validation: ${validation}`);
|
|
@@ -14412,8 +14544,8 @@ function installSideEffects(projectRoot, log, skipCommands = false, emptyStack =
|
|
|
14412
14544
|
const commandStats = cmdResult.assets.commands;
|
|
14413
14545
|
const stackResolved = !emptyStack && commandStats && (commandStats.installed > 0 || commandStats.updated > 0 || commandStats.kept > 0);
|
|
14414
14546
|
if (!stackResolved) {
|
|
14415
|
-
const placeholderPath =
|
|
14416
|
-
if (!
|
|
14547
|
+
const placeholderPath = resolve8(cmdResult.claudeDir, "commands", "_massu-needs-stack.md");
|
|
14548
|
+
if (!existsSync12(placeholderPath)) {
|
|
14417
14549
|
const placeholderBody = [
|
|
14418
14550
|
"# Massu \u2014 stack not yet detected",
|
|
14419
14551
|
"",
|
|
@@ -14434,8 +14566,8 @@ function installSideEffects(projectRoot, log, skipCommands = false, emptyStack =
|
|
|
14434
14566
|
"\u2014 Massu"
|
|
14435
14567
|
].join("\n");
|
|
14436
14568
|
try {
|
|
14437
|
-
|
|
14438
|
-
|
|
14569
|
+
mkdirSync6(resolve8(cmdResult.claudeDir, "commands"), { recursive: true });
|
|
14570
|
+
writeFileSync3(placeholderPath, placeholderBody, "utf-8");
|
|
14439
14571
|
log(" Wrote _massu-needs-stack.md placeholder (no stack detected yet)");
|
|
14440
14572
|
} catch {
|
|
14441
14573
|
}
|
|
@@ -14457,8 +14589,8 @@ function installSideEffects(projectRoot, log, skipCommands = false, emptyStack =
|
|
|
14457
14589
|
(async () => {
|
|
14458
14590
|
try {
|
|
14459
14591
|
const encodedRoot = encodeMemoryDirName(projectRoot);
|
|
14460
|
-
const memoryDir =
|
|
14461
|
-
const memFiles =
|
|
14592
|
+
const memoryDir = resolve8(homedir5(), ".claude", "projects", encodedRoot, "memory");
|
|
14593
|
+
const memFiles = existsSync12(memoryDir) ? readdirSync10(memoryDir).filter((f2) => f2.endsWith(".md") && f2 !== "MEMORY.md") : [];
|
|
14462
14594
|
if (memFiles.length > 0) {
|
|
14463
14595
|
const { getMemoryDb: getMemoryDb2 } = await Promise.resolve().then(() => (init_memory_db(), memory_db_exports));
|
|
14464
14596
|
const db = getMemoryDb2();
|
|
@@ -14648,6 +14780,28 @@ var init_license_response_verifier = __esm({
|
|
|
14648
14780
|
});
|
|
14649
14781
|
|
|
14650
14782
|
// src/license.ts
|
|
14783
|
+
var license_exports = {};
|
|
14784
|
+
__export(license_exports, {
|
|
14785
|
+
PLAN_TO_TIER_MAP: () => PLAN_TO_TIER_MAP,
|
|
14786
|
+
TOOL_TIER_MAP: () => TOOL_TIER_MAP,
|
|
14787
|
+
_resetCachedTier: () => _resetCachedTier,
|
|
14788
|
+
_setCachedTierForTest: () => _setCachedTierForTest,
|
|
14789
|
+
annotateToolDefinitions: () => annotateToolDefinitions,
|
|
14790
|
+
daysUntilExpiry: () => daysUntilExpiry,
|
|
14791
|
+
getCachedOrgId: () => getCachedOrgId,
|
|
14792
|
+
getCachedTierReadOnly: () => getCachedTierReadOnly,
|
|
14793
|
+
getCurrentTier: () => getCurrentTier,
|
|
14794
|
+
getLicenseInfo: () => getLicenseInfo,
|
|
14795
|
+
getLicenseToolDefinitions: () => getLicenseToolDefinitions,
|
|
14796
|
+
getToolTier: () => getToolTier,
|
|
14797
|
+
handleLicenseToolCall: () => handleLicenseToolCall,
|
|
14798
|
+
isCloudFeatureAvailable: () => isCloudFeatureAvailable,
|
|
14799
|
+
isLicenseTool: () => isLicenseTool,
|
|
14800
|
+
isToolAllowed: () => isToolAllowed,
|
|
14801
|
+
tierLevel: () => tierLevel,
|
|
14802
|
+
updateLicenseCache: () => updateLicenseCache,
|
|
14803
|
+
validateLicense: () => validateLicense
|
|
14804
|
+
});
|
|
14651
14805
|
import { createHash as createHash5 } from "crypto";
|
|
14652
14806
|
function warnLicenseSigOnce(reason) {
|
|
14653
14807
|
if (_warnedLicenseSig) return;
|
|
@@ -14713,11 +14867,12 @@ async function validateLicense(apiKey) {
|
|
|
14713
14867
|
const lastValidated = new Date(cached.last_validated);
|
|
14714
14868
|
const hourAgo = new Date(Date.now() - 60 * 60 * 1e3);
|
|
14715
14869
|
if (lastValidated > hourAgo) {
|
|
14716
|
-
return trusted;
|
|
14870
|
+
return { ...trusted, outcome: "cache_fresh" };
|
|
14717
14871
|
}
|
|
14718
14872
|
}
|
|
14719
14873
|
const config = getConfig();
|
|
14720
14874
|
const endpoint = config.cloud?.endpoint;
|
|
14875
|
+
let fallbackOutcome = "no_endpoint";
|
|
14721
14876
|
if (endpoint && /^https?:\/\/.+/.test(endpoint)) {
|
|
14722
14877
|
try {
|
|
14723
14878
|
const response = await fetch(`${endpoint}/validate-key`, {
|
|
@@ -14749,21 +14904,23 @@ async function validateLicense(apiKey) {
|
|
|
14749
14904
|
features,
|
|
14750
14905
|
sigResult.kind === "valid" ? data : null
|
|
14751
14906
|
);
|
|
14752
|
-
return { tier, validUntil, features };
|
|
14907
|
+
return { tier, validUntil, features, outcome: "validated" };
|
|
14753
14908
|
}
|
|
14754
|
-
return { tier: "free", validUntil: "", features: [] };
|
|
14909
|
+
return { tier: "free", validUntil: "", features: [], outcome: "rejected" };
|
|
14755
14910
|
}
|
|
14911
|
+
fallbackOutcome = "server_error";
|
|
14756
14912
|
} catch {
|
|
14913
|
+
fallbackOutcome = "network_error";
|
|
14757
14914
|
}
|
|
14758
14915
|
}
|
|
14759
14916
|
if (cached && trusted) {
|
|
14760
14917
|
const lastValidated = new Date(cached.last_validated);
|
|
14761
14918
|
const sevenDaysAgo = new Date(Date.now() - GRACE_PERIOD_MS);
|
|
14762
14919
|
if (lastValidated > sevenDaysAgo) {
|
|
14763
|
-
return trusted;
|
|
14920
|
+
return { ...trusted, outcome: "grace" };
|
|
14764
14921
|
}
|
|
14765
14922
|
}
|
|
14766
|
-
return { tier: "free", validUntil: "", features: [] };
|
|
14923
|
+
return { tier: "free", validUntil: "", features: [], outcome: fallbackOutcome };
|
|
14767
14924
|
} finally {
|
|
14768
14925
|
memDb.close();
|
|
14769
14926
|
}
|
|
@@ -14819,7 +14976,7 @@ async function getCurrentTier() {
|
|
|
14819
14976
|
const config = getConfig();
|
|
14820
14977
|
const apiKey = config.cloud?.apiKey;
|
|
14821
14978
|
if (!apiKey) {
|
|
14822
|
-
cachedTier = { tier: "free", validUntil: "", features: [] };
|
|
14979
|
+
cachedTier = { tier: "free", validUntil: "", features: [], outcome: "no_key" };
|
|
14823
14980
|
cachedTierTimestamp = Date.now();
|
|
14824
14981
|
return "free";
|
|
14825
14982
|
}
|
|
@@ -14952,6 +15109,14 @@ async function handleLicenseToolCall(name, _args, _memDb) {
|
|
|
14952
15109
|
}
|
|
14953
15110
|
return { content: [{ type: "text", text: `Unknown license tool: ${name}` }] };
|
|
14954
15111
|
}
|
|
15112
|
+
function _resetCachedTier() {
|
|
15113
|
+
cachedTier = null;
|
|
15114
|
+
cachedTierTimestamp = 0;
|
|
15115
|
+
}
|
|
15116
|
+
function _setCachedTierForTest(tier) {
|
|
15117
|
+
cachedTier = { tier, validUntil: "", features: [] };
|
|
15118
|
+
cachedTierTimestamp = Date.now();
|
|
15119
|
+
}
|
|
14955
15120
|
var _warnedLicenseSig, TIER_LEVELS, TOOL_TIER_MAP, PLAN_TO_TIER_MAP, TIER_LABELS, cachedTier, cachedTierTimestamp, IN_MEMORY_CACHE_TTL_MS, GRACE_PERIOD_MS;
|
|
14956
15121
|
var init_license = __esm({
|
|
14957
15122
|
"src/license.ts"() {
|
|
@@ -15107,20 +15272,21 @@ var init_hook_registry = __esm({
|
|
|
15107
15272
|
// src/commands/doctor.ts
|
|
15108
15273
|
var doctor_exports = {};
|
|
15109
15274
|
__export(doctor_exports, {
|
|
15275
|
+
formatLicenseCheck: () => formatLicenseCheck,
|
|
15110
15276
|
runDoctor: () => runDoctor,
|
|
15111
15277
|
runValidateConfig: () => runValidateConfig
|
|
15112
15278
|
});
|
|
15113
|
-
import { existsSync as
|
|
15114
|
-
import { resolve as
|
|
15279
|
+
import { existsSync as existsSync13, readFileSync as readFileSync13, readdirSync as readdirSync11 } from "fs";
|
|
15280
|
+
import { resolve as resolve9, dirname as dirname7 } from "path";
|
|
15115
15281
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
15116
15282
|
import { parse as parseYaml4 } from "yaml";
|
|
15117
15283
|
function checkConfig(projectRoot) {
|
|
15118
|
-
const configPath =
|
|
15119
|
-
if (!
|
|
15284
|
+
const configPath = resolve9(projectRoot, "massu.config.yaml");
|
|
15285
|
+
if (!existsSync13(configPath)) {
|
|
15120
15286
|
return { name: "Configuration", status: "fail", detail: "massu.config.yaml not found. Run: npx massu init" };
|
|
15121
15287
|
}
|
|
15122
15288
|
try {
|
|
15123
|
-
const content =
|
|
15289
|
+
const content = readFileSync13(configPath, "utf-8");
|
|
15124
15290
|
const parsed = parseYaml4(content);
|
|
15125
15291
|
if (!parsed || typeof parsed !== "object") {
|
|
15126
15292
|
return { name: "Configuration", status: "fail", detail: "massu.config.yaml is empty or invalid YAML" };
|
|
@@ -15132,11 +15298,11 @@ function checkConfig(projectRoot) {
|
|
|
15132
15298
|
}
|
|
15133
15299
|
function checkMcpServer(projectRoot) {
|
|
15134
15300
|
const mcpPath = getResolvedPaths().mcpJsonPath;
|
|
15135
|
-
if (!
|
|
15301
|
+
if (!existsSync13(mcpPath)) {
|
|
15136
15302
|
return { name: "MCP Server", status: "fail", detail: ".mcp.json not found. Run: npx massu init" };
|
|
15137
15303
|
}
|
|
15138
15304
|
try {
|
|
15139
|
-
const content = JSON.parse(
|
|
15305
|
+
const content = JSON.parse(readFileSync13(mcpPath, "utf-8"));
|
|
15140
15306
|
const servers = content.mcpServers ?? {};
|
|
15141
15307
|
if (!servers.massu) {
|
|
15142
15308
|
return { name: "MCP Server", status: "fail", detail: "massu not registered in .mcp.json. Run: npx massu init" };
|
|
@@ -15148,7 +15314,7 @@ function checkMcpServer(projectRoot) {
|
|
|
15148
15314
|
}
|
|
15149
15315
|
function checkHooksConfig(projectRoot) {
|
|
15150
15316
|
const settingsPath = getResolvedPaths().settingsLocalPath;
|
|
15151
|
-
if (!
|
|
15317
|
+
if (!existsSync13(settingsPath)) {
|
|
15152
15318
|
return { name: "Hooks Config", status: "fail", detail: ".claude/settings.local.json not found. Run: npx massu init" };
|
|
15153
15319
|
}
|
|
15154
15320
|
try {
|
|
@@ -15176,11 +15342,11 @@ function checkHooksConfig(projectRoot) {
|
|
|
15176
15342
|
}
|
|
15177
15343
|
}
|
|
15178
15344
|
function checkHookFiles(projectRoot) {
|
|
15179
|
-
const nodeModulesHooksDir =
|
|
15345
|
+
const nodeModulesHooksDir = resolve9(projectRoot, "node_modules/@massu/core/dist/hooks");
|
|
15180
15346
|
let hooksDir = nodeModulesHooksDir;
|
|
15181
|
-
if (!
|
|
15182
|
-
const devHooksDir =
|
|
15183
|
-
if (
|
|
15347
|
+
if (!existsSync13(nodeModulesHooksDir)) {
|
|
15348
|
+
const devHooksDir = resolve9(__dirname3, "../../dist/hooks");
|
|
15349
|
+
if (existsSync13(devHooksDir)) {
|
|
15184
15350
|
hooksDir = devHooksDir;
|
|
15185
15351
|
} else {
|
|
15186
15352
|
return { name: "Hook Files", status: "fail", detail: "Compiled hooks not found. Run: npm install @massu/core" };
|
|
@@ -15188,7 +15354,7 @@ function checkHookFiles(projectRoot) {
|
|
|
15188
15354
|
}
|
|
15189
15355
|
const missing = [];
|
|
15190
15356
|
for (const hookFile of EXPECTED_HOOKS) {
|
|
15191
|
-
if (!
|
|
15357
|
+
if (!existsSync13(resolve9(hooksDir, hookFile))) {
|
|
15192
15358
|
missing.push(hookFile);
|
|
15193
15359
|
}
|
|
15194
15360
|
}
|
|
@@ -15214,8 +15380,8 @@ function checkNodeVersion() {
|
|
|
15214
15380
|
return { name: "Node.js", status: "fail", detail: `v${version} \u2014 Node.js 18+ is required` };
|
|
15215
15381
|
}
|
|
15216
15382
|
async function checkGitRepo(projectRoot) {
|
|
15217
|
-
const gitDir =
|
|
15218
|
-
if (!
|
|
15383
|
+
const gitDir = resolve9(projectRoot, ".git");
|
|
15384
|
+
if (!existsSync13(gitDir)) {
|
|
15219
15385
|
return { name: "Git Repository", status: "warn", detail: "Not a git repository (optional but recommended)" };
|
|
15220
15386
|
}
|
|
15221
15387
|
try {
|
|
@@ -15233,7 +15399,7 @@ async function checkGitRepo(projectRoot) {
|
|
|
15233
15399
|
}
|
|
15234
15400
|
function checkKnowledgeDb(projectRoot) {
|
|
15235
15401
|
const knowledgeDbPath = getResolvedPaths().memoryDbPath;
|
|
15236
|
-
if (!
|
|
15402
|
+
if (!existsSync13(knowledgeDbPath)) {
|
|
15237
15403
|
return {
|
|
15238
15404
|
name: "Knowledge DB",
|
|
15239
15405
|
status: "warn",
|
|
@@ -15244,7 +15410,7 @@ function checkKnowledgeDb(projectRoot) {
|
|
|
15244
15410
|
}
|
|
15245
15411
|
function checkMemoryDir(_projectRoot2) {
|
|
15246
15412
|
const memoryDir = getResolvedPaths().memoryDir;
|
|
15247
|
-
if (!
|
|
15413
|
+
if (!existsSync13(memoryDir)) {
|
|
15248
15414
|
return {
|
|
15249
15415
|
name: "Memory Directory",
|
|
15250
15416
|
status: "warn",
|
|
@@ -15255,7 +15421,7 @@ function checkMemoryDir(_projectRoot2) {
|
|
|
15255
15421
|
}
|
|
15256
15422
|
function checkShellHooksWired(_projectRoot2) {
|
|
15257
15423
|
const settingsPath = getResolvedPaths().settingsLocalPath;
|
|
15258
|
-
if (!
|
|
15424
|
+
if (!existsSync13(settingsPath)) {
|
|
15259
15425
|
return {
|
|
15260
15426
|
name: "Shell Hooks",
|
|
15261
15427
|
status: "fail",
|
|
@@ -15283,26 +15449,43 @@ function checkShellHooksWired(_projectRoot2) {
|
|
|
15283
15449
|
};
|
|
15284
15450
|
}
|
|
15285
15451
|
}
|
|
15452
|
+
function formatLicenseCheck(input) {
|
|
15453
|
+
const { source, tier, validUntil, outcome } = input;
|
|
15454
|
+
if (source === "none") {
|
|
15455
|
+
return { name: "License", status: "pass", detail: "Free (no API key configured)" };
|
|
15456
|
+
}
|
|
15457
|
+
const label = apiKeySourceLabel(source);
|
|
15458
|
+
if (tier !== "free") {
|
|
15459
|
+
const cap = tier.charAt(0).toUpperCase() + tier.slice(1);
|
|
15460
|
+
const until = validUntil ? `, valid until ${validUntil}` : "";
|
|
15461
|
+
return { name: "License", status: "pass", detail: `${cap} (via ${label}${until})` };
|
|
15462
|
+
}
|
|
15463
|
+
if (outcome === "server_error") {
|
|
15464
|
+
return {
|
|
15465
|
+
name: "License",
|
|
15466
|
+
status: "warn",
|
|
15467
|
+
detail: `Could not validate \u2014 license server error (tier UNKNOWN; key present via ${label}). Not a Free downgrade; retries automatically.`
|
|
15468
|
+
};
|
|
15469
|
+
}
|
|
15470
|
+
if (outcome === "network_error" || outcome === "no_endpoint") {
|
|
15471
|
+
return {
|
|
15472
|
+
name: "License",
|
|
15473
|
+
status: "warn",
|
|
15474
|
+
detail: `Could not reach license server (tier UNKNOWN; key present via ${label}). Not a Free downgrade; retries automatically.`
|
|
15475
|
+
};
|
|
15476
|
+
}
|
|
15477
|
+
return {
|
|
15478
|
+
name: "License",
|
|
15479
|
+
status: "warn",
|
|
15480
|
+
detail: `Free \u2014 key present via ${label} but validated to Free (check key / subscription)`
|
|
15481
|
+
};
|
|
15482
|
+
}
|
|
15286
15483
|
async function checkLicenseStatus() {
|
|
15287
15484
|
try {
|
|
15485
|
+
const source = getResolvedApiKeySource();
|
|
15288
15486
|
const tier = await getCurrentTier();
|
|
15289
15487
|
const info = await getLicenseInfo();
|
|
15290
|
-
|
|
15291
|
-
return { name: "License", status: "pass", detail: "Free (no API key configured)" };
|
|
15292
|
-
}
|
|
15293
|
-
const days = await daysUntilExpiry();
|
|
15294
|
-
if (days >= 0 && info.validUntil) {
|
|
15295
|
-
return {
|
|
15296
|
-
name: "License",
|
|
15297
|
-
status: "pass",
|
|
15298
|
-
detail: `${tier.charAt(0).toUpperCase() + tier.slice(1)} (valid until ${info.validUntil})`
|
|
15299
|
-
};
|
|
15300
|
-
}
|
|
15301
|
-
return {
|
|
15302
|
-
name: "License",
|
|
15303
|
-
status: "pass",
|
|
15304
|
-
detail: `${tier.charAt(0).toUpperCase() + tier.slice(1)} (valid)`
|
|
15305
|
-
};
|
|
15488
|
+
return formatLicenseCheck({ source, tier, validUntil: info.validUntil, outcome: info.outcome });
|
|
15306
15489
|
} catch (err) {
|
|
15307
15490
|
return {
|
|
15308
15491
|
name: "License",
|
|
@@ -15311,11 +15494,31 @@ async function checkLicenseStatus() {
|
|
|
15311
15494
|
};
|
|
15312
15495
|
}
|
|
15313
15496
|
}
|
|
15497
|
+
async function checkApiKeyHygiene(projectRoot) {
|
|
15498
|
+
if (getResolvedApiKeySource() !== "config") return null;
|
|
15499
|
+
try {
|
|
15500
|
+
const { spawnSync: spawnSync4 } = await import("child_process");
|
|
15501
|
+
const res = spawnSync4("git", ["ls-files", "--error-unmatch", "massu.config.yaml"], {
|
|
15502
|
+
cwd: projectRoot,
|
|
15503
|
+
timeout: 5e3,
|
|
15504
|
+
encoding: "utf-8"
|
|
15505
|
+
});
|
|
15506
|
+
if (res.status === 0) {
|
|
15507
|
+
return {
|
|
15508
|
+
name: "API Key Hygiene",
|
|
15509
|
+
status: "warn",
|
|
15510
|
+
detail: "API key is committed in massu.config.yaml \u2014 move it to the MASSU_API_KEY env var or 'massu login' (~/.massu/credentials)"
|
|
15511
|
+
};
|
|
15512
|
+
}
|
|
15513
|
+
} catch {
|
|
15514
|
+
}
|
|
15515
|
+
return null;
|
|
15516
|
+
}
|
|
15314
15517
|
function checkPythonHealth(projectRoot) {
|
|
15315
15518
|
const config = getConfig();
|
|
15316
15519
|
if (!config.python?.root) return null;
|
|
15317
|
-
const pythonRoot =
|
|
15318
|
-
if (!
|
|
15520
|
+
const pythonRoot = resolve9(projectRoot, config.python.root);
|
|
15521
|
+
if (!existsSync13(pythonRoot)) {
|
|
15319
15522
|
return {
|
|
15320
15523
|
name: "Python",
|
|
15321
15524
|
status: "fail",
|
|
@@ -15334,8 +15537,8 @@ function checkPythonHealth(projectRoot) {
|
|
|
15334
15537
|
if (entry.isDirectory()) {
|
|
15335
15538
|
const excludeDirs = config.python?.exclude_dirs || ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"];
|
|
15336
15539
|
if (!excludeDirs.includes(entry.name)) {
|
|
15337
|
-
const subdir =
|
|
15338
|
-
if (depth <= 2 && !
|
|
15540
|
+
const subdir = resolve9(dir, entry.name);
|
|
15541
|
+
if (depth <= 2 && !existsSync13(resolve9(subdir, "__init__.py"))) {
|
|
15339
15542
|
try {
|
|
15340
15543
|
const subEntries = readdirSync11(subdir);
|
|
15341
15544
|
if (subEntries.some((f2) => f2.endsWith(".py") && f2 !== "__init__.py")) {
|
|
@@ -15405,6 +15608,8 @@ async function runDoctor() {
|
|
|
15405
15608
|
];
|
|
15406
15609
|
const pythonCheck = checkPythonHealth(projectRoot);
|
|
15407
15610
|
if (pythonCheck) checks.push(pythonCheck);
|
|
15611
|
+
const hygieneCheck = await checkApiKeyHygiene(projectRoot);
|
|
15612
|
+
if (hygieneCheck) checks.push(hygieneCheck);
|
|
15408
15613
|
let passed = 0;
|
|
15409
15614
|
let failed = 0;
|
|
15410
15615
|
let warned = 0;
|
|
@@ -15430,15 +15635,15 @@ async function runDoctor() {
|
|
|
15430
15635
|
}
|
|
15431
15636
|
async function runValidateConfig() {
|
|
15432
15637
|
const projectRoot = process.cwd();
|
|
15433
|
-
const configPath =
|
|
15434
|
-
if (!
|
|
15638
|
+
const configPath = resolve9(projectRoot, "massu.config.yaml");
|
|
15639
|
+
if (!existsSync13(configPath)) {
|
|
15435
15640
|
console.error("Error: massu.config.yaml not found in current directory");
|
|
15436
15641
|
console.error("Run: npx massu init");
|
|
15437
15642
|
process.exit(1);
|
|
15438
15643
|
return;
|
|
15439
15644
|
}
|
|
15440
15645
|
try {
|
|
15441
|
-
const content =
|
|
15646
|
+
const content = readFileSync13(configPath, "utf-8");
|
|
15442
15647
|
const parsed = parseYaml4(content);
|
|
15443
15648
|
if (!parsed || typeof parsed !== "object") {
|
|
15444
15649
|
console.error("Error: massu.config.yaml is empty or not a valid YAML object");
|
|
@@ -15476,6 +15681,7 @@ var init_doctor = __esm({
|
|
|
15476
15681
|
"use strict";
|
|
15477
15682
|
init_config();
|
|
15478
15683
|
init_license();
|
|
15684
|
+
init_credentials();
|
|
15479
15685
|
init_settings_local();
|
|
15480
15686
|
init_hook_registry();
|
|
15481
15687
|
__filename3 = fileURLToPath3(import.meta.url);
|
|
@@ -15484,6 +15690,114 @@ var init_doctor = __esm({
|
|
|
15484
15690
|
}
|
|
15485
15691
|
});
|
|
15486
15692
|
|
|
15693
|
+
// src/commands/login.ts
|
|
15694
|
+
var login_exports = {};
|
|
15695
|
+
__export(login_exports, {
|
|
15696
|
+
runLogin: () => runLogin,
|
|
15697
|
+
runLogout: () => runLogout
|
|
15698
|
+
});
|
|
15699
|
+
import { createInterface as createInterface2 } from "readline";
|
|
15700
|
+
function maskKey(k3) {
|
|
15701
|
+
return k3.length <= 12 ? "****" : `${k3.slice(0, API_KEY_PREFIX.length)}\u2026${k3.slice(-4)}`;
|
|
15702
|
+
}
|
|
15703
|
+
function promptHidden(question) {
|
|
15704
|
+
return new Promise((resolvePromise) => {
|
|
15705
|
+
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
15706
|
+
let promptWritten = false;
|
|
15707
|
+
rl._writeToOutput = (chunk) => {
|
|
15708
|
+
if (!promptWritten) {
|
|
15709
|
+
rl.output.write(question);
|
|
15710
|
+
promptWritten = true;
|
|
15711
|
+
}
|
|
15712
|
+
void chunk;
|
|
15713
|
+
};
|
|
15714
|
+
rl.question(question, (answer) => {
|
|
15715
|
+
rl.close();
|
|
15716
|
+
process.stdout.write("\n");
|
|
15717
|
+
resolvePromise(answer);
|
|
15718
|
+
});
|
|
15719
|
+
});
|
|
15720
|
+
}
|
|
15721
|
+
async function readStdinKey() {
|
|
15722
|
+
const chunks = [];
|
|
15723
|
+
for await (const chunk of process.stdin) {
|
|
15724
|
+
chunks.push(chunk);
|
|
15725
|
+
}
|
|
15726
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
15727
|
+
}
|
|
15728
|
+
async function runLogin(argv) {
|
|
15729
|
+
const keyFlagIdx = argv.indexOf("--key");
|
|
15730
|
+
const noVerify = argv.includes("--no-verify");
|
|
15731
|
+
let key;
|
|
15732
|
+
if (keyFlagIdx >= 0 && argv[keyFlagIdx + 1]) {
|
|
15733
|
+
key = argv[keyFlagIdx + 1];
|
|
15734
|
+
} else if (process.stdin.isTTY) {
|
|
15735
|
+
key = await promptHidden("Massu API key: ");
|
|
15736
|
+
} else {
|
|
15737
|
+
key = await readStdinKey();
|
|
15738
|
+
}
|
|
15739
|
+
key = (key ?? "").trim();
|
|
15740
|
+
if (!key.startsWith(API_KEY_PREFIX)) {
|
|
15741
|
+
console.error(`Error: API key must start with "${API_KEY_PREFIX}".`);
|
|
15742
|
+
process.exit(1);
|
|
15743
|
+
return;
|
|
15744
|
+
}
|
|
15745
|
+
const path = writeUserCredentials(key);
|
|
15746
|
+
console.log(`
|
|
15747
|
+
Saved API key ${maskKey(key)} to ${path} (permissions 0600).`);
|
|
15748
|
+
console.log("This file lives outside every repository \u2014 your key is never committed to git.");
|
|
15749
|
+
if (!noVerify) {
|
|
15750
|
+
try {
|
|
15751
|
+
const { resetConfig: resetConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
15752
|
+
resetConfig2();
|
|
15753
|
+
const { validateLicense: validateLicense2 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
15754
|
+
const info = await validateLicense2(key);
|
|
15755
|
+
if (info.tier !== "free") {
|
|
15756
|
+
const cap = info.tier.charAt(0).toUpperCase() + info.tier.slice(1);
|
|
15757
|
+
console.log(
|
|
15758
|
+
`Verified: ${cap} tier${info.validUntil ? `, valid until ${info.validUntil}` : ""}.`
|
|
15759
|
+
);
|
|
15760
|
+
} else {
|
|
15761
|
+
switch (info.outcome) {
|
|
15762
|
+
case "server_error":
|
|
15763
|
+
console.log(
|
|
15764
|
+
"Saved, but could NOT verify your key: the license server returned an error."
|
|
15765
|
+
);
|
|
15766
|
+
console.log(
|
|
15767
|
+
"This is NOT a Free determination \u2014 your tier is unknown. It will re-validate automatically on next use; if this persists, the license server may be down."
|
|
15768
|
+
);
|
|
15769
|
+
break;
|
|
15770
|
+
case "network_error":
|
|
15771
|
+
case "no_endpoint":
|
|
15772
|
+
console.log(
|
|
15773
|
+
"Saved; could not reach the license server right now (offline). Your key will validate automatically on next use."
|
|
15774
|
+
);
|
|
15775
|
+
break;
|
|
15776
|
+
default:
|
|
15777
|
+
console.log(
|
|
15778
|
+
"Verified: this key is on the Free tier (check the key or your subscription at https://massu.ai/dashboard)."
|
|
15779
|
+
);
|
|
15780
|
+
}
|
|
15781
|
+
}
|
|
15782
|
+
} catch {
|
|
15783
|
+
console.log("Saved; could not verify online right now (it will validate on next use).");
|
|
15784
|
+
}
|
|
15785
|
+
}
|
|
15786
|
+
console.log("");
|
|
15787
|
+
}
|
|
15788
|
+
async function runLogout() {
|
|
15789
|
+
const removed = removeUserCredentials();
|
|
15790
|
+
console.log(
|
|
15791
|
+
removed ? `Removed stored credentials at ${credentialsPath()}.` : "No stored credentials to remove."
|
|
15792
|
+
);
|
|
15793
|
+
}
|
|
15794
|
+
var init_login = __esm({
|
|
15795
|
+
"src/commands/login.ts"() {
|
|
15796
|
+
"use strict";
|
|
15797
|
+
init_credentials();
|
|
15798
|
+
}
|
|
15799
|
+
});
|
|
15800
|
+
|
|
15487
15801
|
// src/commands/install-hooks.ts
|
|
15488
15802
|
var install_hooks_exports = {};
|
|
15489
15803
|
__export(install_hooks_exports, {
|
|
@@ -15515,8 +15829,8 @@ __export(hook_runner_exports, {
|
|
|
15515
15829
|
resolveHookFile: () => resolveHookFile,
|
|
15516
15830
|
runHookRunner: () => runHookRunner
|
|
15517
15831
|
});
|
|
15518
|
-
import { existsSync as
|
|
15519
|
-
import { resolve as
|
|
15832
|
+
import { existsSync as existsSync14 } from "fs";
|
|
15833
|
+
import { resolve as resolve10, dirname as dirname8 } from "path";
|
|
15520
15834
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
15521
15835
|
import { spawn } from "child_process";
|
|
15522
15836
|
function resolveHookFile(hookName) {
|
|
@@ -15528,14 +15842,14 @@ function resolveHookFile(hookName) {
|
|
|
15528
15842
|
}
|
|
15529
15843
|
const candidates = [
|
|
15530
15844
|
// Bundled compiled layout: dist/cli.js → ./hooks/<file>.js
|
|
15531
|
-
|
|
15845
|
+
resolve10(__dirname4, "hooks", file),
|
|
15532
15846
|
// TS-source dev / sibling layout: src/commands/ → ../hooks/<file>
|
|
15533
|
-
|
|
15847
|
+
resolve10(__dirname4, "../hooks", file),
|
|
15534
15848
|
// TS-source dev fallback: src/commands/ → ../../dist/hooks/<file>
|
|
15535
|
-
|
|
15849
|
+
resolve10(__dirname4, "../../dist/hooks", file)
|
|
15536
15850
|
];
|
|
15537
15851
|
for (const candidate of candidates) {
|
|
15538
|
-
if (
|
|
15852
|
+
if (existsSync14(candidate)) {
|
|
15539
15853
|
return candidate;
|
|
15540
15854
|
}
|
|
15541
15855
|
}
|
|
@@ -15600,7 +15914,7 @@ __export(permissions_exports, {
|
|
|
15600
15914
|
handlePermissionsSubcommand: () => handlePermissionsSubcommand,
|
|
15601
15915
|
printPermissionsHelp: () => printPermissionsHelp
|
|
15602
15916
|
});
|
|
15603
|
-
import { resolve as
|
|
15917
|
+
import { resolve as resolve11 } from "path";
|
|
15604
15918
|
function resolveClaudeDir2() {
|
|
15605
15919
|
let claudeDirName = ".claude";
|
|
15606
15920
|
try {
|
|
@@ -15608,7 +15922,7 @@ function resolveClaudeDir2() {
|
|
|
15608
15922
|
} catch {
|
|
15609
15923
|
claudeDirName = ".claude";
|
|
15610
15924
|
}
|
|
15611
|
-
return
|
|
15925
|
+
return resolve11(process.cwd(), claudeDirName);
|
|
15612
15926
|
}
|
|
15613
15927
|
async function handlePermissionsSubcommand(args2) {
|
|
15614
15928
|
const sub = args2[0];
|
|
@@ -15738,8 +16052,8 @@ var init_auto_learning_entitlement = __esm({
|
|
|
15738
16052
|
});
|
|
15739
16053
|
|
|
15740
16054
|
// src/commands/license.ts
|
|
15741
|
-
var
|
|
15742
|
-
__export(
|
|
16055
|
+
var license_exports2 = {};
|
|
16056
|
+
__export(license_exports2, {
|
|
15743
16057
|
handleLicenseSubcommand: () => handleLicenseSubcommand,
|
|
15744
16058
|
printLicenseHelp: () => printLicenseHelp
|
|
15745
16059
|
});
|
|
@@ -15827,8 +16141,8 @@ var init_license2 = __esm({
|
|
|
15827
16141
|
});
|
|
15828
16142
|
|
|
15829
16143
|
// src/changelog-generator.ts
|
|
15830
|
-
import { existsSync as
|
|
15831
|
-
import { resolve as
|
|
16144
|
+
import { existsSync as existsSync15, readFileSync as readFileSync14, readdirSync as readdirSync12 } from "fs";
|
|
16145
|
+
import { resolve as resolve12 } from "path";
|
|
15832
16146
|
function parseCommitsForPlanTokens(subjects) {
|
|
15833
16147
|
const tokens = /* @__PURE__ */ new Set();
|
|
15834
16148
|
const maintenance = [];
|
|
@@ -15845,7 +16159,7 @@ function parseCommitsForPlanTokens(subjects) {
|
|
|
15845
16159
|
function loadPlanSummaries(tokens, planDir) {
|
|
15846
16160
|
const result = /* @__PURE__ */ new Map();
|
|
15847
16161
|
if (tokens.size === 0) return result;
|
|
15848
|
-
if (!
|
|
16162
|
+
if (!existsSync15(planDir)) {
|
|
15849
16163
|
throw new Error(`Plan directory does not exist: ${planDir}`);
|
|
15850
16164
|
}
|
|
15851
16165
|
const files = readdirSync12(planDir).filter((f2) => f2.endsWith(".md"));
|
|
@@ -15853,8 +16167,8 @@ function loadPlanSummaries(tokens, planDir) {
|
|
|
15853
16167
|
let matchedFile = null;
|
|
15854
16168
|
let content = "";
|
|
15855
16169
|
for (const file of files) {
|
|
15856
|
-
const path =
|
|
15857
|
-
const text18 =
|
|
16170
|
+
const path = resolve12(planDir, file);
|
|
16171
|
+
const text18 = readFileSync14(path, "utf-8");
|
|
15858
16172
|
const tokenRe = new RegExp(
|
|
15859
16173
|
`^\\*\\*Plan Token\\*\\*:\\s*\`?${token.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")}\`?(\\s|$)`,
|
|
15860
16174
|
"m"
|
|
@@ -15935,8 +16249,8 @@ __export(changelog_exports, {
|
|
|
15935
16249
|
printChangelogHelp: () => printChangelogHelp
|
|
15936
16250
|
});
|
|
15937
16251
|
import { execSync } from "child_process";
|
|
15938
|
-
import { existsSync as
|
|
15939
|
-
import { resolve as
|
|
16252
|
+
import { existsSync as existsSync16, readFileSync as readFileSync15 } from "fs";
|
|
16253
|
+
import { resolve as resolve13 } from "path";
|
|
15940
16254
|
function resolveRepoRoot() {
|
|
15941
16255
|
try {
|
|
15942
16256
|
return execSync("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
|
|
@@ -15960,25 +16274,25 @@ function getCommitSubjects(range) {
|
|
|
15960
16274
|
}
|
|
15961
16275
|
}
|
|
15962
16276
|
function getCurrentVersion(repoRoot) {
|
|
15963
|
-
const pkgPath =
|
|
15964
|
-
if (!
|
|
15965
|
-
const pkg = JSON.parse(
|
|
16277
|
+
const pkgPath = resolve13(repoRoot, "packages/core/package.json");
|
|
16278
|
+
if (!existsSync16(pkgPath)) return "0.0.0";
|
|
16279
|
+
const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
|
|
15966
16280
|
return pkg.version || "0.0.0";
|
|
15967
16281
|
}
|
|
15968
16282
|
function todayDate() {
|
|
15969
16283
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
15970
16284
|
}
|
|
15971
16285
|
function getLatestChangelogEntryBody(repoRoot) {
|
|
15972
|
-
const path =
|
|
15973
|
-
if (!
|
|
15974
|
-
const content =
|
|
16286
|
+
const path = resolve13(repoRoot, "CHANGELOG.md");
|
|
16287
|
+
if (!existsSync16(path)) return "";
|
|
16288
|
+
const content = readFileSync15(path, "utf-8");
|
|
15975
16289
|
const m3 = content.match(/^## \[[\d.]+\][^\n]*\n([\s\S]*?)(?=\n## \[|$)/m);
|
|
15976
16290
|
return m3 ? m3[1] : "";
|
|
15977
16291
|
}
|
|
15978
16292
|
async function handleChangelogSubcommand(args2) {
|
|
15979
16293
|
const sub = args2[0];
|
|
15980
16294
|
const repoRoot = resolveRepoRoot();
|
|
15981
|
-
const planDir =
|
|
16295
|
+
const planDir = resolve13(repoRoot, "docs/plans");
|
|
15982
16296
|
switch (sub) {
|
|
15983
16297
|
case "generate": {
|
|
15984
16298
|
const lastTag = getLastTag();
|
|
@@ -16189,7 +16503,7 @@ var init_rule_pack_schema = __esm({
|
|
|
16189
16503
|
});
|
|
16190
16504
|
|
|
16191
16505
|
// src/rule-pack-sync.ts
|
|
16192
|
-
import { existsSync as
|
|
16506
|
+
import { existsSync as existsSync17, writeFileSync as writeFileSync4, mkdirSync as mkdirSync7 } from "fs";
|
|
16193
16507
|
import { join as join11, dirname as dirname9 } from "path";
|
|
16194
16508
|
async function pullInstalledPackRules(db, opts = {}) {
|
|
16195
16509
|
const config = getConfig();
|
|
@@ -16252,7 +16566,7 @@ async function pullInstalledPackRules(db, opts = {}) {
|
|
|
16252
16566
|
result.pulled += 1;
|
|
16253
16567
|
const promptHash = packRulePromptHash(pack.slug, rule);
|
|
16254
16568
|
const candidatePath = sidecarPath(projectRoot, promptHash);
|
|
16255
|
-
if (
|
|
16569
|
+
if (existsSync17(candidatePath) || alreadyApplied(db, promptHash)) {
|
|
16256
16570
|
result.skipped += 1;
|
|
16257
16571
|
continue;
|
|
16258
16572
|
}
|
|
@@ -16340,8 +16654,8 @@ function materializeCandidate(projectRoot, candidatePath, promptHash, rule, pack
|
|
|
16340
16654
|
draft_text: draftText
|
|
16341
16655
|
};
|
|
16342
16656
|
const dir = dirname9(candidatePath);
|
|
16343
|
-
if (!
|
|
16344
|
-
|
|
16657
|
+
if (!existsSync17(dir)) mkdirSync7(dir, { recursive: true });
|
|
16658
|
+
writeFileSync4(candidatePath, JSON.stringify(sidecar, null, 2), "utf-8");
|
|
16345
16659
|
}
|
|
16346
16660
|
function emitDropTelemetry(db, eventType, data) {
|
|
16347
16661
|
recordTelemetry(db, eventType, data);
|
|
@@ -16455,8 +16769,8 @@ var show_template_exports = {};
|
|
|
16455
16769
|
__export(show_template_exports, {
|
|
16456
16770
|
runShowTemplate: () => runShowTemplate
|
|
16457
16771
|
});
|
|
16458
|
-
import { existsSync as
|
|
16459
|
-
import { resolve as
|
|
16772
|
+
import { existsSync as existsSync18, readFileSync as readFileSync16 } from "fs";
|
|
16773
|
+
import { resolve as resolve14 } from "path";
|
|
16460
16774
|
function normalizeBaseName(input) {
|
|
16461
16775
|
return input.endsWith(".md") ? input.slice(0, -".md".length) : input;
|
|
16462
16776
|
}
|
|
@@ -16484,14 +16798,14 @@ async function runShowTemplate(args2) {
|
|
|
16484
16798
|
return;
|
|
16485
16799
|
}
|
|
16486
16800
|
const suffix = choice.kind === "hit" ? choice.suffix : "";
|
|
16487
|
-
const file = suffix === "" ?
|
|
16488
|
-
if (!
|
|
16801
|
+
const file = suffix === "" ? resolve14(sourceDir, `${baseName}.md`) : resolve14(sourceDir, `${baseName}${suffix}.md`);
|
|
16802
|
+
if (!existsSync18(file)) {
|
|
16489
16803
|
process.stderr.write(`massu: resolved template "${file}" no longer exists
|
|
16490
16804
|
`);
|
|
16491
16805
|
process.exit(1);
|
|
16492
16806
|
return;
|
|
16493
16807
|
}
|
|
16494
|
-
process.stdout.write(
|
|
16808
|
+
process.stdout.write(readFileSync16(file, "utf-8"));
|
|
16495
16809
|
}
|
|
16496
16810
|
var init_show_template = __esm({
|
|
16497
16811
|
"src/commands/show-template.ts"() {
|
|
@@ -16544,12 +16858,12 @@ var init_passthrough = __esm({
|
|
|
16544
16858
|
});
|
|
16545
16859
|
|
|
16546
16860
|
// src/lib/fileLock.ts
|
|
16547
|
-
import { mkdirSync as
|
|
16861
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync17, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
16548
16862
|
import { dirname as dirname10 } from "path";
|
|
16549
16863
|
import * as lockfile from "proper-lockfile";
|
|
16550
16864
|
function readLockHolderPid(lockPath) {
|
|
16551
16865
|
try {
|
|
16552
|
-
const raw =
|
|
16866
|
+
const raw = readFileSync17(`${lockPath}.pid`, "utf-8").trim();
|
|
16553
16867
|
const pid = Number.parseInt(raw, 10);
|
|
16554
16868
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
16555
16869
|
return pid;
|
|
@@ -16568,7 +16882,7 @@ function busyWaitSync(ms) {
|
|
|
16568
16882
|
Atomics.wait(view, 0, 0, ms);
|
|
16569
16883
|
}
|
|
16570
16884
|
function withFileLockSync(lockPath, fn, opts = {}) {
|
|
16571
|
-
|
|
16885
|
+
mkdirSync8(dirname10(lockPath), { recursive: true });
|
|
16572
16886
|
const staleMs = opts.staleMs ?? 3e4;
|
|
16573
16887
|
const blockMs = opts.retries === 0 ? 0 : opts.blockMs ?? 3e4;
|
|
16574
16888
|
const pollIntervalMs = opts.pollIntervalMs ?? 100;
|
|
@@ -16585,7 +16899,7 @@ function withFileLockSync(lockPath, fn, opts = {}) {
|
|
|
16585
16899
|
realpath: false
|
|
16586
16900
|
});
|
|
16587
16901
|
try {
|
|
16588
|
-
|
|
16902
|
+
writeFileSync5(`${lockPath}.pid`, String(process.pid), "utf-8");
|
|
16589
16903
|
} catch {
|
|
16590
16904
|
}
|
|
16591
16905
|
break;
|
|
@@ -16612,7 +16926,7 @@ function withFileLockSync(lockPath, fn, opts = {}) {
|
|
|
16612
16926
|
} catch {
|
|
16613
16927
|
}
|
|
16614
16928
|
try {
|
|
16615
|
-
|
|
16929
|
+
rmSync4(`${lockPath}.pid`, { force: true });
|
|
16616
16930
|
} catch {
|
|
16617
16931
|
}
|
|
16618
16932
|
}
|
|
@@ -16640,9 +16954,9 @@ var init_fileLock = __esm({
|
|
|
16640
16954
|
});
|
|
16641
16955
|
|
|
16642
16956
|
// src/lib/installLock.ts
|
|
16643
|
-
import { resolve as
|
|
16957
|
+
import { resolve as resolve15 } from "path";
|
|
16644
16958
|
function withInstallLock(projectRoot, fn, opts = {}) {
|
|
16645
|
-
const lockPath =
|
|
16959
|
+
const lockPath = resolve15(projectRoot, ".massu", "installAll.lock");
|
|
16646
16960
|
return withFileLockSync(
|
|
16647
16961
|
lockPath,
|
|
16648
16962
|
fn,
|
|
@@ -16682,8 +16996,8 @@ __export(config_refresh_exports, {
|
|
|
16682
16996
|
mergeRefresh: () => mergeRefresh,
|
|
16683
16997
|
runConfigRefresh: () => runConfigRefresh
|
|
16684
16998
|
});
|
|
16685
|
-
import { existsSync as
|
|
16686
|
-
import { resolve as
|
|
16999
|
+
import { existsSync as existsSync19, readFileSync as readFileSync18, rmSync as rmSync5 } from "fs";
|
|
17000
|
+
import { resolve as resolve16 } from "path";
|
|
16687
17001
|
import { parse as parseYaml5 } from "yaml";
|
|
16688
17002
|
function flatten(obj, prefix3 = "") {
|
|
16689
17003
|
const out = {};
|
|
@@ -16811,17 +17125,17 @@ function renderDiff(diff) {
|
|
|
16811
17125
|
}
|
|
16812
17126
|
async function runConfigRefresh(opts = {}) {
|
|
16813
17127
|
const cwd = opts.cwd ?? process.cwd();
|
|
16814
|
-
const configPath =
|
|
17128
|
+
const configPath = resolve16(cwd, "massu.config.yaml");
|
|
16815
17129
|
const log = opts.silent ? () => {
|
|
16816
17130
|
} : (s) => process.stdout.write(s);
|
|
16817
|
-
if (!
|
|
17131
|
+
if (!existsSync19(configPath)) {
|
|
16818
17132
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
16819
17133
|
if (!opts.silent) process.stderr.write(message + "\n");
|
|
16820
17134
|
return { exitCode: 1, applied: false, dryRun: !!opts.dryRun, diff: [], message };
|
|
16821
17135
|
}
|
|
16822
17136
|
let existing;
|
|
16823
17137
|
try {
|
|
16824
|
-
const content =
|
|
17138
|
+
const content = readFileSync18(configPath, "utf-8");
|
|
16825
17139
|
const parsed = parseYaml5(content);
|
|
16826
17140
|
if (!parsed || typeof parsed !== "object") {
|
|
16827
17141
|
throw new Error("config is not a YAML object");
|
|
@@ -16894,10 +17208,10 @@ async function runConfigRefresh(opts = {}) {
|
|
|
16894
17208
|
`);
|
|
16895
17209
|
const stackResolved = installResult.totalInstalled > 0 || installResult.totalUpdated > 0;
|
|
16896
17210
|
if (stackResolved) {
|
|
16897
|
-
const placeholderPath =
|
|
16898
|
-
if (
|
|
17211
|
+
const placeholderPath = resolve16(installResult.claudeDir, "commands", "_massu-needs-stack.md");
|
|
17212
|
+
if (existsSync19(placeholderPath)) {
|
|
16899
17213
|
try {
|
|
16900
|
-
|
|
17214
|
+
rmSync5(placeholderPath, { force: true });
|
|
16901
17215
|
log("Removed _massu-needs-stack.md (stack now declared).\n");
|
|
16902
17216
|
} catch {
|
|
16903
17217
|
}
|
|
@@ -17004,12 +17318,12 @@ var init_gitToplevel = __esm({
|
|
|
17004
17318
|
});
|
|
17005
17319
|
|
|
17006
17320
|
// src/watch/lockfile-detector.ts
|
|
17007
|
-
import { existsSync as
|
|
17008
|
-
import { resolve as
|
|
17321
|
+
import { existsSync as existsSync20, statSync as statSync8 } from "fs";
|
|
17322
|
+
import { resolve as resolve17 } from "path";
|
|
17009
17323
|
function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WINDOW_MS) {
|
|
17010
17324
|
for (const lf of KNOWN_LOCKFILES) {
|
|
17011
|
-
const p19 =
|
|
17012
|
-
if (!
|
|
17325
|
+
const p19 = resolve17(projectRoot, lf);
|
|
17326
|
+
if (!existsSync20(p19)) continue;
|
|
17013
17327
|
try {
|
|
17014
17328
|
const stat = statSync8(p19);
|
|
17015
17329
|
const delta = now - stat.mtimeMs;
|
|
@@ -17022,7 +17336,7 @@ function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WIN
|
|
|
17022
17336
|
function gitMidOperation(projectRoot) {
|
|
17023
17337
|
const sentinels = ["MERGE_HEAD", "REBASE_HEAD", "CHERRY_PICK_HEAD", "rebase-apply", "rebase-merge"];
|
|
17024
17338
|
for (const s of sentinels) {
|
|
17025
|
-
if (
|
|
17339
|
+
if (existsSync20(resolve17(projectRoot, ".git", s))) return true;
|
|
17026
17340
|
}
|
|
17027
17341
|
return false;
|
|
17028
17342
|
}
|
|
@@ -17221,18 +17535,18 @@ var init_paths = __esm({
|
|
|
17221
17535
|
});
|
|
17222
17536
|
|
|
17223
17537
|
// src/watch/state.ts
|
|
17224
|
-
import { closeSync as closeSync3, existsSync as
|
|
17225
|
-
import { dirname as dirname11, resolve as
|
|
17538
|
+
import { closeSync as closeSync3, existsSync as existsSync21, fsyncSync as fsyncSync3, mkdirSync as mkdirSync9, openSync as openSync3, readFileSync as readFileSync19, renameSync as renameSync4, rmSync as rmSync6, writeFileSync as writeFileSync6, writeSync as writeSync3 } from "fs";
|
|
17539
|
+
import { dirname as dirname11, resolve as resolve18 } from "path";
|
|
17226
17540
|
function watchStatePath(projectRoot) {
|
|
17227
|
-
return
|
|
17541
|
+
return resolve18(projectRoot, ".massu", "watch-state.json");
|
|
17228
17542
|
}
|
|
17229
17543
|
function backupStatePath(projectRoot) {
|
|
17230
|
-
return
|
|
17544
|
+
return resolve18(projectRoot, ".massu", "watch-state.v0.bak.json");
|
|
17231
17545
|
}
|
|
17232
17546
|
function readState(projectRoot) {
|
|
17233
17547
|
const path = watchStatePath(projectRoot);
|
|
17234
|
-
if (!
|
|
17235
|
-
const content =
|
|
17548
|
+
if (!existsSync21(path)) return { ...DEFAULT_STATE };
|
|
17549
|
+
const content = readFileSync19(path, "utf-8");
|
|
17236
17550
|
let raw;
|
|
17237
17551
|
try {
|
|
17238
17552
|
raw = JSON.parse(content);
|
|
@@ -17274,14 +17588,14 @@ function readState(projectRoot) {
|
|
|
17274
17588
|
}
|
|
17275
17589
|
function archiveCorrupt(projectRoot, content) {
|
|
17276
17590
|
const bak = backupStatePath(projectRoot);
|
|
17277
|
-
|
|
17278
|
-
|
|
17591
|
+
mkdirSync9(dirname11(bak), { recursive: true });
|
|
17592
|
+
writeFileSync6(bak, content, "utf-8");
|
|
17279
17593
|
}
|
|
17280
17594
|
function writeStateAtomic(projectRoot, state) {
|
|
17281
17595
|
const path = watchStatePath(projectRoot);
|
|
17282
17596
|
writeStateAtomicCounter = writeStateAtomicCounter + 1 >>> 0;
|
|
17283
17597
|
const tmp = `${path}.${process.pid}.${writeStateAtomicCounter}.tmp`;
|
|
17284
|
-
|
|
17598
|
+
mkdirSync9(dirname11(path), { recursive: true });
|
|
17285
17599
|
let renamed = false;
|
|
17286
17600
|
try {
|
|
17287
17601
|
const fd = openSync3(tmp, "w");
|
|
@@ -17295,9 +17609,9 @@ function writeStateAtomic(projectRoot, state) {
|
|
|
17295
17609
|
renameSync4(tmp, path);
|
|
17296
17610
|
renamed = true;
|
|
17297
17611
|
} finally {
|
|
17298
|
-
if (!renamed &&
|
|
17612
|
+
if (!renamed && existsSync21(tmp)) {
|
|
17299
17613
|
try {
|
|
17300
|
-
|
|
17614
|
+
rmSync6(tmp, { force: true });
|
|
17301
17615
|
} catch {
|
|
17302
17616
|
}
|
|
17303
17617
|
}
|
|
@@ -17577,8 +17891,8 @@ __export(watch_exports, {
|
|
|
17577
17891
|
runWatch: () => runWatch
|
|
17578
17892
|
});
|
|
17579
17893
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
17580
|
-
import { basename as basename5, dirname as dirname12, resolve as
|
|
17581
|
-
import { appendFileSync, existsSync as
|
|
17894
|
+
import { basename as basename5, dirname as dirname12, resolve as resolve19 } from "path";
|
|
17895
|
+
import { appendFileSync, existsSync as existsSync22, mkdirSync as mkdirSync10, readFileSync as readFileSync20 } from "fs";
|
|
17582
17896
|
function parseFlags(args2) {
|
|
17583
17897
|
const out = {
|
|
17584
17898
|
foreground: false,
|
|
@@ -17603,8 +17917,8 @@ function parseFlags(args2) {
|
|
|
17603
17917
|
}
|
|
17604
17918
|
function findClaudeBg() {
|
|
17605
17919
|
const home = process.env.HOME ?? "";
|
|
17606
|
-
const fixed = home ?
|
|
17607
|
-
if (fixed &&
|
|
17920
|
+
const fixed = home ? resolve19(home, ".claude", "bin", "claude-bg") : null;
|
|
17921
|
+
if (fixed && existsSync22(fixed)) return fixed;
|
|
17608
17922
|
const which = spawnSync3("which", ["claude-bg"], { encoding: "utf-8" });
|
|
17609
17923
|
if (which.status === 0 && which.stdout) {
|
|
17610
17924
|
const p19 = which.stdout.trim();
|
|
@@ -17665,7 +17979,7 @@ async function runWatch(args2) {
|
|
|
17665
17979
|
}
|
|
17666
17980
|
function runStatus(root) {
|
|
17667
17981
|
const path = watchStatePath(root);
|
|
17668
|
-
if (!
|
|
17982
|
+
if (!existsSync22(path)) {
|
|
17669
17983
|
process.stdout.write("massu watch: not running (no state file)\n");
|
|
17670
17984
|
return { exitCode: 0 };
|
|
17671
17985
|
}
|
|
@@ -17747,7 +18061,7 @@ async function runForeground(root) {
|
|
|
17747
18061
|
}
|
|
17748
18062
|
throw err;
|
|
17749
18063
|
}
|
|
17750
|
-
return new Promise((
|
|
18064
|
+
return new Promise((resolve42) => {
|
|
17751
18065
|
const shutdown = async () => {
|
|
17752
18066
|
if (stopped) return;
|
|
17753
18067
|
stopped = true;
|
|
@@ -17757,7 +18071,7 @@ async function runForeground(root) {
|
|
|
17757
18071
|
process.chdir(priorCwd);
|
|
17758
18072
|
} catch {
|
|
17759
18073
|
}
|
|
17760
|
-
|
|
18074
|
+
resolve42({ exitCode: 0 });
|
|
17761
18075
|
};
|
|
17762
18076
|
process.on("SIGINT", () => {
|
|
17763
18077
|
void shutdown();
|
|
@@ -17818,23 +18132,23 @@ async function runOnQuiescent(projectRoot) {
|
|
|
17818
18132
|
);
|
|
17819
18133
|
}
|
|
17820
18134
|
function refreshLogPath(projectRoot) {
|
|
17821
|
-
return
|
|
18135
|
+
return resolve19(projectRoot, ".massu", "refresh-log.jsonl");
|
|
17822
18136
|
}
|
|
17823
18137
|
function appendRefreshLog(projectRoot, event) {
|
|
17824
18138
|
const path = refreshLogPath(projectRoot);
|
|
17825
18139
|
try {
|
|
17826
|
-
|
|
18140
|
+
mkdirSync10(dirname12(path), { recursive: true });
|
|
17827
18141
|
appendFileSync(path, JSON.stringify(event) + "\n", "utf-8");
|
|
17828
18142
|
} catch {
|
|
17829
18143
|
}
|
|
17830
18144
|
}
|
|
17831
18145
|
function readRefreshLog(projectRoot, limit = 10, opts = {}) {
|
|
17832
18146
|
const path = refreshLogPath(projectRoot);
|
|
17833
|
-
if (!
|
|
18147
|
+
if (!existsSync22(path)) return [];
|
|
17834
18148
|
const warn = opts.warn ?? ((s) => {
|
|
17835
18149
|
process.stderr.write(s);
|
|
17836
18150
|
});
|
|
17837
|
-
const lines =
|
|
18151
|
+
const lines = readFileSync20(path, "utf-8").split("\n").filter(Boolean);
|
|
17838
18152
|
const tail = lines.slice(-limit);
|
|
17839
18153
|
const out = [];
|
|
17840
18154
|
let corrupt = 0;
|
|
@@ -17905,14 +18219,14 @@ var init_refresh_log = __esm({
|
|
|
17905
18219
|
|
|
17906
18220
|
// src/security/atomic-write.ts
|
|
17907
18221
|
import {
|
|
17908
|
-
chmodSync as
|
|
18222
|
+
chmodSync as chmodSync4,
|
|
17909
18223
|
closeSync as closeSync4,
|
|
17910
|
-
existsSync as
|
|
18224
|
+
existsSync as existsSync23,
|
|
17911
18225
|
fsyncSync as fsyncSync4,
|
|
17912
|
-
mkdirSync as
|
|
18226
|
+
mkdirSync as mkdirSync11,
|
|
17913
18227
|
openSync as openSync4,
|
|
17914
18228
|
renameSync as renameSync5,
|
|
17915
|
-
rmSync as
|
|
18229
|
+
rmSync as rmSync7,
|
|
17916
18230
|
statSync as statSync9,
|
|
17917
18231
|
writeSync as writeSync4
|
|
17918
18232
|
} from "node:fs";
|
|
@@ -17921,12 +18235,12 @@ function atomicWrite(path, content, opts = {}) {
|
|
|
17921
18235
|
const tmpPath = `${path}.tmp`;
|
|
17922
18236
|
const parentDir = dirname13(path);
|
|
17923
18237
|
try {
|
|
17924
|
-
if (!
|
|
18238
|
+
if (!existsSync23(parentDir)) {
|
|
17925
18239
|
const mkdirOpts = { recursive: true };
|
|
17926
18240
|
if (opts.ensureParentDirMode !== void 0) {
|
|
17927
18241
|
mkdirOpts.mode = opts.ensureParentDirMode;
|
|
17928
18242
|
}
|
|
17929
|
-
|
|
18243
|
+
mkdirSync11(parentDir, mkdirOpts);
|
|
17930
18244
|
}
|
|
17931
18245
|
const buf = typeof content === "string" ? Buffer.from(content, "utf-8") : content;
|
|
17932
18246
|
const openMode = opts.mode ?? 420;
|
|
@@ -17938,14 +18252,14 @@ function atomicWrite(path, content, opts = {}) {
|
|
|
17938
18252
|
closeSync4(fd);
|
|
17939
18253
|
}
|
|
17940
18254
|
if (opts.mode !== void 0) {
|
|
17941
|
-
|
|
18255
|
+
chmodSync4(tmpPath, opts.mode);
|
|
17942
18256
|
}
|
|
17943
18257
|
renameSync5(tmpPath, path);
|
|
17944
18258
|
return { written: true };
|
|
17945
18259
|
} catch (err) {
|
|
17946
|
-
if (
|
|
18260
|
+
if (existsSync23(tmpPath)) {
|
|
17947
18261
|
try {
|
|
17948
|
-
|
|
18262
|
+
rmSync7(tmpPath, { force: true });
|
|
17949
18263
|
} catch {
|
|
17950
18264
|
}
|
|
17951
18265
|
}
|
|
@@ -18292,24 +18606,24 @@ var init_fetcher = __esm({
|
|
|
18292
18606
|
});
|
|
18293
18607
|
|
|
18294
18608
|
// src/security/manifest-cache.ts
|
|
18295
|
-
import { existsSync as
|
|
18296
|
-
import { homedir as
|
|
18297
|
-
import { resolve as
|
|
18609
|
+
import { existsSync as existsSync24, readFileSync as readFileSync21, statSync as statSync10 } from "node:fs";
|
|
18610
|
+
import { homedir as homedir6 } from "node:os";
|
|
18611
|
+
import { resolve as resolve20 } from "node:path";
|
|
18298
18612
|
import { z as z4 } from "zod";
|
|
18299
18613
|
function defaultCachePaths() {
|
|
18300
|
-
const dir =
|
|
18614
|
+
const dir = resolve20(homedir6(), ".massu");
|
|
18301
18615
|
return {
|
|
18302
|
-
cachePath:
|
|
18303
|
-
lockPath:
|
|
18616
|
+
cachePath: resolve20(dir, "adapter-manifest.json"),
|
|
18617
|
+
lockPath: resolve20(dir, ".adapter-manifest.lock")
|
|
18304
18618
|
};
|
|
18305
18619
|
}
|
|
18306
18620
|
function loadCachedManifest(paths = defaultCachePaths()) {
|
|
18307
|
-
if (!
|
|
18621
|
+
if (!existsSync24(paths.cachePath)) {
|
|
18308
18622
|
return { kind: "absent" };
|
|
18309
18623
|
}
|
|
18310
18624
|
let raw;
|
|
18311
18625
|
try {
|
|
18312
|
-
const content =
|
|
18626
|
+
const content = readFileSync21(paths.cachePath, "utf-8");
|
|
18313
18627
|
raw = JSON.parse(content);
|
|
18314
18628
|
} catch (err) {
|
|
18315
18629
|
return {
|
|
@@ -18498,15 +18812,15 @@ var init_adapter_origin = __esm({
|
|
|
18498
18812
|
});
|
|
18499
18813
|
|
|
18500
18814
|
// src/security/local-fingerprint.ts
|
|
18501
|
-
import { existsSync as
|
|
18502
|
-
import { homedir as
|
|
18503
|
-
import { resolve as
|
|
18815
|
+
import { existsSync as existsSync25, readFileSync as readFileSync22, lstatSync as lstatSync5 } from "node:fs";
|
|
18816
|
+
import { homedir as homedir7 } from "node:os";
|
|
18817
|
+
import { resolve as resolve21, isAbsolute } from "node:path";
|
|
18504
18818
|
import { createHash as createHash7 } from "node:crypto";
|
|
18505
18819
|
import { z as z5 } from "zod";
|
|
18506
18820
|
function computeLocalFingerprint(localPaths, projectRoot) {
|
|
18507
18821
|
const tuples = [];
|
|
18508
18822
|
for (const p19 of localPaths) {
|
|
18509
|
-
const abs = isAbsolute(p19) ? p19 :
|
|
18823
|
+
const abs = isAbsolute(p19) ? p19 : resolve21(projectRoot, p19);
|
|
18510
18824
|
let contentTag;
|
|
18511
18825
|
try {
|
|
18512
18826
|
const lst = lstatSync5(abs);
|
|
@@ -18515,7 +18829,7 @@ function computeLocalFingerprint(localPaths, projectRoot) {
|
|
|
18515
18829
|
} else if (!lst.isFile()) {
|
|
18516
18830
|
contentTag = "<not-a-file>";
|
|
18517
18831
|
} else {
|
|
18518
|
-
contentTag = createHash7("sha256").update(
|
|
18832
|
+
contentTag = createHash7("sha256").update(readFileSync22(abs)).digest("hex");
|
|
18519
18833
|
}
|
|
18520
18834
|
} catch {
|
|
18521
18835
|
contentTag = "<missing>";
|
|
@@ -18527,10 +18841,10 @@ function computeLocalFingerprint(localPaths, projectRoot) {
|
|
|
18527
18841
|
return createHash7("sha256").update(canonical).digest("hex");
|
|
18528
18842
|
}
|
|
18529
18843
|
function readFingerprintSentinel(path = FINGERPRINT_PATH) {
|
|
18530
|
-
if (!
|
|
18844
|
+
if (!existsSync25(path)) return null;
|
|
18531
18845
|
let raw;
|
|
18532
18846
|
try {
|
|
18533
|
-
raw = JSON.parse(
|
|
18847
|
+
raw = JSON.parse(readFileSync22(path, "utf-8"));
|
|
18534
18848
|
} catch {
|
|
18535
18849
|
return null;
|
|
18536
18850
|
}
|
|
@@ -18578,7 +18892,7 @@ var init_local_fingerprint = __esm({
|
|
|
18578
18892
|
"use strict";
|
|
18579
18893
|
init_atomic_write();
|
|
18580
18894
|
init_manifest_schema();
|
|
18581
|
-
FINGERPRINT_PATH =
|
|
18895
|
+
FINGERPRINT_PATH = resolve21(homedir7(), ".massu", "adapters-local-fingerprint.json");
|
|
18582
18896
|
FingerprintSentinelSchema = z5.object({
|
|
18583
18897
|
fingerprint: z5.string().regex(/^[0-9a-f]{64}$/),
|
|
18584
18898
|
source: z5.enum(["cli", "cli-resync"]),
|
|
@@ -18594,15 +18908,15 @@ var init_local_fingerprint = __esm({
|
|
|
18594
18908
|
});
|
|
18595
18909
|
|
|
18596
18910
|
// src/security/install-tracking.ts
|
|
18597
|
-
import { readFileSync as
|
|
18911
|
+
import { readFileSync as readFileSync23, readdirSync as readdirSync13, lstatSync as lstatSync6, existsSync as existsSync26 } from "node:fs";
|
|
18598
18912
|
import { join as join12, relative as relative5, sep } from "node:path";
|
|
18599
|
-
import { homedir as
|
|
18600
|
-
import { resolve as
|
|
18913
|
+
import { homedir as homedir8 } from "node:os";
|
|
18914
|
+
import { resolve as resolve22 } from "node:path";
|
|
18601
18915
|
import { createHash as createHash8 } from "node:crypto";
|
|
18602
18916
|
import { z as z6 } from "zod";
|
|
18603
18917
|
function containsHiddenDirs(packageDir) {
|
|
18604
18918
|
for (const hidden of EXCLUDED_DIR_NAMES) {
|
|
18605
|
-
if (
|
|
18919
|
+
if (existsSync26(`${packageDir}/${hidden}`)) {
|
|
18606
18920
|
return hidden;
|
|
18607
18921
|
}
|
|
18608
18922
|
}
|
|
@@ -18648,7 +18962,7 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
18648
18962
|
files.sort((a2, b2) => a2.relativePath < b2.relativePath ? -1 : a2.relativePath > b2.relativePath ? 1 : 0);
|
|
18649
18963
|
const top = createHash8("sha256");
|
|
18650
18964
|
for (const f2 of files) {
|
|
18651
|
-
const fileHash = createHash8("sha256").update(
|
|
18965
|
+
const fileHash = createHash8("sha256").update(readFileSync23(f2.absPath)).digest("hex");
|
|
18652
18966
|
top.update(f2.relativePath, "utf-8");
|
|
18653
18967
|
top.update("\0", "utf-8");
|
|
18654
18968
|
top.update(fileHash, "utf-8");
|
|
@@ -18657,10 +18971,10 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
18657
18971
|
return top.digest("hex");
|
|
18658
18972
|
}
|
|
18659
18973
|
function readInstalledManifest(path = INSTALLED_MANIFEST_PATH) {
|
|
18660
|
-
if (!
|
|
18974
|
+
if (!existsSync26(path)) return {};
|
|
18661
18975
|
let raw;
|
|
18662
18976
|
try {
|
|
18663
|
-
raw = JSON.parse(
|
|
18977
|
+
raw = JSON.parse(readFileSync23(path, "utf-8"));
|
|
18664
18978
|
} catch {
|
|
18665
18979
|
return {};
|
|
18666
18980
|
}
|
|
@@ -18724,7 +19038,7 @@ var init_install_tracking = __esm({
|
|
|
18724
19038
|
"src/security/install-tracking.ts"() {
|
|
18725
19039
|
"use strict";
|
|
18726
19040
|
init_atomic_write();
|
|
18727
|
-
INSTALLED_MANIFEST_PATH =
|
|
19041
|
+
INSTALLED_MANIFEST_PATH = resolve22(homedir8(), ".massu", "adapter-manifest-installed.json");
|
|
18728
19042
|
DEFAULT_MAX_FILE_BYTES = 64 * 1024 * 1024;
|
|
18729
19043
|
EXCLUDED_DIR_NAMES = /* @__PURE__ */ new Set([".git", "node_modules", ".cache", ".tmp"]);
|
|
18730
19044
|
InstallEntrySchema = z6.object({
|
|
@@ -18747,12 +19061,12 @@ var init_install_tracking = __esm({
|
|
|
18747
19061
|
});
|
|
18748
19062
|
|
|
18749
19063
|
// src/detect/adapters/discover.ts
|
|
18750
|
-
import { existsSync as
|
|
18751
|
-
import { resolve as
|
|
19064
|
+
import { existsSync as existsSync27, readdirSync as readdirSync14, readFileSync as readFileSync24, lstatSync as lstatSync7 } from "node:fs";
|
|
19065
|
+
import { resolve as resolve23, isAbsolute as isAbsolute2 } from "node:path";
|
|
18752
19066
|
import { z as z7 } from "zod";
|
|
18753
19067
|
function walkNodeModules(projectRoot, warnings) {
|
|
18754
|
-
const nodeModulesDir =
|
|
18755
|
-
if (!
|
|
19068
|
+
const nodeModulesDir = resolve23(projectRoot, "node_modules");
|
|
19069
|
+
if (!existsSync27(nodeModulesDir)) {
|
|
18756
19070
|
return [];
|
|
18757
19071
|
}
|
|
18758
19072
|
const candidates = [];
|
|
@@ -18765,7 +19079,7 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
18765
19079
|
}
|
|
18766
19080
|
for (const entry of topLevelEntries) {
|
|
18767
19081
|
if (entry.startsWith(".")) continue;
|
|
18768
|
-
const entryPath =
|
|
19082
|
+
const entryPath = resolve23(nodeModulesDir, entry);
|
|
18769
19083
|
let entryStat;
|
|
18770
19084
|
try {
|
|
18771
19085
|
entryStat = lstatSync7(entryPath);
|
|
@@ -18787,7 +19101,7 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
18787
19101
|
continue;
|
|
18788
19102
|
}
|
|
18789
19103
|
for (const sub of scopedEntries) {
|
|
18790
|
-
const subPath =
|
|
19104
|
+
const subPath = resolve23(entryPath, sub);
|
|
18791
19105
|
let subStat;
|
|
18792
19106
|
try {
|
|
18793
19107
|
subStat = lstatSync7(subPath);
|
|
@@ -18806,11 +19120,11 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
18806
19120
|
return candidates;
|
|
18807
19121
|
}
|
|
18808
19122
|
function tryReadAdapterPackage(packageDir, warnings) {
|
|
18809
|
-
const pkgJsonPath =
|
|
18810
|
-
if (!
|
|
19123
|
+
const pkgJsonPath = resolve23(packageDir, "package.json");
|
|
19124
|
+
if (!existsSync27(pkgJsonPath)) return null;
|
|
18811
19125
|
let raw;
|
|
18812
19126
|
try {
|
|
18813
|
-
raw = JSON.parse(
|
|
19127
|
+
raw = JSON.parse(readFileSync24(pkgJsonPath, "utf-8"));
|
|
18814
19128
|
} catch (err) {
|
|
18815
19129
|
warnings.push(
|
|
18816
19130
|
`skipping ${packageDir}: package.json parse failed (${err instanceof Error ? err.message : String(err)})`
|
|
@@ -18944,8 +19258,8 @@ function discoverAdapters(opts) {
|
|
|
18944
19258
|
const localSet = new Set(opts.configLocalPaths);
|
|
18945
19259
|
for (const localPath of opts.configLocalPaths) {
|
|
18946
19260
|
if (seenIds.has(localPath)) continue;
|
|
18947
|
-
const absPath = isAbsolute2(localPath) ? localPath :
|
|
18948
|
-
if (!
|
|
19261
|
+
const absPath = isAbsolute2(localPath) ? localPath : resolve23(opts.projectRoot, localPath);
|
|
19262
|
+
if (!existsSync27(absPath)) {
|
|
18949
19263
|
warnings.push(
|
|
18950
19264
|
`local adapter file not found: ${localPath} (resolved to ${absPath}). Remove via: massu adapters remove-local ${localPath}`
|
|
18951
19265
|
);
|
|
@@ -19027,8 +19341,8 @@ __export(adapters_exports, {
|
|
|
19027
19341
|
runAdaptersResyncLocalFingerprint: () => runAdaptersResyncLocalFingerprint,
|
|
19028
19342
|
runAdaptersSearch: () => runAdaptersSearch
|
|
19029
19343
|
});
|
|
19030
|
-
import { existsSync as
|
|
19031
|
-
import { resolve as
|
|
19344
|
+
import { existsSync as existsSync28, readFileSync as readFileSync25 } from "node:fs";
|
|
19345
|
+
import { resolve as resolve24 } from "node:path";
|
|
19032
19346
|
import { parseDocument } from "yaml";
|
|
19033
19347
|
async function handleAdaptersSubcommand(args2) {
|
|
19034
19348
|
const sub = args2[0];
|
|
@@ -19295,8 +19609,8 @@ function mutateLocalArray(mutator, command) {
|
|
|
19295
19609
|
);
|
|
19296
19610
|
return { exitCode: 2 };
|
|
19297
19611
|
}
|
|
19298
|
-
const yamlPath =
|
|
19299
|
-
if (!
|
|
19612
|
+
const yamlPath = resolve24(projectRoot, "massu.config.yaml");
|
|
19613
|
+
if (!existsSync28(yamlPath)) {
|
|
19300
19614
|
process.stderr.write(
|
|
19301
19615
|
`${command}: massu.config.yaml not found at ${yamlPath}. Run \`massu init\` first.
|
|
19302
19616
|
`
|
|
@@ -19305,7 +19619,7 @@ function mutateLocalArray(mutator, command) {
|
|
|
19305
19619
|
}
|
|
19306
19620
|
let yamlText;
|
|
19307
19621
|
try {
|
|
19308
|
-
yamlText =
|
|
19622
|
+
yamlText = readFileSync25(yamlPath, "utf-8");
|
|
19309
19623
|
} catch (err) {
|
|
19310
19624
|
process.stderr.write(`${command}: failed to read ${yamlPath}: ${err instanceof Error ? err.message : String(err)}
|
|
19311
19625
|
`);
|
|
@@ -19326,7 +19640,7 @@ function mutateLocalArray(mutator, command) {
|
|
|
19326
19640
|
if (next === null) {
|
|
19327
19641
|
return { exitCode: 0 };
|
|
19328
19642
|
}
|
|
19329
|
-
const lockPath =
|
|
19643
|
+
const lockPath = resolve24(projectRoot, ".massu", "adapters-local-mutate.lock");
|
|
19330
19644
|
return withFileLockSync(lockPath, () => {
|
|
19331
19645
|
doc.setIn(["adapters", "local"], next);
|
|
19332
19646
|
const newYaml = doc.toString();
|
|
@@ -19395,23 +19709,23 @@ async function runAdaptersInstall(args2) {
|
|
|
19395
19709
|
`);
|
|
19396
19710
|
return { exitCode: 1 };
|
|
19397
19711
|
}
|
|
19398
|
-
const packageDir =
|
|
19399
|
-
if (!
|
|
19712
|
+
const packageDir = resolve24(projectRoot, "node_modules", ...packageName.split("/"));
|
|
19713
|
+
if (!existsSync28(packageDir)) {
|
|
19400
19714
|
process.stderr.write(
|
|
19401
19715
|
`install: ${packageName} is not installed in node_modules. Run \`npm install ${packageName}\` first.
|
|
19402
19716
|
`
|
|
19403
19717
|
);
|
|
19404
19718
|
return { exitCode: 1 };
|
|
19405
19719
|
}
|
|
19406
|
-
const pkgJsonPath =
|
|
19407
|
-
if (!
|
|
19720
|
+
const pkgJsonPath = resolve24(packageDir, "package.json");
|
|
19721
|
+
if (!existsSync28(pkgJsonPath)) {
|
|
19408
19722
|
process.stderr.write(`install: ${packageName} has no package.json at ${pkgJsonPath}
|
|
19409
19723
|
`);
|
|
19410
19724
|
return { exitCode: 1 };
|
|
19411
19725
|
}
|
|
19412
19726
|
let pkgJson;
|
|
19413
19727
|
try {
|
|
19414
|
-
pkgJson = JSON.parse(
|
|
19728
|
+
pkgJson = JSON.parse(readFileSync25(pkgJsonPath, "utf-8"));
|
|
19415
19729
|
} catch (err) {
|
|
19416
19730
|
process.stderr.write(`install: ${packageName} has malformed package.json: ${err instanceof Error ? err.message : String(err)}
|
|
19417
19731
|
`);
|
|
@@ -19530,8 +19844,8 @@ async function runAdaptersResign(_args) {
|
|
|
19530
19844
|
removeInstalledManifestEntry(name);
|
|
19531
19845
|
continue;
|
|
19532
19846
|
}
|
|
19533
|
-
const packageDir =
|
|
19534
|
-
if (!
|
|
19847
|
+
const packageDir = resolve24(projectRoot, "node_modules", ...name.split("/"));
|
|
19848
|
+
if (!existsSync28(packageDir)) {
|
|
19535
19849
|
removed++;
|
|
19536
19850
|
warnings.push(`${name}@${entry.version}: not present in node_modules \u2014 REMOVED from sidecar`);
|
|
19537
19851
|
removeInstalledManifestEntry(name);
|
|
@@ -19630,10 +19944,10 @@ var init_sql_table_names = __esm({
|
|
|
19630
19944
|
// src/db.ts
|
|
19631
19945
|
import Database2 from "better-sqlite3";
|
|
19632
19946
|
import { dirname as dirname14, join as join13 } from "path";
|
|
19633
|
-
import { existsSync as
|
|
19947
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync12, readdirSync as readdirSync15, statSync as statSync11 } from "fs";
|
|
19634
19948
|
function getCodeGraphDb() {
|
|
19635
19949
|
const dbPath = getResolvedPaths().codegraphDbPath;
|
|
19636
|
-
if (!
|
|
19950
|
+
if (!existsSync29(dbPath)) {
|
|
19637
19951
|
throw new CodegraphDbNotInitializedError(dbPath);
|
|
19638
19952
|
}
|
|
19639
19953
|
const db = new Database2(dbPath, { readonly: true });
|
|
@@ -19643,8 +19957,8 @@ function getCodeGraphDb() {
|
|
|
19643
19957
|
function getDataDb() {
|
|
19644
19958
|
const dbPath = getResolvedPaths().dataDbPath;
|
|
19645
19959
|
const dir = dirname14(dbPath);
|
|
19646
|
-
if (!
|
|
19647
|
-
|
|
19960
|
+
if (!existsSync29(dir)) {
|
|
19961
|
+
mkdirSync12(dir, { recursive: true });
|
|
19648
19962
|
}
|
|
19649
19963
|
const db = new Database2(dbPath);
|
|
19650
19964
|
db.pragma("journal_mode = WAL");
|
|
@@ -19953,12 +20267,12 @@ var init_db = __esm({
|
|
|
19953
20267
|
// src/knowledge-db.ts
|
|
19954
20268
|
import Database3 from "better-sqlite3";
|
|
19955
20269
|
import { dirname as dirname15 } from "path";
|
|
19956
|
-
import { existsSync as
|
|
20270
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync13 } from "fs";
|
|
19957
20271
|
function getKnowledgeDb() {
|
|
19958
20272
|
const dbPath = getResolvedPaths().knowledgeDbPath;
|
|
19959
20273
|
const dir = dirname15(dbPath);
|
|
19960
|
-
if (!
|
|
19961
|
-
|
|
20274
|
+
if (!existsSync30(dir)) {
|
|
20275
|
+
mkdirSync13(dir, { recursive: true });
|
|
19962
20276
|
}
|
|
19963
20277
|
const db = new Database3(dbPath);
|
|
19964
20278
|
db.pragma("journal_mode = WAL");
|
|
@@ -20129,10 +20443,10 @@ var init_knowledge_db = __esm({
|
|
|
20129
20443
|
});
|
|
20130
20444
|
|
|
20131
20445
|
// src/security-utils.ts
|
|
20132
|
-
import { resolve as
|
|
20446
|
+
import { resolve as resolve25, normalize } from "path";
|
|
20133
20447
|
function ensureWithinRoot(filePath, projectRoot) {
|
|
20134
|
-
const resolvedRoot =
|
|
20135
|
-
const resolvedPath =
|
|
20448
|
+
const resolvedRoot = resolve25(projectRoot);
|
|
20449
|
+
const resolvedPath = resolve25(resolvedRoot, filePath);
|
|
20136
20450
|
const normalizedPath = normalize(resolvedPath);
|
|
20137
20451
|
const normalizedRoot = normalize(resolvedRoot);
|
|
20138
20452
|
if (!normalizedPath.startsWith(normalizedRoot + "/") && normalizedPath !== normalizedRoot) {
|
|
@@ -20205,8 +20519,8 @@ var init_rules = __esm({
|
|
|
20205
20519
|
});
|
|
20206
20520
|
|
|
20207
20521
|
// src/import-resolver.ts
|
|
20208
|
-
import { readFileSync as
|
|
20209
|
-
import { resolve as
|
|
20522
|
+
import { readFileSync as readFileSync26, existsSync as existsSync31, statSync as statSync12 } from "fs";
|
|
20523
|
+
import { resolve as resolve26, dirname as dirname16, join as join14 } from "path";
|
|
20210
20524
|
function parseImports(source) {
|
|
20211
20525
|
const imports = [];
|
|
20212
20526
|
const lines = source.split("\n");
|
|
@@ -20262,23 +20576,23 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
20262
20576
|
let basePath;
|
|
20263
20577
|
if (specifier.startsWith("@/")) {
|
|
20264
20578
|
const paths = getResolvedPaths();
|
|
20265
|
-
basePath =
|
|
20579
|
+
basePath = resolve26(paths.pathAlias["@"] ?? paths.srcDir, specifier.slice(2));
|
|
20266
20580
|
} else {
|
|
20267
|
-
basePath =
|
|
20581
|
+
basePath = resolve26(dirname16(fromFile), specifier);
|
|
20268
20582
|
}
|
|
20269
|
-
if (
|
|
20583
|
+
if (existsSync31(basePath) && !isDirectory(basePath)) {
|
|
20270
20584
|
return toRelative(basePath);
|
|
20271
20585
|
}
|
|
20272
20586
|
const resolvedPaths = getResolvedPaths();
|
|
20273
20587
|
for (const ext of resolvedPaths.extensions) {
|
|
20274
20588
|
const withExt = basePath + ext;
|
|
20275
|
-
if (
|
|
20589
|
+
if (existsSync31(withExt)) {
|
|
20276
20590
|
return toRelative(withExt);
|
|
20277
20591
|
}
|
|
20278
20592
|
}
|
|
20279
20593
|
for (const indexFile of resolvedPaths.indexFiles) {
|
|
20280
20594
|
const indexPath = join14(basePath, indexFile);
|
|
20281
|
-
if (
|
|
20595
|
+
if (existsSync31(indexPath)) {
|
|
20282
20596
|
return toRelative(indexPath);
|
|
20283
20597
|
}
|
|
20284
20598
|
}
|
|
@@ -20314,11 +20628,11 @@ function buildImportIndex(dataDb, codegraphDb) {
|
|
|
20314
20628
|
const batchSize = 500;
|
|
20315
20629
|
let batch = [];
|
|
20316
20630
|
for (const file of files) {
|
|
20317
|
-
const absPath = ensureWithinRoot(
|
|
20318
|
-
if (!
|
|
20631
|
+
const absPath = ensureWithinRoot(resolve26(projectRoot, file.path), projectRoot);
|
|
20632
|
+
if (!existsSync31(absPath)) continue;
|
|
20319
20633
|
let source;
|
|
20320
20634
|
try {
|
|
20321
|
-
source =
|
|
20635
|
+
source = readFileSync26(absPath, "utf-8");
|
|
20322
20636
|
} catch {
|
|
20323
20637
|
continue;
|
|
20324
20638
|
}
|
|
@@ -20355,15 +20669,15 @@ var init_import_resolver = __esm({
|
|
|
20355
20669
|
});
|
|
20356
20670
|
|
|
20357
20671
|
// src/trpc-index.ts
|
|
20358
|
-
import { readFileSync as
|
|
20359
|
-
import { resolve as
|
|
20672
|
+
import { readFileSync as readFileSync27, existsSync as existsSync32, readdirSync as readdirSync16 } from "fs";
|
|
20673
|
+
import { resolve as resolve27, join as join15 } from "path";
|
|
20360
20674
|
function parseRootRouter() {
|
|
20361
20675
|
const paths = getResolvedPaths();
|
|
20362
20676
|
const rootPath = paths.rootRouterPath;
|
|
20363
|
-
if (!
|
|
20677
|
+
if (!existsSync32(rootPath)) {
|
|
20364
20678
|
throw new Error(`Root router not found at ${rootPath}`);
|
|
20365
20679
|
}
|
|
20366
|
-
const source =
|
|
20680
|
+
const source = readFileSync27(rootPath, "utf-8");
|
|
20367
20681
|
const mappings = [];
|
|
20368
20682
|
const importMap = /* @__PURE__ */ new Map();
|
|
20369
20683
|
const importRegex = /import\s+\{[^}]*?(\w+Router)[^}]*\}\s+from\s+['"]\.\/routers\/([^'"]+)['"]/g;
|
|
@@ -20371,16 +20685,16 @@ function parseRootRouter() {
|
|
|
20371
20685
|
while ((match = importRegex.exec(source)) !== null) {
|
|
20372
20686
|
const variable = match[1];
|
|
20373
20687
|
let filePath = match[2];
|
|
20374
|
-
const fullPath =
|
|
20688
|
+
const fullPath = resolve27(paths.routersDir, filePath);
|
|
20375
20689
|
for (const ext of [".ts", ".tsx", ""]) {
|
|
20376
20690
|
const candidate = fullPath + ext;
|
|
20377
20691
|
const routersRelPath = getConfig().paths.routers ?? "src/server/api/routers";
|
|
20378
|
-
if (
|
|
20692
|
+
if (existsSync32(candidate)) {
|
|
20379
20693
|
filePath = routersRelPath + "/" + filePath + ext;
|
|
20380
20694
|
break;
|
|
20381
20695
|
}
|
|
20382
20696
|
const indexCandidate = join15(fullPath, "index.ts");
|
|
20383
|
-
if (
|
|
20697
|
+
if (existsSync32(indexCandidate)) {
|
|
20384
20698
|
filePath = routersRelPath + "/" + filePath + "/index.ts";
|
|
20385
20699
|
break;
|
|
20386
20700
|
}
|
|
@@ -20399,9 +20713,9 @@ function parseRootRouter() {
|
|
|
20399
20713
|
return mappings;
|
|
20400
20714
|
}
|
|
20401
20715
|
function extractProcedures(routerFilePath) {
|
|
20402
|
-
const absPath =
|
|
20403
|
-
if (!
|
|
20404
|
-
const source =
|
|
20716
|
+
const absPath = resolve27(getProjectRoot(), routerFilePath);
|
|
20717
|
+
if (!existsSync32(absPath)) return [];
|
|
20718
|
+
const source = readFileSync27(absPath, "utf-8");
|
|
20405
20719
|
const procedures = [];
|
|
20406
20720
|
const seen = /* @__PURE__ */ new Set();
|
|
20407
20721
|
const procRegex = /(\w+)\s*:\s*(protected|public)Procedure/g;
|
|
@@ -20424,13 +20738,13 @@ function findUICallSites(routerKey, procedureName) {
|
|
|
20424
20738
|
const root = getProjectRoot();
|
|
20425
20739
|
const src = config.paths.source;
|
|
20426
20740
|
const searchDirs = [
|
|
20427
|
-
|
|
20428
|
-
|
|
20429
|
-
|
|
20741
|
+
resolve27(root, config.paths.pages ?? src + "/app"),
|
|
20742
|
+
resolve27(root, config.paths.components ?? src + "/components"),
|
|
20743
|
+
resolve27(root, config.paths.hooks ?? src + "/hooks")
|
|
20430
20744
|
];
|
|
20431
20745
|
const searchPattern = `api.${routerKey}.${procedureName}`;
|
|
20432
20746
|
for (const dir of searchDirs) {
|
|
20433
|
-
if (!
|
|
20747
|
+
if (!existsSync32(dir)) continue;
|
|
20434
20748
|
searchDirectory(dir, searchPattern, callSites);
|
|
20435
20749
|
}
|
|
20436
20750
|
return callSites;
|
|
@@ -20444,7 +20758,7 @@ function searchDirectory(dir, pattern, results) {
|
|
|
20444
20758
|
searchDirectory(fullPath, pattern, results);
|
|
20445
20759
|
} else if (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) {
|
|
20446
20760
|
try {
|
|
20447
|
-
const source =
|
|
20761
|
+
const source = readFileSync27(fullPath, "utf-8");
|
|
20448
20762
|
const lines = source.split("\n");
|
|
20449
20763
|
for (let i = 0; i < lines.length; i++) {
|
|
20450
20764
|
if (lines[i].includes(pattern)) {
|
|
@@ -20508,8 +20822,8 @@ var init_trpc_index = __esm({
|
|
|
20508
20822
|
});
|
|
20509
20823
|
|
|
20510
20824
|
// src/page-deps.ts
|
|
20511
|
-
import { readFileSync as
|
|
20512
|
-
import { resolve as
|
|
20825
|
+
import { readFileSync as readFileSync28, existsSync as existsSync33 } from "fs";
|
|
20826
|
+
import { resolve as resolve28 } from "path";
|
|
20513
20827
|
function deriveRoute(pageFile) {
|
|
20514
20828
|
let route = pageFile.replace(/^src\/app/, "").replace(/\/page\.tsx?$/, "").replace(/\/page\.jsx?$/, "");
|
|
20515
20829
|
return route || "/";
|
|
@@ -20547,10 +20861,10 @@ function findRouterCalls(files) {
|
|
|
20547
20861
|
const routers = /* @__PURE__ */ new Set();
|
|
20548
20862
|
const projectRoot = getProjectRoot();
|
|
20549
20863
|
for (const file of files) {
|
|
20550
|
-
const absPath = ensureWithinRoot(
|
|
20551
|
-
if (!
|
|
20864
|
+
const absPath = ensureWithinRoot(resolve28(projectRoot, file), projectRoot);
|
|
20865
|
+
if (!existsSync33(absPath)) continue;
|
|
20552
20866
|
try {
|
|
20553
|
-
const source =
|
|
20867
|
+
const source = readFileSync28(absPath, "utf-8");
|
|
20554
20868
|
const apiCallRegex = /api\.(\w+)\.\w+/g;
|
|
20555
20869
|
let match;
|
|
20556
20870
|
while ((match = apiCallRegex.exec(source)) !== null) {
|
|
@@ -20568,10 +20882,10 @@ function findTablesFromRouters(routerNames, dataDb) {
|
|
|
20568
20882
|
`SELECT DISTINCT router_file FROM ${t("trpc_procedures")} WHERE router_name = ? LIMIT 10000`
|
|
20569
20883
|
).all(routerName);
|
|
20570
20884
|
for (const proc of procs) {
|
|
20571
|
-
const absPath = ensureWithinRoot(
|
|
20572
|
-
if (!
|
|
20885
|
+
const absPath = ensureWithinRoot(resolve28(getProjectRoot(), proc.router_file), getProjectRoot());
|
|
20886
|
+
if (!existsSync33(absPath)) continue;
|
|
20573
20887
|
try {
|
|
20574
|
-
const source =
|
|
20888
|
+
const source = readFileSync28(absPath, "utf-8");
|
|
20575
20889
|
const dbPattern = getConfig().dbAccessPattern ?? "ctx.db.{table}";
|
|
20576
20890
|
const regexStr = dbPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{table\\}", "(\\w+)");
|
|
20577
20891
|
const tableRegex = new RegExp(regexStr + "\\.", "g");
|
|
@@ -20843,14 +21157,14 @@ var init_domains = __esm({
|
|
|
20843
21157
|
});
|
|
20844
21158
|
|
|
20845
21159
|
// src/schema-mapper.ts
|
|
20846
|
-
import { readFileSync as
|
|
21160
|
+
import { readFileSync as readFileSync29, existsSync as existsSync34, readdirSync as readdirSync17 } from "fs";
|
|
20847
21161
|
import { join as join16 } from "path";
|
|
20848
21162
|
function parsePrismaSchema() {
|
|
20849
21163
|
const schemaPath = getResolvedPaths().prismaSchemaPath;
|
|
20850
|
-
if (!
|
|
21164
|
+
if (!existsSync34(schemaPath)) {
|
|
20851
21165
|
throw new Error(`Prisma schema not found at ${schemaPath}`);
|
|
20852
21166
|
}
|
|
20853
|
-
const source =
|
|
21167
|
+
const source = readFileSync29(schemaPath, "utf-8");
|
|
20854
21168
|
const models = [];
|
|
20855
21169
|
const sourceLines = source.split("\n");
|
|
20856
21170
|
let i = 0;
|
|
@@ -20908,7 +21222,7 @@ function toSnakeCase(str) {
|
|
|
20908
21222
|
function findColumnUsageInRouters(tableName) {
|
|
20909
21223
|
const usage = /* @__PURE__ */ new Map();
|
|
20910
21224
|
const routersDir = getResolvedPaths().routersDir;
|
|
20911
|
-
if (!
|
|
21225
|
+
if (!existsSync34(routersDir)) return usage;
|
|
20912
21226
|
scanDirectory(routersDir, tableName, usage);
|
|
20913
21227
|
return usage;
|
|
20914
21228
|
}
|
|
@@ -20925,7 +21239,7 @@ function scanDirectory(dir, tableName, usage) {
|
|
|
20925
21239
|
}
|
|
20926
21240
|
function scanFile(absPath, tableName, usage) {
|
|
20927
21241
|
try {
|
|
20928
|
-
const source =
|
|
21242
|
+
const source = readFileSync29(absPath, "utf-8");
|
|
20929
21243
|
if (!source.includes(tableName)) return;
|
|
20930
21244
|
const relPath = absPath.slice(getProjectRoot().length + 1);
|
|
20931
21245
|
const lines = source.split("\n");
|
|
@@ -20970,7 +21284,7 @@ function detectMismatches(models) {
|
|
|
20970
21284
|
}
|
|
20971
21285
|
function findFilesUsingColumn(dir, column, tableName) {
|
|
20972
21286
|
const result = [];
|
|
20973
|
-
if (!
|
|
21287
|
+
if (!existsSync34(dir)) return result;
|
|
20974
21288
|
const entries = readdirSync17(dir, { withFileTypes: true });
|
|
20975
21289
|
for (const entry of entries) {
|
|
20976
21290
|
const fullPath = join16(dir, entry.name);
|
|
@@ -20978,7 +21292,7 @@ function findFilesUsingColumn(dir, column, tableName) {
|
|
|
20978
21292
|
result.push(...findFilesUsingColumn(fullPath, column, tableName));
|
|
20979
21293
|
} else if (entry.name.endsWith(".ts")) {
|
|
20980
21294
|
try {
|
|
20981
|
-
const source =
|
|
21295
|
+
const source = readFileSync29(fullPath, "utf-8");
|
|
20982
21296
|
if (source.includes(tableName) && source.includes(column)) {
|
|
20983
21297
|
result.push(fullPath.slice(getProjectRoot().length + 1));
|
|
20984
21298
|
}
|
|
@@ -21123,12 +21437,12 @@ var init_import_parser = __esm({
|
|
|
21123
21437
|
});
|
|
21124
21438
|
|
|
21125
21439
|
// src/python/import-resolver.ts
|
|
21126
|
-
import { readFileSync as
|
|
21127
|
-
import { resolve as
|
|
21440
|
+
import { readFileSync as readFileSync30, existsSync as existsSync35, readdirSync as readdirSync18 } from "fs";
|
|
21441
|
+
import { resolve as resolve30, join as join17, relative as relative6, dirname as dirname17 } from "path";
|
|
21128
21442
|
function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
21129
21443
|
const projectRoot = getProjectRoot();
|
|
21130
21444
|
if (level > 0) {
|
|
21131
|
-
let baseDir = dirname17(
|
|
21445
|
+
let baseDir = dirname17(resolve30(projectRoot, fromFile));
|
|
21132
21446
|
for (let i = 1; i < level; i++) {
|
|
21133
21447
|
baseDir = dirname17(baseDir);
|
|
21134
21448
|
}
|
|
@@ -21140,17 +21454,17 @@ function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
|
21140
21454
|
return tryResolvePythonPath(baseDir, projectRoot);
|
|
21141
21455
|
}
|
|
21142
21456
|
const parts = module.split(".");
|
|
21143
|
-
const candidate = join17(
|
|
21457
|
+
const candidate = join17(resolve30(projectRoot, pythonRoot), ...parts);
|
|
21144
21458
|
return tryResolvePythonPath(candidate, projectRoot);
|
|
21145
21459
|
}
|
|
21146
21460
|
function tryResolvePythonPath(basePath, projectRoot) {
|
|
21147
|
-
if (
|
|
21461
|
+
if (existsSync35(basePath + ".py")) {
|
|
21148
21462
|
return relative6(projectRoot, basePath + ".py");
|
|
21149
21463
|
}
|
|
21150
|
-
if (
|
|
21464
|
+
if (existsSync35(join17(basePath, "__init__.py"))) {
|
|
21151
21465
|
return relative6(projectRoot, join17(basePath, "__init__.py"));
|
|
21152
21466
|
}
|
|
21153
|
-
if (basePath.endsWith(".py") &&
|
|
21467
|
+
if (basePath.endsWith(".py") && existsSync35(basePath)) {
|
|
21154
21468
|
return relative6(projectRoot, basePath);
|
|
21155
21469
|
}
|
|
21156
21470
|
return null;
|
|
@@ -21173,7 +21487,7 @@ function walkPythonFiles(dir, excludeDirs) {
|
|
|
21173
21487
|
}
|
|
21174
21488
|
function buildPythonImportIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
21175
21489
|
const projectRoot = getProjectRoot();
|
|
21176
|
-
const absRoot =
|
|
21490
|
+
const absRoot = resolve30(projectRoot, pythonRoot);
|
|
21177
21491
|
dataDb.exec(`DELETE FROM ${t("py_imports")}`);
|
|
21178
21492
|
const insertStmt = dataDb.prepare(
|
|
21179
21493
|
`INSERT INTO ${t("py_imports")} (source_file, target_file, import_type, imported_names, line) VALUES (?, ?, ?, ?, ?)`
|
|
@@ -21190,7 +21504,7 @@ function buildPythonImportIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__"
|
|
|
21190
21504
|
const relFile = relative6(projectRoot, absFile);
|
|
21191
21505
|
let source;
|
|
21192
21506
|
try {
|
|
21193
|
-
source =
|
|
21507
|
+
source = readFileSync30(absFile, "utf-8");
|
|
21194
21508
|
} catch {
|
|
21195
21509
|
continue;
|
|
21196
21510
|
}
|
|
@@ -21457,7 +21771,7 @@ var init_route_parser = __esm({
|
|
|
21457
21771
|
});
|
|
21458
21772
|
|
|
21459
21773
|
// src/python/route-indexer.ts
|
|
21460
|
-
import { readFileSync as
|
|
21774
|
+
import { readFileSync as readFileSync31, readdirSync as readdirSync19 } from "fs";
|
|
21461
21775
|
import { join as join18, relative as relative7 } from "path";
|
|
21462
21776
|
function walkPyFiles(dir, excludeDirs) {
|
|
21463
21777
|
const files = [];
|
|
@@ -21490,7 +21804,7 @@ function buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__",
|
|
|
21490
21804
|
const relFile = relative7(projectRoot, absFile);
|
|
21491
21805
|
let source;
|
|
21492
21806
|
try {
|
|
21493
|
-
source =
|
|
21807
|
+
source = readFileSync31(absFile, "utf-8");
|
|
21494
21808
|
} catch {
|
|
21495
21809
|
continue;
|
|
21496
21810
|
}
|
|
@@ -21702,7 +22016,7 @@ var init_model_parser = __esm({
|
|
|
21702
22016
|
});
|
|
21703
22017
|
|
|
21704
22018
|
// src/python/model-indexer.ts
|
|
21705
|
-
import { readFileSync as
|
|
22019
|
+
import { readFileSync as readFileSync32, readdirSync as readdirSync20 } from "fs";
|
|
21706
22020
|
import { join as join19, relative as relative8 } from "path";
|
|
21707
22021
|
function walkPyFiles2(dir, excludeDirs) {
|
|
21708
22022
|
const files = [];
|
|
@@ -21738,7 +22052,7 @@ function buildPythonModelIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__",
|
|
|
21738
22052
|
const relFile = relative8(projectRoot, absFile);
|
|
21739
22053
|
let source;
|
|
21740
22054
|
try {
|
|
21741
|
-
source =
|
|
22055
|
+
source = readFileSync32(absFile, "utf-8");
|
|
21742
22056
|
} catch {
|
|
21743
22057
|
continue;
|
|
21744
22058
|
}
|
|
@@ -21999,7 +22313,7 @@ var init_migration_parser = __esm({
|
|
|
21999
22313
|
});
|
|
22000
22314
|
|
|
22001
22315
|
// src/python/migration-indexer.ts
|
|
22002
|
-
import { readFileSync as
|
|
22316
|
+
import { readFileSync as readFileSync33, readdirSync as readdirSync21 } from "fs";
|
|
22003
22317
|
import { join as join20, relative as relative9 } from "path";
|
|
22004
22318
|
function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
22005
22319
|
const projectRoot = getProjectRoot();
|
|
@@ -22025,7 +22339,7 @@ function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
|
22025
22339
|
for (const absFile of files) {
|
|
22026
22340
|
let source;
|
|
22027
22341
|
try {
|
|
22028
|
-
source =
|
|
22342
|
+
source = readFileSync33(absFile, "utf-8");
|
|
22029
22343
|
} catch {
|
|
22030
22344
|
continue;
|
|
22031
22345
|
}
|
|
@@ -22060,7 +22374,7 @@ var init_migration_indexer = __esm({
|
|
|
22060
22374
|
});
|
|
22061
22375
|
|
|
22062
22376
|
// src/python/coupling-detector.ts
|
|
22063
|
-
import { readFileSync as
|
|
22377
|
+
import { readFileSync as readFileSync34, readdirSync as readdirSync22 } from "fs";
|
|
22064
22378
|
import { join as join21, relative as relative10 } from "path";
|
|
22065
22379
|
function buildPythonCouplingIndex(dataDb) {
|
|
22066
22380
|
const projectRoot = getProjectRoot();
|
|
@@ -22097,7 +22411,7 @@ function buildPythonCouplingIndex(dataDb) {
|
|
|
22097
22411
|
const relFile = relative10(projectRoot, absFile);
|
|
22098
22412
|
let source;
|
|
22099
22413
|
try {
|
|
22100
|
-
source =
|
|
22414
|
+
source = readFileSync34(absFile, "utf-8");
|
|
22101
22415
|
} catch {
|
|
22102
22416
|
continue;
|
|
22103
22417
|
}
|
|
@@ -22503,8 +22817,8 @@ var init_memory_tools = __esm({
|
|
|
22503
22817
|
});
|
|
22504
22818
|
|
|
22505
22819
|
// src/docs-tools.ts
|
|
22506
|
-
import { readFileSync as
|
|
22507
|
-
import { resolve as
|
|
22820
|
+
import { readFileSync as readFileSync35, existsSync as existsSync36 } from "fs";
|
|
22821
|
+
import { resolve as resolve31, basename as basename6 } from "path";
|
|
22508
22822
|
function p3(baseName) {
|
|
22509
22823
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
22510
22824
|
}
|
|
@@ -22559,10 +22873,10 @@ function handleDocsToolCall(name, args2) {
|
|
|
22559
22873
|
}
|
|
22560
22874
|
function loadDocsMap() {
|
|
22561
22875
|
const mapPath = getResolvedPaths().docsMapPath;
|
|
22562
|
-
if (!
|
|
22876
|
+
if (!existsSync36(mapPath)) {
|
|
22563
22877
|
throw new Error(`docs-map.json not found at ${mapPath}`);
|
|
22564
22878
|
}
|
|
22565
|
-
return JSON.parse(
|
|
22879
|
+
return JSON.parse(readFileSync35(mapPath, "utf-8"));
|
|
22566
22880
|
}
|
|
22567
22881
|
function matchesPattern(filePath, pattern) {
|
|
22568
22882
|
const regexStr = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\{\{GLOBSTAR\}\}/g, ".*");
|
|
@@ -22632,13 +22946,13 @@ function extractFrontmatter(content) {
|
|
|
22632
22946
|
}
|
|
22633
22947
|
function extractProcedureNames(routerPath) {
|
|
22634
22948
|
const root = getProjectRoot();
|
|
22635
|
-
const absPath = ensureWithinRoot(
|
|
22636
|
-
if (!
|
|
22637
|
-
const altPath = ensureWithinRoot(
|
|
22638
|
-
if (!
|
|
22639
|
-
return extractProcedureNamesFromContent(
|
|
22949
|
+
const absPath = ensureWithinRoot(resolve31(getResolvedPaths().srcDir, "..", routerPath), root);
|
|
22950
|
+
if (!existsSync36(absPath)) {
|
|
22951
|
+
const altPath = ensureWithinRoot(resolve31(getResolvedPaths().srcDir, "../server/api/routers", basename6(routerPath)), root);
|
|
22952
|
+
if (!existsSync36(altPath)) return [];
|
|
22953
|
+
return extractProcedureNamesFromContent(readFileSync35(altPath, "utf-8"));
|
|
22640
22954
|
}
|
|
22641
|
-
return extractProcedureNamesFromContent(
|
|
22955
|
+
return extractProcedureNamesFromContent(readFileSync35(absPath, "utf-8"));
|
|
22642
22956
|
}
|
|
22643
22957
|
function extractProcedureNamesFromContent(content) {
|
|
22644
22958
|
const procRegex = /\.(?:query|mutation)\s*\(/g;
|
|
@@ -22678,8 +22992,8 @@ function handleDocsAudit(args2) {
|
|
|
22678
22992
|
for (const [mappingId, triggeringFiles] of affectedMappings) {
|
|
22679
22993
|
const mapping = docsMap.mappings.find((m3) => m3.id === mappingId);
|
|
22680
22994
|
if (!mapping) continue;
|
|
22681
|
-
const helpPagePath = ensureWithinRoot(
|
|
22682
|
-
if (!
|
|
22995
|
+
const helpPagePath = ensureWithinRoot(resolve31(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
22996
|
+
if (!existsSync36(helpPagePath)) {
|
|
22683
22997
|
results.push({
|
|
22684
22998
|
helpPage: mapping.helpPage,
|
|
22685
22999
|
mappingId,
|
|
@@ -22691,7 +23005,7 @@ function handleDocsAudit(args2) {
|
|
|
22691
23005
|
});
|
|
22692
23006
|
continue;
|
|
22693
23007
|
}
|
|
22694
|
-
const content =
|
|
23008
|
+
const content = readFileSync35(helpPagePath, "utf-8");
|
|
22695
23009
|
const sections = extractSections(content);
|
|
22696
23010
|
const frontmatter = extractFrontmatter(content);
|
|
22697
23011
|
const staleReasons = [];
|
|
@@ -22731,9 +23045,9 @@ function handleDocsAudit(args2) {
|
|
|
22731
23045
|
});
|
|
22732
23046
|
for (const [guideName, parentId] of Object.entries(docsMap.userGuideInheritance.examples)) {
|
|
22733
23047
|
if (parentId === mappingId) {
|
|
22734
|
-
const guidePath = ensureWithinRoot(
|
|
22735
|
-
if (
|
|
22736
|
-
const guideContent =
|
|
23048
|
+
const guidePath = ensureWithinRoot(resolve31(getResolvedPaths().helpSitePath, `pages/user-guides/${guideName}/index.mdx`), getProjectRoot());
|
|
23049
|
+
if (existsSync36(guidePath)) {
|
|
23050
|
+
const guideContent = readFileSync35(guidePath, "utf-8");
|
|
22737
23051
|
const guideFrontmatter = extractFrontmatter(guideContent);
|
|
22738
23052
|
if (!guideFrontmatter?.lastVerified || status === "STALE") {
|
|
22739
23053
|
results.push({
|
|
@@ -22766,14 +23080,14 @@ function handleDocsCoverage(args2) {
|
|
|
22766
23080
|
const gaps = [];
|
|
22767
23081
|
const mappings = filterDomain ? docsMap.mappings.filter((m3) => m3.id === filterDomain) : docsMap.mappings;
|
|
22768
23082
|
for (const mapping of mappings) {
|
|
22769
|
-
const helpPagePath = ensureWithinRoot(
|
|
22770
|
-
const exists =
|
|
23083
|
+
const helpPagePath = ensureWithinRoot(resolve31(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
23084
|
+
const exists = existsSync36(helpPagePath);
|
|
22771
23085
|
let hasContent = false;
|
|
22772
23086
|
let lineCount = 0;
|
|
22773
23087
|
let lastVerified = null;
|
|
22774
23088
|
let status = null;
|
|
22775
23089
|
if (exists) {
|
|
22776
|
-
const content =
|
|
23090
|
+
const content = readFileSync35(helpPagePath, "utf-8");
|
|
22777
23091
|
lineCount = content.split("\n").length;
|
|
22778
23092
|
hasContent = lineCount > 10;
|
|
22779
23093
|
const frontmatter = extractFrontmatter(content);
|
|
@@ -23114,8 +23428,8 @@ var init_observability_tools = __esm({
|
|
|
23114
23428
|
});
|
|
23115
23429
|
|
|
23116
23430
|
// src/sentinel-db.ts
|
|
23117
|
-
import { existsSync as
|
|
23118
|
-
import { resolve as
|
|
23431
|
+
import { existsSync as existsSync37 } from "fs";
|
|
23432
|
+
import { resolve as resolve32 } from "path";
|
|
23119
23433
|
function parsePortalScope(raw) {
|
|
23120
23434
|
if (!raw) return [];
|
|
23121
23435
|
try {
|
|
@@ -23351,23 +23665,23 @@ function validateFeatures(db, domainFilter) {
|
|
|
23351
23665
|
const missingProcedures = [];
|
|
23352
23666
|
const missingPages = [];
|
|
23353
23667
|
for (const comp of components) {
|
|
23354
|
-
const absPath =
|
|
23355
|
-
if (!
|
|
23668
|
+
const absPath = resolve32(PROJECT_ROOT, comp.component_file);
|
|
23669
|
+
if (!existsSync37(absPath)) {
|
|
23356
23670
|
missingComponents.push(comp.component_file);
|
|
23357
23671
|
}
|
|
23358
23672
|
}
|
|
23359
23673
|
for (const proc of procedures) {
|
|
23360
|
-
const routerPath =
|
|
23361
|
-
if (!
|
|
23674
|
+
const routerPath = resolve32(PROJECT_ROOT, `src/server/api/routers/${proc.router_name}.ts`);
|
|
23675
|
+
if (!existsSync37(routerPath)) {
|
|
23362
23676
|
missingProcedures.push({ router: proc.router_name, procedure: proc.procedure_name });
|
|
23363
23677
|
}
|
|
23364
23678
|
}
|
|
23365
23679
|
for (const page of pages) {
|
|
23366
23680
|
const routeToPath = page.page_route.replace(/^\/(portal-[^/]+\/)?/, "src/app/").replace(/\/$/, "") + "/page.tsx";
|
|
23367
|
-
const absPath =
|
|
23368
|
-
if (page.page_route.startsWith("/") && !
|
|
23369
|
-
const altPath =
|
|
23370
|
-
if (!
|
|
23681
|
+
const absPath = resolve32(PROJECT_ROOT, routeToPath);
|
|
23682
|
+
if (page.page_route.startsWith("/") && !existsSync37(absPath)) {
|
|
23683
|
+
const altPath = resolve32(PROJECT_ROOT, `src/app${page.page_route}/page.tsx`);
|
|
23684
|
+
if (!existsSync37(altPath)) {
|
|
23371
23685
|
missingPages.push(page.page_route);
|
|
23372
23686
|
}
|
|
23373
23687
|
}
|
|
@@ -23893,8 +24207,8 @@ var init_sentinel_tools = __esm({
|
|
|
23893
24207
|
});
|
|
23894
24208
|
|
|
23895
24209
|
// src/sentinel-scanner.ts
|
|
23896
|
-
import { readFileSync as
|
|
23897
|
-
import { resolve as
|
|
24210
|
+
import { readFileSync as readFileSync36, existsSync as existsSync38, readdirSync as readdirSync23, statSync as statSync13 } from "fs";
|
|
24211
|
+
import { resolve as resolve33, join as join22, basename as basename7, dirname as dirname18, relative as relative11 } from "path";
|
|
23898
24212
|
function inferDomain(filePath) {
|
|
23899
24213
|
const domains = getConfig().domains;
|
|
23900
24214
|
const path = filePath.toLowerCase();
|
|
@@ -24025,8 +24339,8 @@ function scanComponentExports(dataDb) {
|
|
|
24025
24339
|
const projectRoot = getProjectRoot();
|
|
24026
24340
|
const componentsBase = config.paths.components ?? config.paths.source + "/components";
|
|
24027
24341
|
const componentDirs = [];
|
|
24028
|
-
const basePath =
|
|
24029
|
-
if (
|
|
24342
|
+
const basePath = resolve33(projectRoot, componentsBase);
|
|
24343
|
+
if (existsSync38(basePath)) {
|
|
24030
24344
|
try {
|
|
24031
24345
|
const entries = readdirSync23(basePath, { withFileTypes: true });
|
|
24032
24346
|
for (const entry of entries) {
|
|
@@ -24038,12 +24352,12 @@ function scanComponentExports(dataDb) {
|
|
|
24038
24352
|
}
|
|
24039
24353
|
}
|
|
24040
24354
|
for (const dir of componentDirs) {
|
|
24041
|
-
const absDir =
|
|
24042
|
-
if (!
|
|
24355
|
+
const absDir = resolve33(projectRoot, dir);
|
|
24356
|
+
if (!existsSync38(absDir)) continue;
|
|
24043
24357
|
const files = walkDir2(absDir).filter((f2) => f2.endsWith(".tsx") || f2.endsWith(".ts"));
|
|
24044
24358
|
for (const file of files) {
|
|
24045
24359
|
const relPath = relative11(projectRoot, file);
|
|
24046
|
-
const source =
|
|
24360
|
+
const source = readFileSync36(file, "utf-8");
|
|
24047
24361
|
const annotations = parseFeatureAnnotations(source);
|
|
24048
24362
|
if (annotations.length > 0) {
|
|
24049
24363
|
for (const ann of annotations) {
|
|
@@ -25086,7 +25400,7 @@ var init_audit_trail = __esm({
|
|
|
25086
25400
|
});
|
|
25087
25401
|
|
|
25088
25402
|
// src/validation-engine.ts
|
|
25089
|
-
import { existsSync as
|
|
25403
|
+
import { existsSync as existsSync39, readFileSync as readFileSync37 } from "fs";
|
|
25090
25404
|
function p10(baseName) {
|
|
25091
25405
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
25092
25406
|
}
|
|
@@ -25117,7 +25431,7 @@ function validateFile(filePath, projectRoot) {
|
|
|
25117
25431
|
});
|
|
25118
25432
|
return checks;
|
|
25119
25433
|
}
|
|
25120
|
-
if (!
|
|
25434
|
+
if (!existsSync39(absPath)) {
|
|
25121
25435
|
checks.push({
|
|
25122
25436
|
name: "file_exists",
|
|
25123
25437
|
severity: "error",
|
|
@@ -25126,7 +25440,7 @@ function validateFile(filePath, projectRoot) {
|
|
|
25126
25440
|
});
|
|
25127
25441
|
return checks;
|
|
25128
25442
|
}
|
|
25129
|
-
const source =
|
|
25443
|
+
const source = readFileSync37(absPath, "utf-8");
|
|
25130
25444
|
const lines = source.split("\n");
|
|
25131
25445
|
if (activeChecks.rule_compliance !== false) {
|
|
25132
25446
|
for (const ruleSet of config.rules) {
|
|
@@ -25572,7 +25886,7 @@ var init_adr_generator = __esm({
|
|
|
25572
25886
|
});
|
|
25573
25887
|
|
|
25574
25888
|
// src/security-scorer.ts
|
|
25575
|
-
import { existsSync as
|
|
25889
|
+
import { existsSync as existsSync40, readFileSync as readFileSync38 } from "fs";
|
|
25576
25890
|
function p12(baseName) {
|
|
25577
25891
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
25578
25892
|
}
|
|
@@ -25596,12 +25910,12 @@ function scoreFileSecurity(filePath, projectRoot) {
|
|
|
25596
25910
|
}]
|
|
25597
25911
|
};
|
|
25598
25912
|
}
|
|
25599
|
-
if (!
|
|
25913
|
+
if (!existsSync40(absPath)) {
|
|
25600
25914
|
return { riskScore: 0, findings: [] };
|
|
25601
25915
|
}
|
|
25602
25916
|
let source;
|
|
25603
25917
|
try {
|
|
25604
|
-
source =
|
|
25918
|
+
source = readFileSync38(absPath, "utf-8");
|
|
25605
25919
|
} catch {
|
|
25606
25920
|
return { riskScore: 0, findings: [] };
|
|
25607
25921
|
}
|
|
@@ -25891,8 +26205,8 @@ var init_security_scorer = __esm({
|
|
|
25891
26205
|
});
|
|
25892
26206
|
|
|
25893
26207
|
// src/dependency-scorer.ts
|
|
25894
|
-
import { existsSync as
|
|
25895
|
-
import { resolve as
|
|
26208
|
+
import { existsSync as existsSync41, readFileSync as readFileSync39 } from "fs";
|
|
26209
|
+
import { resolve as resolve34 } from "path";
|
|
25896
26210
|
function p13(baseName) {
|
|
25897
26211
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
25898
26212
|
}
|
|
@@ -25924,10 +26238,10 @@ function calculateDepRisk(factors) {
|
|
|
25924
26238
|
return Math.min(100, risk);
|
|
25925
26239
|
}
|
|
25926
26240
|
function getInstalledPackages(projectRoot) {
|
|
25927
|
-
const pkgPath =
|
|
25928
|
-
if (!
|
|
26241
|
+
const pkgPath = resolve34(projectRoot, "package.json");
|
|
26242
|
+
if (!existsSync41(pkgPath)) return /* @__PURE__ */ new Map();
|
|
25929
26243
|
try {
|
|
25930
|
-
const pkg = JSON.parse(
|
|
26244
|
+
const pkg = JSON.parse(readFileSync39(pkgPath, "utf-8"));
|
|
25931
26245
|
const packages = /* @__PURE__ */ new Map();
|
|
25932
26246
|
for (const [name, version] of Object.entries(pkg.dependencies ?? {})) {
|
|
25933
26247
|
packages.set(name, version);
|
|
@@ -26533,8 +26847,8 @@ var init_regression_detector = __esm({
|
|
|
26533
26847
|
|
|
26534
26848
|
// src/knowledge-indexer.ts
|
|
26535
26849
|
import { createHash as createHash9 } from "crypto";
|
|
26536
|
-
import { readFileSync as
|
|
26537
|
-
import { resolve as
|
|
26850
|
+
import { readFileSync as readFileSync40, readdirSync as readdirSync24, statSync as statSync14, existsSync as existsSync42 } from "fs";
|
|
26851
|
+
import { resolve as resolve35, relative as relative12, basename as basename8, extname as extname2 } from "path";
|
|
26538
26852
|
function getKnowledgePaths() {
|
|
26539
26853
|
const resolved = getResolvedPaths();
|
|
26540
26854
|
const config = getConfig();
|
|
@@ -26562,7 +26876,7 @@ function discoverMarkdownFiles(baseDir) {
|
|
|
26562
26876
|
try {
|
|
26563
26877
|
const entries = readdirSync24(dir, { withFileTypes: true });
|
|
26564
26878
|
for (const entry of entries) {
|
|
26565
|
-
const fullPath =
|
|
26879
|
+
const fullPath = resolve35(dir, entry.name);
|
|
26566
26880
|
if (entry.isDirectory()) {
|
|
26567
26881
|
if (entry.name === "archive" && dir.includes("session-state")) continue;
|
|
26568
26882
|
if (entry.name === "archive" && dir.includes("status")) continue;
|
|
@@ -26841,11 +27155,11 @@ function indexAllKnowledge(db) {
|
|
|
26841
27155
|
files.push(...memFiles);
|
|
26842
27156
|
} catch {
|
|
26843
27157
|
}
|
|
26844
|
-
if (
|
|
27158
|
+
if (existsSync42(paths.plansDir)) {
|
|
26845
27159
|
const planFiles = discoverMarkdownFiles(paths.plansDir);
|
|
26846
27160
|
files.push(...planFiles);
|
|
26847
27161
|
}
|
|
26848
|
-
if (
|
|
27162
|
+
if (existsSync42(paths.docsDir)) {
|
|
26849
27163
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
26850
27164
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
26851
27165
|
files.push(...docsFiles);
|
|
@@ -26888,8 +27202,8 @@ function indexAllKnowledge(db) {
|
|
|
26888
27202
|
} catch {
|
|
26889
27203
|
}
|
|
26890
27204
|
for (const filePath of files) {
|
|
26891
|
-
if (!
|
|
26892
|
-
const content =
|
|
27205
|
+
if (!existsSync42(filePath)) continue;
|
|
27206
|
+
const content = readFileSync40(filePath, "utf-8");
|
|
26893
27207
|
const hash = hashContent2(content);
|
|
26894
27208
|
const relPath = filePath.startsWith(paths.claudeDir) ? relative12(paths.claudeDir, filePath) : filePath.startsWith(paths.plansDir) ? "plans/" + relative12(paths.plansDir, filePath) : filePath.startsWith(paths.docsDir) ? "docs/" + relative12(paths.docsDir, filePath) : filePath.startsWith(paths.memoryDir) ? `memory/${relative12(paths.memoryDir, filePath)}` : basename8(filePath);
|
|
26895
27209
|
const category = categorizeFile(filePath);
|
|
@@ -27024,10 +27338,10 @@ function isKnowledgeStale(db) {
|
|
|
27024
27338
|
files.push(...discoverMarkdownFiles(paths.memoryDir));
|
|
27025
27339
|
} catch {
|
|
27026
27340
|
}
|
|
27027
|
-
if (
|
|
27341
|
+
if (existsSync42(paths.plansDir)) {
|
|
27028
27342
|
files.push(...discoverMarkdownFiles(paths.plansDir));
|
|
27029
27343
|
}
|
|
27030
|
-
if (
|
|
27344
|
+
if (existsSync42(paths.docsDir)) {
|
|
27031
27345
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
27032
27346
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
27033
27347
|
files.push(...docsFiles);
|
|
@@ -27056,8 +27370,8 @@ var init_knowledge_indexer = __esm({
|
|
|
27056
27370
|
});
|
|
27057
27371
|
|
|
27058
27372
|
// src/knowledge-tools.ts
|
|
27059
|
-
import { readFileSync as
|
|
27060
|
-
import { resolve as
|
|
27373
|
+
import { readFileSync as readFileSync41, writeFileSync as writeFileSync7, appendFileSync as appendFileSync2, readdirSync as readdirSync25 } from "fs";
|
|
27374
|
+
import { resolve as resolve36, basename as basename9 } from "path";
|
|
27061
27375
|
function p16(baseName) {
|
|
27062
27376
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
27063
27377
|
}
|
|
@@ -27796,7 +28110,7 @@ function handleCorrect(db, args2) {
|
|
|
27796
28110
|
if (!wrong || !correction || !rule) {
|
|
27797
28111
|
return text15("Error: wrong, correction, and rule are all required.");
|
|
27798
28112
|
}
|
|
27799
|
-
const correctionsPath =
|
|
28113
|
+
const correctionsPath = resolve36(getResolvedPaths().memoryDir, "corrections.md");
|
|
27800
28114
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
27801
28115
|
const title = rule.slice(0, 60);
|
|
27802
28116
|
const entry = `
|
|
@@ -27809,14 +28123,14 @@ ${crRule ? `- **CR**: ${crRule}
|
|
|
27809
28123
|
`;
|
|
27810
28124
|
let existing = "";
|
|
27811
28125
|
try {
|
|
27812
|
-
existing =
|
|
28126
|
+
existing = readFileSync41(correctionsPath, "utf-8");
|
|
27813
28127
|
} catch {
|
|
27814
28128
|
}
|
|
27815
28129
|
const archiveIdx = existing.indexOf("## Archived");
|
|
27816
28130
|
if (archiveIdx > 0) {
|
|
27817
28131
|
const before = existing.slice(0, archiveIdx);
|
|
27818
28132
|
const after = existing.slice(archiveIdx);
|
|
27819
|
-
|
|
28133
|
+
writeFileSync7(correctionsPath, before + entry + after);
|
|
27820
28134
|
} else {
|
|
27821
28135
|
appendFileSync2(correctionsPath, entry);
|
|
27822
28136
|
}
|
|
@@ -28764,8 +29078,8 @@ var init_framework_supports = __esm({
|
|
|
28764
29078
|
});
|
|
28765
29079
|
|
|
28766
29080
|
// src/tools.ts
|
|
28767
|
-
import { readFileSync as
|
|
28768
|
-
import { resolve as
|
|
29081
|
+
import { readFileSync as readFileSync42, existsSync as existsSync44 } from "fs";
|
|
29082
|
+
import { resolve as resolve37, basename as basename10 } from "path";
|
|
28769
29083
|
function prefix2() {
|
|
28770
29084
|
return getConfig().toolPrefix;
|
|
28771
29085
|
}
|
|
@@ -28800,7 +29114,7 @@ function ensureIndexes(dataDb, codegraphDb, force = false) {
|
|
|
28800
29114
|
if (config.python?.root) {
|
|
28801
29115
|
const pythonRoot = config.python.root;
|
|
28802
29116
|
const excludeDirs = config.python.exclude_dirs || ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"];
|
|
28803
|
-
if (force || isPythonDataStale(dataDb,
|
|
29117
|
+
if (force || isPythonDataStale(dataDb, resolve37(getProjectRoot(), pythonRoot))) {
|
|
28804
29118
|
const pyImports = buildPythonImportIndex(dataDb, pythonRoot, excludeDirs);
|
|
28805
29119
|
results.push(`Python imports: ${pyImports}`);
|
|
28806
29120
|
const pyRoutes = buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs);
|
|
@@ -29183,9 +29497,9 @@ function handleContext(file, dataDb, codegraphDb) {
|
|
|
29183
29497
|
try {
|
|
29184
29498
|
const resolvedPaths = getResolvedPaths();
|
|
29185
29499
|
const root = getProjectRoot();
|
|
29186
|
-
const absFilePath = ensureWithinRoot(
|
|
29187
|
-
if (
|
|
29188
|
-
const fileContent =
|
|
29500
|
+
const absFilePath = ensureWithinRoot(resolve37(resolvedPaths.srcDir, "..", file), root);
|
|
29501
|
+
if (existsSync44(absFilePath)) {
|
|
29502
|
+
const fileContent = readFileSync42(absFilePath, "utf-8").slice(0, 3e3);
|
|
29189
29503
|
const keywords = [];
|
|
29190
29504
|
if (fileContent.includes("ctx.db")) keywords.push("database", "schema");
|
|
29191
29505
|
if (fileContent.includes("BigInt") || fileContent.includes("Decimal")) keywords.push("BigInt", "serialization");
|
|
@@ -29622,11 +29936,11 @@ function handleSchema(args2) {
|
|
|
29622
29936
|
lines.push("Checking all column references against Prisma schema...");
|
|
29623
29937
|
lines.push("");
|
|
29624
29938
|
const projectRoot = getProjectRoot();
|
|
29625
|
-
const absPath = ensureWithinRoot(
|
|
29626
|
-
if (!
|
|
29939
|
+
const absPath = ensureWithinRoot(resolve37(projectRoot, file), projectRoot);
|
|
29940
|
+
if (!existsSync44(absPath)) {
|
|
29627
29941
|
return text17(`File not found: ${file}`);
|
|
29628
29942
|
}
|
|
29629
|
-
const source =
|
|
29943
|
+
const source = readFileSync42(absPath, "utf-8");
|
|
29630
29944
|
const config = getConfig();
|
|
29631
29945
|
const dbPattern = config.dbAccessPattern ?? "ctx.db.{table}";
|
|
29632
29946
|
const regexStr = dbPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{table\\}", "(\\w+)");
|
|
@@ -30031,8 +30345,8 @@ var init_server_dispatch = __esm({
|
|
|
30031
30345
|
|
|
30032
30346
|
// src/server.ts
|
|
30033
30347
|
var server_exports = {};
|
|
30034
|
-
import { readFileSync as
|
|
30035
|
-
import { resolve as
|
|
30348
|
+
import { readFileSync as readFileSync43 } from "fs";
|
|
30349
|
+
import { resolve as resolve38, dirname as dirname19 } from "path";
|
|
30036
30350
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
30037
30351
|
function pruneMemoryOnStartup() {
|
|
30038
30352
|
try {
|
|
@@ -30067,7 +30381,7 @@ var init_server = __esm({
|
|
|
30067
30381
|
__dirname5 = dirname19(fileURLToPath5(import.meta.url));
|
|
30068
30382
|
PKG_VERSION = (() => {
|
|
30069
30383
|
try {
|
|
30070
|
-
const pkg = JSON.parse(
|
|
30384
|
+
const pkg = JSON.parse(readFileSync43(resolve38(__dirname5, "..", "package.json"), "utf-8"));
|
|
30071
30385
|
return pkg.version ?? "0.0.0";
|
|
30072
30386
|
} catch {
|
|
30073
30387
|
return "0.0.0";
|
|
@@ -30353,19 +30667,19 @@ var config_upgrade_exports = {};
|
|
|
30353
30667
|
__export(config_upgrade_exports, {
|
|
30354
30668
|
runConfigUpgrade: () => runConfigUpgrade
|
|
30355
30669
|
});
|
|
30356
|
-
import { existsSync as
|
|
30357
|
-
import { resolve as
|
|
30670
|
+
import { existsSync as existsSync45, readFileSync as readFileSync44, writeFileSync as writeFileSync8, copyFileSync, unlinkSync as unlinkSync2 } from "fs";
|
|
30671
|
+
import { resolve as resolve39 } from "path";
|
|
30358
30672
|
import { parse as parseYaml6 } from "yaml";
|
|
30359
30673
|
async function runConfigUpgrade(opts = {}) {
|
|
30360
30674
|
const cwd = opts.cwd ?? process.cwd();
|
|
30361
|
-
const configPath =
|
|
30675
|
+
const configPath = resolve39(cwd, "massu.config.yaml");
|
|
30362
30676
|
const bakPath = `${configPath}.bak`;
|
|
30363
30677
|
const log = opts.silent ? () => {
|
|
30364
30678
|
} : (s) => process.stdout.write(s);
|
|
30365
30679
|
const err = opts.silent ? () => {
|
|
30366
30680
|
} : (s) => process.stderr.write(s);
|
|
30367
30681
|
if (opts.rollback) {
|
|
30368
|
-
if (!
|
|
30682
|
+
if (!existsSync45(bakPath)) {
|
|
30369
30683
|
const message = `No backup found at ${bakPath}`;
|
|
30370
30684
|
err(message + "\n");
|
|
30371
30685
|
return { exitCode: 1, action: "none", message };
|
|
@@ -30381,14 +30695,14 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
30381
30695
|
return { exitCode: 2, action: "none", message };
|
|
30382
30696
|
}
|
|
30383
30697
|
}
|
|
30384
|
-
if (!
|
|
30698
|
+
if (!existsSync45(configPath)) {
|
|
30385
30699
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
30386
30700
|
err(message + "\n");
|
|
30387
30701
|
return { exitCode: 1, action: "none", message };
|
|
30388
30702
|
}
|
|
30389
30703
|
let existing;
|
|
30390
30704
|
try {
|
|
30391
|
-
const content =
|
|
30705
|
+
const content = readFileSync44(configPath, "utf-8");
|
|
30392
30706
|
const parsed = parseYaml6(content);
|
|
30393
30707
|
if (!parsed || typeof parsed !== "object") {
|
|
30394
30708
|
throw new Error("config is not a YAML object");
|
|
@@ -30411,8 +30725,8 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
30411
30725
|
fingerprint: computeFingerprint(detection)
|
|
30412
30726
|
};
|
|
30413
30727
|
try {
|
|
30414
|
-
const original =
|
|
30415
|
-
|
|
30728
|
+
const original = readFileSync44(configPath, "utf-8");
|
|
30729
|
+
writeFileSync8(bakPath, original, "utf-8");
|
|
30416
30730
|
} catch (e2) {
|
|
30417
30731
|
const message = `Failed to write backup: ${e2 instanceof Error ? e2.message : String(e2)}`;
|
|
30418
30732
|
err(message + "\n");
|
|
@@ -30445,8 +30759,8 @@ var config_check_drift_exports = {};
|
|
|
30445
30759
|
__export(config_check_drift_exports, {
|
|
30446
30760
|
runConfigCheckDrift: () => runConfigCheckDrift
|
|
30447
30761
|
});
|
|
30448
|
-
import { existsSync as
|
|
30449
|
-
import { resolve as
|
|
30762
|
+
import { existsSync as existsSync46, readFileSync as readFileSync45 } from "fs";
|
|
30763
|
+
import { resolve as resolve40 } from "path";
|
|
30450
30764
|
import { parse as parseYaml7 } from "yaml";
|
|
30451
30765
|
function renderChanges(changes) {
|
|
30452
30766
|
if (changes.length === 0) return "(none)\n";
|
|
@@ -30454,12 +30768,12 @@ function renderChanges(changes) {
|
|
|
30454
30768
|
}
|
|
30455
30769
|
async function runConfigCheckDrift(opts = {}) {
|
|
30456
30770
|
const cwd = opts.cwd ?? process.cwd();
|
|
30457
|
-
const configPath =
|
|
30771
|
+
const configPath = resolve40(cwd, "massu.config.yaml");
|
|
30458
30772
|
const log = opts.silent ? () => {
|
|
30459
30773
|
} : (s) => process.stdout.write(s);
|
|
30460
30774
|
const err = opts.silent ? () => {
|
|
30461
30775
|
} : (s) => process.stderr.write(s);
|
|
30462
|
-
if (!
|
|
30776
|
+
if (!existsSync46(configPath)) {
|
|
30463
30777
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
30464
30778
|
err(message + "\n");
|
|
30465
30779
|
return {
|
|
@@ -30473,7 +30787,7 @@ async function runConfigCheckDrift(opts = {}) {
|
|
|
30473
30787
|
}
|
|
30474
30788
|
let config;
|
|
30475
30789
|
try {
|
|
30476
|
-
const content =
|
|
30790
|
+
const content = readFileSync45(configPath, "utf-8");
|
|
30477
30791
|
const parsed = parseYaml7(content);
|
|
30478
30792
|
if (!parsed || typeof parsed !== "object") {
|
|
30479
30793
|
throw new Error("config is not a YAML object");
|
|
@@ -30540,8 +30854,8 @@ var init_config_check_drift = __esm({
|
|
|
30540
30854
|
});
|
|
30541
30855
|
|
|
30542
30856
|
// src/cli.ts
|
|
30543
|
-
import { readFileSync as
|
|
30544
|
-
import { resolve as
|
|
30857
|
+
import { readFileSync as readFileSync46 } from "fs";
|
|
30858
|
+
import { resolve as resolve41, dirname as dirname20 } from "path";
|
|
30545
30859
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
30546
30860
|
var __filename5 = fileURLToPath6(import.meta.url);
|
|
30547
30861
|
var __dirname6 = dirname20(__filename5);
|
|
@@ -30559,6 +30873,16 @@ async function main() {
|
|
|
30559
30873
|
await runDoctor2();
|
|
30560
30874
|
break;
|
|
30561
30875
|
}
|
|
30876
|
+
case "login": {
|
|
30877
|
+
const { runLogin: runLogin2 } = await Promise.resolve().then(() => (init_login(), login_exports));
|
|
30878
|
+
await runLogin2(args.slice(1));
|
|
30879
|
+
break;
|
|
30880
|
+
}
|
|
30881
|
+
case "logout": {
|
|
30882
|
+
const { runLogout: runLogout2 } = await Promise.resolve().then(() => (init_login(), login_exports));
|
|
30883
|
+
await runLogout2();
|
|
30884
|
+
break;
|
|
30885
|
+
}
|
|
30562
30886
|
case "install-hooks": {
|
|
30563
30887
|
const { runInstallHooks: runInstallHooks2 } = await Promise.resolve().then(() => (init_install_hooks(), install_hooks_exports));
|
|
30564
30888
|
await runInstallHooks2();
|
|
@@ -30582,7 +30906,7 @@ async function main() {
|
|
|
30582
30906
|
return;
|
|
30583
30907
|
}
|
|
30584
30908
|
case "license": {
|
|
30585
|
-
const { handleLicenseSubcommand: handleLicenseSubcommand2 } = await Promise.resolve().then(() => (init_license2(),
|
|
30909
|
+
const { handleLicenseSubcommand: handleLicenseSubcommand2 } = await Promise.resolve().then(() => (init_license2(), license_exports2));
|
|
30586
30910
|
const result = await handleLicenseSubcommand2(args.slice(1));
|
|
30587
30911
|
process.exit(result.exitCode);
|
|
30588
30912
|
return;
|
|
@@ -30719,6 +31043,10 @@ Usage:
|
|
|
30719
31043
|
Commands:
|
|
30720
31044
|
init Set up Massu AI in your project (one command, full setup)
|
|
30721
31045
|
doctor Check installation health
|
|
31046
|
+
login Store your API key user-level in ~/.massu/credentials (git-safe).
|
|
31047
|
+
Prefer the interactive prompt or MASSU_API_KEY env; --key <k>
|
|
31048
|
+
exposes the key to shell history. Use --no-verify to skip online check.
|
|
31049
|
+
logout Remove the stored user-level API key
|
|
30722
31050
|
install-hooks Install/update Claude Code hooks
|
|
30723
31051
|
install-commands Install/update slash commands (use --skip-permissions to opt out of MCP allowlist seeding)
|
|
30724
31052
|
show-template Print the resolved variant of a bundled template (e.g. for diffs)
|
|
@@ -30769,7 +31097,7 @@ Examples:
|
|
|
30769
31097
|
}
|
|
30770
31098
|
function printVersion() {
|
|
30771
31099
|
try {
|
|
30772
|
-
const pkg = JSON.parse(
|
|
31100
|
+
const pkg = JSON.parse(readFileSync46(resolve41(__dirname6, "../package.json"), "utf-8"));
|
|
30773
31101
|
console.log(`massu v${pkg.version}`);
|
|
30774
31102
|
} catch {
|
|
30775
31103
|
console.log("massu v0.1.0");
|