@massu/core 1.15.0 → 1.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/commands/massu-loop/references/loop-controller.md +54 -7
- package/dist/cli.js +930 -575
- package/dist/hooks/auto-learning-pipeline.js +90 -19
- package/dist/hooks/classify-failure.js +112 -43
- package/dist/hooks/cost-tracker.js +108 -39
- package/dist/hooks/fix-detector.js +95 -24
- package/dist/hooks/incident-pipeline.js +114 -45
- package/dist/hooks/post-edit-context.js +105 -36
- package/dist/hooks/post-tool-use.js +137 -68
- package/dist/hooks/pre-compact.js +108 -39
- package/dist/hooks/pre-delete-check.js +107 -38
- package/dist/hooks/pre-tool-use-gate.js +113 -44
- package/dist/hooks/quality-event.js +108 -39
- package/dist/hooks/rule-enforcement-pipeline.js +92 -21
- package/dist/hooks/session-end.js +126 -57
- package/dist/hooks/session-start.js +177 -99
- package/dist/hooks/user-prompt.js +124 -55
- package/package.json +7 -6
package/dist/cli.js
CHANGED
|
@@ -12,11 +12,20 @@ var __require = /* @__PURE__ */ ((x2) => typeof require !== "undefined" ? requir
|
|
|
12
12
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
13
13
|
throw Error('Dynamic require of "' + x2 + '" is not supported');
|
|
14
14
|
});
|
|
15
|
-
var __esm = (fn, res) => function __init() {
|
|
16
|
-
|
|
15
|
+
var __esm = (fn, res, err) => function __init() {
|
|
16
|
+
if (err) throw err[0];
|
|
17
|
+
try {
|
|
18
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
19
|
+
} catch (e2) {
|
|
20
|
+
throw err = [e2], e2;
|
|
21
|
+
}
|
|
17
22
|
};
|
|
18
23
|
var __commonJS = (cb, mod) => function __require2() {
|
|
19
|
-
|
|
24
|
+
try {
|
|
25
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
26
|
+
} catch (e2) {
|
|
27
|
+
throw mod = 0, e2;
|
|
28
|
+
}
|
|
20
29
|
};
|
|
21
30
|
var __export = (target, all) => {
|
|
22
31
|
for (var name in all)
|
|
@@ -49,17 +58,136 @@ var init_memory_path = __esm({
|
|
|
49
58
|
}
|
|
50
59
|
});
|
|
51
60
|
|
|
52
|
-
// src/
|
|
53
|
-
import { resolve, dirname } from "path";
|
|
54
|
-
import { existsSync, readFileSync } from "fs";
|
|
61
|
+
// src/credentials.ts
|
|
55
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";
|
|
56
184
|
import { parse as parseYaml } from "yaml";
|
|
57
185
|
import { z } from "zod";
|
|
58
186
|
function findProjectRoot() {
|
|
59
187
|
const cwd = process.cwd();
|
|
60
188
|
let dir = cwd;
|
|
61
189
|
while (true) {
|
|
62
|
-
if (
|
|
190
|
+
if (existsSync2(resolve2(dir, "massu.config.yaml"))) {
|
|
63
191
|
return dir;
|
|
64
192
|
}
|
|
65
193
|
const parent = dirname(dir);
|
|
@@ -68,10 +196,10 @@ function findProjectRoot() {
|
|
|
68
196
|
}
|
|
69
197
|
dir = cwd;
|
|
70
198
|
while (true) {
|
|
71
|
-
if (
|
|
199
|
+
if (existsSync2(resolve2(dir, "package.json"))) {
|
|
72
200
|
return dir;
|
|
73
201
|
}
|
|
74
|
-
if (
|
|
202
|
+
if (existsSync2(resolve2(dir, ".git"))) {
|
|
75
203
|
return dir;
|
|
76
204
|
}
|
|
77
205
|
const parent = dirname(dir);
|
|
@@ -89,10 +217,10 @@ function getProjectRoot() {
|
|
|
89
217
|
function getConfig() {
|
|
90
218
|
if (_config) return _config;
|
|
91
219
|
const root = getProjectRoot();
|
|
92
|
-
const configPath =
|
|
220
|
+
const configPath = resolve2(root, "massu.config.yaml");
|
|
93
221
|
let rawYaml = {};
|
|
94
|
-
if (
|
|
95
|
-
const content =
|
|
222
|
+
if (existsSync2(configPath)) {
|
|
223
|
+
const content = readFileSync2(configPath, "utf-8");
|
|
96
224
|
rawYaml = parseYaml(content) ?? {};
|
|
97
225
|
}
|
|
98
226
|
const result = RawConfigSchema.safeParse(rawYaml);
|
|
@@ -109,7 +237,7 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
109
237
|
);
|
|
110
238
|
}
|
|
111
239
|
const parsed = result.data;
|
|
112
|
-
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);
|
|
113
241
|
const fw = parsed.framework;
|
|
114
242
|
let router = fw.router;
|
|
115
243
|
let orm = fw.orm;
|
|
@@ -167,60 +295,72 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
167
295
|
telemetry: parsed.telemetry,
|
|
168
296
|
lsp: parsed.lsp
|
|
169
297
|
};
|
|
170
|
-
|
|
298
|
+
const resolvedKey = resolveApiKey({ configApiKey: _config.cloud?.apiKey });
|
|
299
|
+
_resolvedApiKeySource = resolvedKey.source;
|
|
300
|
+
const resolvedEndpoint = resolveEndpoint({ configEndpoint: _config.cloud?.endpoint });
|
|
301
|
+
if (resolvedKey.apiKey) {
|
|
171
302
|
_config.cloud = {
|
|
172
303
|
enabled: true,
|
|
173
304
|
sync: { memory: true, analytics: true, audit: true },
|
|
174
305
|
..._config.cloud,
|
|
175
|
-
apiKey:
|
|
306
|
+
apiKey: resolvedKey.apiKey,
|
|
307
|
+
endpoint: resolvedEndpoint
|
|
176
308
|
};
|
|
309
|
+
} else if (_config.cloud) {
|
|
310
|
+
_config.cloud = { ..._config.cloud, endpoint: _config.cloud.endpoint ?? resolvedEndpoint };
|
|
177
311
|
}
|
|
178
312
|
return _config;
|
|
179
313
|
}
|
|
314
|
+
function getResolvedApiKeySource() {
|
|
315
|
+
getConfig();
|
|
316
|
+
return _resolvedApiKeySource;
|
|
317
|
+
}
|
|
180
318
|
function getResolvedPaths() {
|
|
181
319
|
const config = getConfig();
|
|
182
320
|
const root = getProjectRoot();
|
|
183
321
|
const claudeDirName = config.conventions?.claudeDirName ?? ".claude";
|
|
184
322
|
return {
|
|
185
|
-
codegraphDbPath:
|
|
186
|
-
dataDbPath:
|
|
187
|
-
prismaSchemaPath:
|
|
188
|
-
rootRouterPath:
|
|
189
|
-
routersDir:
|
|
190
|
-
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),
|
|
191
329
|
pathAlias: Object.fromEntries(
|
|
192
330
|
Object.entries(config.paths.aliases).map(([alias, target]) => [
|
|
193
331
|
alias,
|
|
194
|
-
|
|
332
|
+
resolve2(root, target)
|
|
195
333
|
])
|
|
196
334
|
),
|
|
197
335
|
extensions: [".ts", ".tsx", ".js", ".jsx"],
|
|
198
336
|
indexFiles: ["index.ts", "index.tsx", "index.js", "index.jsx"],
|
|
199
|
-
patternsDir:
|
|
200
|
-
claudeMdPath:
|
|
201
|
-
docsMapPath:
|
|
202
|
-
helpSitePath:
|
|
203
|
-
memoryDbPath:
|
|
204
|
-
knowledgeDbPath:
|
|
205
|
-
plansDir:
|
|
206
|
-
docsDir:
|
|
207
|
-
claudeDir:
|
|
208
|
-
memoryDir:
|
|
209
|
-
sessionStatePath:
|
|
210
|
-
sessionArchivePath:
|
|
211
|
-
mcpJsonPath:
|
|
212
|
-
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")
|
|
213
351
|
};
|
|
214
352
|
}
|
|
215
353
|
function resetConfig() {
|
|
216
354
|
_config = null;
|
|
217
355
|
_projectRoot = null;
|
|
356
|
+
_resolvedApiKeySource = "none";
|
|
218
357
|
}
|
|
219
|
-
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;
|
|
220
359
|
var init_config = __esm({
|
|
221
360
|
"src/config.ts"() {
|
|
222
361
|
"use strict";
|
|
223
362
|
init_memory_path();
|
|
363
|
+
init_credentials();
|
|
224
364
|
DomainConfigSchema = z.object({
|
|
225
365
|
name: z.string().default("Unknown"),
|
|
226
366
|
routers: z.array(z.string()).default([]),
|
|
@@ -602,6 +742,7 @@ var init_config = __esm({
|
|
|
602
742
|
lsp: LSPConfigSchema.optional()
|
|
603
743
|
}).passthrough();
|
|
604
744
|
_config = null;
|
|
745
|
+
_resolvedApiKeySource = "none";
|
|
605
746
|
_projectRoot = null;
|
|
606
747
|
}
|
|
607
748
|
});
|
|
@@ -664,7 +805,7 @@ __export(memory_db_exports, {
|
|
|
664
805
|
});
|
|
665
806
|
import Database from "better-sqlite3";
|
|
666
807
|
import { dirname as dirname2, basename } from "path";
|
|
667
|
-
import { existsSync as
|
|
808
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
668
809
|
function sanitizeFts5Query(raw) {
|
|
669
810
|
const trimmed = raw.trim();
|
|
670
811
|
if (!trimmed) return '""';
|
|
@@ -674,8 +815,8 @@ function sanitizeFts5Query(raw) {
|
|
|
674
815
|
function getMemoryDb() {
|
|
675
816
|
const dbPath = getResolvedPaths().memoryDbPath;
|
|
676
817
|
const dir = dirname2(dbPath);
|
|
677
|
-
if (!
|
|
678
|
-
|
|
818
|
+
if (!existsSync3(dir)) {
|
|
819
|
+
mkdirSync2(dir, { recursive: true });
|
|
679
820
|
}
|
|
680
821
|
const db = new Database(dbPath);
|
|
681
822
|
db.pragma("journal_mode = WAL");
|
|
@@ -2008,12 +2149,12 @@ var init_memory_db = __esm({
|
|
|
2008
2149
|
});
|
|
2009
2150
|
|
|
2010
2151
|
// src/memory-file-ingest.ts
|
|
2011
|
-
import { readFileSync as
|
|
2152
|
+
import { readFileSync as readFileSync3, existsSync as existsSync4, readdirSync } from "fs";
|
|
2012
2153
|
import { join } from "path";
|
|
2013
2154
|
import { parse as parseYaml2 } from "yaml";
|
|
2014
2155
|
function ingestMemoryFile(db, sessionId, filePath) {
|
|
2015
|
-
if (!
|
|
2016
|
-
const content =
|
|
2156
|
+
if (!existsSync4(filePath)) return "skipped";
|
|
2157
|
+
const content = readFileSync3(filePath, "utf-8");
|
|
2017
2158
|
const basename11 = (filePath.split("/").pop() ?? "").replace(".md", "");
|
|
2018
2159
|
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
2019
2160
|
let name = basename11;
|
|
@@ -2051,7 +2192,7 @@ ${body}` : body;
|
|
|
2051
2192
|
}
|
|
2052
2193
|
function backfillMemoryFiles(db, memoryDir, sessionId) {
|
|
2053
2194
|
const stats = { inserted: 0, updated: 0, skipped: 0, total: 0 };
|
|
2054
|
-
if (!
|
|
2195
|
+
if (!existsSync4(memoryDir)) return stats;
|
|
2055
2196
|
const files = readdirSync(memoryDir).filter(
|
|
2056
2197
|
(f2) => f2.endsWith(".md") && f2 !== "MEMORY.md"
|
|
2057
2198
|
);
|
|
@@ -2264,16 +2405,16 @@ var init_template_engine = __esm({
|
|
|
2264
2405
|
// src/lib/settings-local.ts
|
|
2265
2406
|
import {
|
|
2266
2407
|
closeSync,
|
|
2267
|
-
existsSync as
|
|
2408
|
+
existsSync as existsSync5,
|
|
2268
2409
|
fsyncSync,
|
|
2269
|
-
mkdirSync as
|
|
2410
|
+
mkdirSync as mkdirSync3,
|
|
2270
2411
|
openSync,
|
|
2271
|
-
readFileSync as
|
|
2412
|
+
readFileSync as readFileSync4,
|
|
2272
2413
|
renameSync,
|
|
2273
|
-
rmSync,
|
|
2414
|
+
rmSync as rmSync2,
|
|
2274
2415
|
writeSync
|
|
2275
2416
|
} from "fs";
|
|
2276
|
-
import { dirname as dirname3, resolve as
|
|
2417
|
+
import { dirname as dirname3, resolve as resolve4 } from "path";
|
|
2277
2418
|
function atomicWriteFile(targetPath, content, mode = 420) {
|
|
2278
2419
|
const tmpPath = `${targetPath}.${process.pid}.tmp`;
|
|
2279
2420
|
try {
|
|
@@ -2287,9 +2428,9 @@ function atomicWriteFile(targetPath, content, mode = 420) {
|
|
|
2287
2428
|
}
|
|
2288
2429
|
renameSync(tmpPath, targetPath);
|
|
2289
2430
|
} catch (err) {
|
|
2290
|
-
if (
|
|
2431
|
+
if (existsSync5(tmpPath)) {
|
|
2291
2432
|
try {
|
|
2292
|
-
|
|
2433
|
+
rmSync2(tmpPath, { force: true });
|
|
2293
2434
|
} catch {
|
|
2294
2435
|
}
|
|
2295
2436
|
}
|
|
@@ -2297,11 +2438,11 @@ function atomicWriteFile(targetPath, content, mode = 420) {
|
|
|
2297
2438
|
}
|
|
2298
2439
|
}
|
|
2299
2440
|
function readSettingsAtPath(absolutePath) {
|
|
2300
|
-
if (!
|
|
2441
|
+
if (!existsSync5(absolutePath)) {
|
|
2301
2442
|
return {};
|
|
2302
2443
|
}
|
|
2303
2444
|
try {
|
|
2304
|
-
const raw =
|
|
2445
|
+
const raw = readFileSync4(absolutePath, "utf-8");
|
|
2305
2446
|
const parsed = JSON.parse(raw);
|
|
2306
2447
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
2307
2448
|
return {};
|
|
@@ -2312,13 +2453,13 @@ function readSettingsAtPath(absolutePath) {
|
|
|
2312
2453
|
}
|
|
2313
2454
|
}
|
|
2314
2455
|
function readSettingsLocal(claudeDir) {
|
|
2315
|
-
return readSettingsAtPath(
|
|
2456
|
+
return readSettingsAtPath(resolve4(claudeDir, "settings.local.json"));
|
|
2316
2457
|
}
|
|
2317
2458
|
function writeSettingsLocalAtomic(claudeDir, settings) {
|
|
2318
|
-
const targetPath =
|
|
2459
|
+
const targetPath = resolve4(claudeDir, "settings.local.json");
|
|
2319
2460
|
const dir = dirname3(targetPath);
|
|
2320
|
-
if (!
|
|
2321
|
-
|
|
2461
|
+
if (!existsSync5(dir)) {
|
|
2462
|
+
mkdirSync3(dir, { recursive: true });
|
|
2322
2463
|
}
|
|
2323
2464
|
const content = JSON.stringify(settings, null, 2) + "\n";
|
|
2324
2465
|
atomicWriteFile(targetPath, content);
|
|
@@ -2331,7 +2472,7 @@ var init_settings_local = __esm({
|
|
|
2331
2472
|
|
|
2332
2473
|
// src/permissions.ts
|
|
2333
2474
|
import { createHash } from "crypto";
|
|
2334
|
-
import { homedir as
|
|
2475
|
+
import { homedir as homedir3 } from "os";
|
|
2335
2476
|
import { join as join2 } from "path";
|
|
2336
2477
|
function canonicalJson(value) {
|
|
2337
2478
|
if (value === null || typeof value !== "object") {
|
|
@@ -2371,7 +2512,7 @@ function detectInvalidDefaultMode(settings) {
|
|
|
2371
2512
|
return { invalid: false };
|
|
2372
2513
|
}
|
|
2373
2514
|
function readGlobalSettings() {
|
|
2374
|
-
return readSettingsAtPath(join2(
|
|
2515
|
+
return readSettingsAtPath(join2(homedir3(), ".claude", "settings.json"));
|
|
2375
2516
|
}
|
|
2376
2517
|
function mergedPermissionState(global2, local, canonical) {
|
|
2377
2518
|
const globalPerm = global2.permissions ?? {};
|
|
@@ -2555,27 +2696,27 @@ __export(install_commands_exports, {
|
|
|
2555
2696
|
syncDirectory: () => syncDirectory
|
|
2556
2697
|
});
|
|
2557
2698
|
import {
|
|
2558
|
-
existsSync as
|
|
2559
|
-
readFileSync as
|
|
2560
|
-
mkdirSync as
|
|
2699
|
+
existsSync as existsSync6,
|
|
2700
|
+
readFileSync as readFileSync5,
|
|
2701
|
+
mkdirSync as mkdirSync4,
|
|
2561
2702
|
readdirSync as readdirSync2,
|
|
2562
2703
|
statSync
|
|
2563
2704
|
} from "fs";
|
|
2564
|
-
import { resolve as
|
|
2705
|
+
import { resolve as resolve5, dirname as dirname4, join as join3 } from "path";
|
|
2565
2706
|
import { fileURLToPath } from "url";
|
|
2566
2707
|
import { createHash as createHash2 } from "crypto";
|
|
2567
2708
|
function resolveAssetDir(assetName) {
|
|
2568
2709
|
const cwd = process.cwd();
|
|
2569
|
-
const nodeModulesPath =
|
|
2570
|
-
if (
|
|
2710
|
+
const nodeModulesPath = resolve5(cwd, "node_modules/@massu/core", assetName);
|
|
2711
|
+
if (existsSync6(nodeModulesPath)) {
|
|
2571
2712
|
return nodeModulesPath;
|
|
2572
2713
|
}
|
|
2573
|
-
const distRelPath =
|
|
2574
|
-
if (
|
|
2714
|
+
const distRelPath = resolve5(__dirname, "..", assetName);
|
|
2715
|
+
if (existsSync6(distRelPath)) {
|
|
2575
2716
|
return distRelPath;
|
|
2576
2717
|
}
|
|
2577
|
-
const srcRelPath =
|
|
2578
|
-
if (
|
|
2718
|
+
const srcRelPath = resolve5(__dirname, "../..", assetName);
|
|
2719
|
+
if (existsSync6(srcRelPath)) {
|
|
2579
2720
|
return srcRelPath;
|
|
2580
2721
|
}
|
|
2581
2722
|
return null;
|
|
@@ -2587,12 +2728,12 @@ function hashContent(content) {
|
|
|
2587
2728
|
return createHash2("sha256").update(content, "utf-8").digest("hex");
|
|
2588
2729
|
}
|
|
2589
2730
|
function loadManifest(claudeDir) {
|
|
2590
|
-
const path =
|
|
2591
|
-
if (!
|
|
2731
|
+
const path = resolve5(claudeDir, MANIFEST_RELPATH);
|
|
2732
|
+
if (!existsSync6(path)) {
|
|
2592
2733
|
return emptyManifest();
|
|
2593
2734
|
}
|
|
2594
2735
|
try {
|
|
2595
|
-
const raw =
|
|
2736
|
+
const raw = readFileSync5(path, "utf-8");
|
|
2596
2737
|
const parsed = JSON.parse(raw);
|
|
2597
2738
|
if (!parsed || typeof parsed !== "object" || !parsed.entries) {
|
|
2598
2739
|
return emptyManifest();
|
|
@@ -2603,11 +2744,11 @@ function loadManifest(claudeDir) {
|
|
|
2603
2744
|
}
|
|
2604
2745
|
}
|
|
2605
2746
|
function saveManifest(claudeDir, manifest) {
|
|
2606
|
-
const dir =
|
|
2607
|
-
if (!
|
|
2608
|
-
|
|
2747
|
+
const dir = resolve5(claudeDir, ".massu");
|
|
2748
|
+
if (!existsSync6(dir)) {
|
|
2749
|
+
mkdirSync4(dir, { recursive: true });
|
|
2609
2750
|
}
|
|
2610
|
-
const finalPath =
|
|
2751
|
+
const finalPath = resolve5(dir, "install-manifest.json");
|
|
2611
2752
|
manifest.generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2612
2753
|
atomicWriteFile(finalPath, JSON.stringify(manifest, null, 2));
|
|
2613
2754
|
}
|
|
@@ -2669,18 +2810,18 @@ function pickVariant(baseName, sourceDir, framework) {
|
|
|
2669
2810
|
}
|
|
2670
2811
|
for (const cand of candidates) {
|
|
2671
2812
|
if (cand.subFramework) {
|
|
2672
|
-
const subPath =
|
|
2673
|
-
if (
|
|
2813
|
+
const subPath = resolve5(sourceDir, `${baseName}.${cand.lang}-${cand.subFramework}.md`);
|
|
2814
|
+
if (existsSync6(subPath)) {
|
|
2674
2815
|
return { kind: "hit", suffix: `.${cand.lang}-${cand.subFramework}` };
|
|
2675
2816
|
}
|
|
2676
2817
|
}
|
|
2677
|
-
const langPath =
|
|
2678
|
-
if (
|
|
2818
|
+
const langPath = resolve5(sourceDir, `${baseName}.${cand.lang}.md`);
|
|
2819
|
+
if (existsSync6(langPath)) {
|
|
2679
2820
|
return { kind: "hit", suffix: `.${cand.lang}` };
|
|
2680
2821
|
}
|
|
2681
2822
|
}
|
|
2682
|
-
const defaultPath =
|
|
2683
|
-
if (
|
|
2823
|
+
const defaultPath = resolve5(sourceDir, `${baseName}.md`);
|
|
2824
|
+
if (existsSync6(defaultPath)) {
|
|
2684
2825
|
return { kind: "hit", suffix: "" };
|
|
2685
2826
|
}
|
|
2686
2827
|
if (framework.type === "multi" && !framework.primary) {
|
|
@@ -2696,15 +2837,15 @@ function isVariantFilename(entry) {
|
|
|
2696
2837
|
}
|
|
2697
2838
|
function syncDirectory(sourceDir, targetDir, framework, manifest, manifestKeyPrefix, topLevel = true, templateVars = {}) {
|
|
2698
2839
|
const stats = { installed: 0, updated: 0, skipped: 0, kept: 0 };
|
|
2699
|
-
if (!
|
|
2700
|
-
|
|
2840
|
+
if (!existsSync6(targetDir)) {
|
|
2841
|
+
mkdirSync4(targetDir, { recursive: true });
|
|
2701
2842
|
}
|
|
2702
2843
|
const entries = readdirSync2(sourceDir);
|
|
2703
2844
|
for (const entry of entries) {
|
|
2704
|
-
const sourcePath =
|
|
2845
|
+
const sourcePath = resolve5(sourceDir, entry);
|
|
2705
2846
|
const entryStat = statSync(sourcePath);
|
|
2706
2847
|
if (entryStat.isDirectory()) {
|
|
2707
|
-
const subTargetDir =
|
|
2848
|
+
const subTargetDir = resolve5(targetDir, entry);
|
|
2708
2849
|
const subPrefix = manifestKeyPrefix === "" ? entry : `${manifestKeyPrefix}/${entry}`;
|
|
2709
2850
|
const subStats = syncDirectory(
|
|
2710
2851
|
sourcePath,
|
|
@@ -2733,13 +2874,13 @@ function syncDirectory(sourceDir, targetDir, framework, manifest, manifestKeyPre
|
|
|
2733
2874
|
const suffix = choice.kind === "hit" ? choice.suffix : "";
|
|
2734
2875
|
sourceFilename = suffix === "" ? `${baseName}.md` : `${baseName}${suffix}.md`;
|
|
2735
2876
|
}
|
|
2736
|
-
const resolvedSourcePath =
|
|
2737
|
-
if (!
|
|
2877
|
+
const resolvedSourcePath = resolve5(sourceDir, sourceFilename);
|
|
2878
|
+
if (!existsSync6(resolvedSourcePath)) {
|
|
2738
2879
|
continue;
|
|
2739
2880
|
}
|
|
2740
2881
|
const targetFilename = topLevel ? `${baseName}.md` : entry;
|
|
2741
|
-
const targetPath =
|
|
2742
|
-
const rawContent =
|
|
2882
|
+
const targetPath = resolve5(targetDir, targetFilename);
|
|
2883
|
+
const rawContent = readFileSync5(resolvedSourcePath, "utf-8");
|
|
2743
2884
|
let sourceContent;
|
|
2744
2885
|
try {
|
|
2745
2886
|
sourceContent = renderTemplate(rawContent, templateVars);
|
|
@@ -2757,8 +2898,8 @@ function syncDirectory(sourceDir, targetDir, framework, manifest, manifestKeyPre
|
|
|
2757
2898
|
const sourceHash = hashContent(sourceContent);
|
|
2758
2899
|
const manifestKey = manifestKeyPrefix === "" ? targetFilename : `${manifestKeyPrefix}/${targetFilename}`;
|
|
2759
2900
|
const lastInstalledHash = manifest.entries[manifestKey];
|
|
2760
|
-
if (
|
|
2761
|
-
const existingContent =
|
|
2901
|
+
if (existsSync6(targetPath)) {
|
|
2902
|
+
const existingContent = readFileSync5(targetPath, "utf-8");
|
|
2762
2903
|
const existingHash = hashContent(existingContent);
|
|
2763
2904
|
if (existingHash === sourceHash) {
|
|
2764
2905
|
manifest.entries[manifestKey] = sourceHash;
|
|
@@ -2817,10 +2958,10 @@ function buildTemplateVars() {
|
|
|
2817
2958
|
}
|
|
2818
2959
|
function installCommands(projectRoot, opts = {}) {
|
|
2819
2960
|
const claudeDirName = getConfig().conventions?.claudeDirName ?? ".claude";
|
|
2820
|
-
const claudeDir =
|
|
2821
|
-
const targetDir =
|
|
2822
|
-
if (!
|
|
2823
|
-
|
|
2961
|
+
const claudeDir = resolve5(projectRoot, claudeDirName);
|
|
2962
|
+
const targetDir = resolve5(claudeDir, "commands");
|
|
2963
|
+
if (!existsSync6(targetDir)) {
|
|
2964
|
+
mkdirSync4(targetDir, { recursive: true });
|
|
2824
2965
|
}
|
|
2825
2966
|
const sourceDir = resolveAssetDir("commands");
|
|
2826
2967
|
if (!sourceDir) {
|
|
@@ -2849,7 +2990,7 @@ function installCommands(projectRoot, opts = {}) {
|
|
|
2849
2990
|
}
|
|
2850
2991
|
function installAll(projectRoot, opts = {}) {
|
|
2851
2992
|
const claudeDirName = getConfig().conventions?.claudeDirName ?? ".claude";
|
|
2852
|
-
const claudeDir =
|
|
2993
|
+
const claudeDir = resolve5(projectRoot, claudeDirName);
|
|
2853
2994
|
const assets = {};
|
|
2854
2995
|
let totalInstalled = 0;
|
|
2855
2996
|
let totalUpdated = 0;
|
|
@@ -2862,7 +3003,7 @@ function installAll(projectRoot, opts = {}) {
|
|
|
2862
3003
|
for (const assetType of ASSET_TYPES) {
|
|
2863
3004
|
const sourceDir = resolveAssetDir(assetType.name);
|
|
2864
3005
|
if (!sourceDir) continue;
|
|
2865
|
-
const targetDir =
|
|
3006
|
+
const targetDir = resolve5(claudeDir, assetType.targetSubdir);
|
|
2866
3007
|
const stats = syncDirectory(
|
|
2867
3008
|
sourceDir,
|
|
2868
3009
|
targetDir,
|
|
@@ -3166,17 +3307,17 @@ var init_manifest_registry = __esm({
|
|
|
3166
3307
|
});
|
|
3167
3308
|
|
|
3168
3309
|
// src/detect/package-detector.ts
|
|
3169
|
-
import { readFileSync as
|
|
3310
|
+
import { readFileSync as readFileSync6, existsSync as existsSync7, statSync as statSync2, lstatSync, readdirSync as readdirSync3 } from "fs";
|
|
3170
3311
|
import { join as join4, relative as relative2 } from "path";
|
|
3171
3312
|
import { parse as parseToml } from "smol-toml";
|
|
3172
3313
|
function safeRead(path) {
|
|
3173
3314
|
try {
|
|
3174
|
-
if (!
|
|
3315
|
+
if (!existsSync7(path)) return null;
|
|
3175
3316
|
const ls = lstatSync(path);
|
|
3176
3317
|
if (ls.isSymbolicLink()) return null;
|
|
3177
3318
|
const st = statSync2(path);
|
|
3178
3319
|
if (!st.isFile()) return null;
|
|
3179
|
-
return
|
|
3320
|
+
return readFileSync6(path, "utf-8");
|
|
3180
3321
|
} catch {
|
|
3181
3322
|
return null;
|
|
3182
3323
|
}
|
|
@@ -3207,7 +3348,7 @@ function parsePackageJson(path, directory, root, warnings) {
|
|
|
3207
3348
|
const peer = Object.keys(
|
|
3208
3349
|
pkg.peerDependencies ?? {}
|
|
3209
3350
|
);
|
|
3210
|
-
const hasTs = deps.includes("typescript") || devDeps.includes("typescript") ||
|
|
3351
|
+
const hasTs = deps.includes("typescript") || devDeps.includes("typescript") || existsSync7(join4(directory, "tsconfig.json"));
|
|
3211
3352
|
const language = hasTs ? "typescript" : "javascript";
|
|
3212
3353
|
const scripts = Object.keys(
|
|
3213
3354
|
pkg.scripts ?? {}
|
|
@@ -3634,7 +3775,7 @@ function detectManifestsInDir(dir, root, warnings) {
|
|
|
3634
3775
|
for (const entry of getManifestRegistry2()) {
|
|
3635
3776
|
if (!entry.pattern.startsWith("*")) {
|
|
3636
3777
|
const path = join4(dir, entry.pattern);
|
|
3637
|
-
if (!
|
|
3778
|
+
if (!existsSync7(path)) continue;
|
|
3638
3779
|
const m3 = entry.parse(path, dir, root, warnings);
|
|
3639
3780
|
if (m3 !== null) out.push(m3);
|
|
3640
3781
|
} else {
|
|
@@ -3648,7 +3789,7 @@ function detectManifestsInDir(dir, root, warnings) {
|
|
|
3648
3789
|
for (const fname of dirEntries) {
|
|
3649
3790
|
if (!matchManifestPattern2(fname, entry.pattern)) continue;
|
|
3650
3791
|
const path = join4(dir, fname);
|
|
3651
|
-
if (!
|
|
3792
|
+
if (!existsSync7(path)) continue;
|
|
3652
3793
|
const m3 = entry.parse(path, dir, root, warnings);
|
|
3653
3794
|
if (m3 !== null) out.push(m3);
|
|
3654
3795
|
}
|
|
@@ -3669,7 +3810,7 @@ function detectPackageManifests(projectRoot) {
|
|
|
3669
3810
|
manifests.push(...detectManifestsInDir(projectRoot, projectRoot, warnings));
|
|
3670
3811
|
for (const ws of WORKSPACE_DIRS) {
|
|
3671
3812
|
const wsRoot = join4(projectRoot, ws);
|
|
3672
|
-
if (!
|
|
3813
|
+
if (!existsSync7(wsRoot)) continue;
|
|
3673
3814
|
for (const sub of listSubdirs(wsRoot)) {
|
|
3674
3815
|
manifests.push(...detectManifestsInDir(sub, projectRoot, warnings));
|
|
3675
3816
|
for (const sub2 of listSubdirs(sub)) {
|
|
@@ -8440,41 +8581,41 @@ var require_queue = __commonJS({
|
|
|
8440
8581
|
queue.drained = drained;
|
|
8441
8582
|
return queue;
|
|
8442
8583
|
function push(value) {
|
|
8443
|
-
var p19 = new Promise(function(
|
|
8584
|
+
var p19 = new Promise(function(resolve42, reject) {
|
|
8444
8585
|
pushCb(value, function(err, result) {
|
|
8445
8586
|
if (err) {
|
|
8446
8587
|
reject(err);
|
|
8447
8588
|
return;
|
|
8448
8589
|
}
|
|
8449
|
-
|
|
8590
|
+
resolve42(result);
|
|
8450
8591
|
});
|
|
8451
8592
|
});
|
|
8452
8593
|
p19.catch(noop);
|
|
8453
8594
|
return p19;
|
|
8454
8595
|
}
|
|
8455
8596
|
function unshift(value) {
|
|
8456
|
-
var p19 = new Promise(function(
|
|
8597
|
+
var p19 = new Promise(function(resolve42, reject) {
|
|
8457
8598
|
unshiftCb(value, function(err, result) {
|
|
8458
8599
|
if (err) {
|
|
8459
8600
|
reject(err);
|
|
8460
8601
|
return;
|
|
8461
8602
|
}
|
|
8462
|
-
|
|
8603
|
+
resolve42(result);
|
|
8463
8604
|
});
|
|
8464
8605
|
});
|
|
8465
8606
|
p19.catch(noop);
|
|
8466
8607
|
return p19;
|
|
8467
8608
|
}
|
|
8468
8609
|
function drained() {
|
|
8469
|
-
var p19 = new Promise(function(
|
|
8610
|
+
var p19 = new Promise(function(resolve42) {
|
|
8470
8611
|
process.nextTick(function() {
|
|
8471
8612
|
if (queue.idle()) {
|
|
8472
|
-
|
|
8613
|
+
resolve42();
|
|
8473
8614
|
} else {
|
|
8474
8615
|
var previousDrain = queue.drain;
|
|
8475
8616
|
queue.drain = function() {
|
|
8476
8617
|
if (typeof previousDrain === "function") previousDrain();
|
|
8477
|
-
|
|
8618
|
+
resolve42();
|
|
8478
8619
|
queue.drain = previousDrain;
|
|
8479
8620
|
};
|
|
8480
8621
|
}
|
|
@@ -8960,9 +9101,9 @@ var require_stream3 = __commonJS({
|
|
|
8960
9101
|
});
|
|
8961
9102
|
}
|
|
8962
9103
|
_getStat(filepath) {
|
|
8963
|
-
return new Promise((
|
|
9104
|
+
return new Promise((resolve42, reject) => {
|
|
8964
9105
|
this._stat(filepath, this._fsStatSettings, (error, stats) => {
|
|
8965
|
-
return error === null ?
|
|
9106
|
+
return error === null ? resolve42(stats) : reject(error);
|
|
8966
9107
|
});
|
|
8967
9108
|
});
|
|
8968
9109
|
}
|
|
@@ -8986,10 +9127,10 @@ var require_async5 = __commonJS({
|
|
|
8986
9127
|
this._readerStream = new stream_1.default(this._settings);
|
|
8987
9128
|
}
|
|
8988
9129
|
dynamic(root, options) {
|
|
8989
|
-
return new Promise((
|
|
9130
|
+
return new Promise((resolve42, reject) => {
|
|
8990
9131
|
this._walkAsync(root, options, (error, entries) => {
|
|
8991
9132
|
if (error === null) {
|
|
8992
|
-
|
|
9133
|
+
resolve42(entries);
|
|
8993
9134
|
} else {
|
|
8994
9135
|
reject(error);
|
|
8995
9136
|
}
|
|
@@ -8999,10 +9140,10 @@ var require_async5 = __commonJS({
|
|
|
8999
9140
|
async static(patterns, options) {
|
|
9000
9141
|
const entries = [];
|
|
9001
9142
|
const stream = this._readerStream.static(patterns, options);
|
|
9002
|
-
return new Promise((
|
|
9143
|
+
return new Promise((resolve42, reject) => {
|
|
9003
9144
|
stream.once("error", reject);
|
|
9004
9145
|
stream.on("data", (entry) => entries.push(entry));
|
|
9005
|
-
stream.once("end", () =>
|
|
9146
|
+
stream.once("end", () => resolve42(entries));
|
|
9006
9147
|
});
|
|
9007
9148
|
}
|
|
9008
9149
|
};
|
|
@@ -9661,7 +9802,7 @@ var require_out4 = __commonJS({
|
|
|
9661
9802
|
|
|
9662
9803
|
// src/detect/source-dir-detector.ts
|
|
9663
9804
|
import { realpathSync } from "fs";
|
|
9664
|
-
import { resolve as
|
|
9805
|
+
import { resolve as resolve6 } from "path";
|
|
9665
9806
|
function extsFor(language) {
|
|
9666
9807
|
return EXTENSIONS[language] ?? [];
|
|
9667
9808
|
}
|
|
@@ -9687,7 +9828,7 @@ function topSegment(rel) {
|
|
|
9687
9828
|
function isInsideRoot(root, candidate) {
|
|
9688
9829
|
try {
|
|
9689
9830
|
const realRoot = realpathSync(root);
|
|
9690
|
-
const realCand = realpathSync(
|
|
9831
|
+
const realCand = realpathSync(resolve6(root, candidate));
|
|
9691
9832
|
return realCand === realRoot || realCand.startsWith(realRoot + "/");
|
|
9692
9833
|
} catch {
|
|
9693
9834
|
return false;
|
|
@@ -9855,25 +9996,25 @@ var init_source_dir_detector = __esm({
|
|
|
9855
9996
|
});
|
|
9856
9997
|
|
|
9857
9998
|
// src/detect/monorepo-detector.ts
|
|
9858
|
-
import { readFileSync as
|
|
9999
|
+
import { readFileSync as readFileSync7, existsSync as existsSync8, statSync as statSync3, lstatSync as lstatSync2, readdirSync as readdirSync4 } from "fs";
|
|
9859
10000
|
import { join as join5, relative as relative3 } from "path";
|
|
9860
10001
|
import { parse as parseYaml3 } from "yaml";
|
|
9861
10002
|
import { parse as parseToml2 } from "smol-toml";
|
|
9862
10003
|
function safeReadText(path) {
|
|
9863
10004
|
try {
|
|
9864
|
-
if (!
|
|
10005
|
+
if (!existsSync8(path)) return null;
|
|
9865
10006
|
const ls = lstatSync2(path);
|
|
9866
10007
|
if (ls.isSymbolicLink()) return null;
|
|
9867
10008
|
const st = statSync3(path);
|
|
9868
10009
|
if (!st.isFile()) return null;
|
|
9869
|
-
return
|
|
10010
|
+
return readFileSync7(path, "utf-8");
|
|
9870
10011
|
} catch {
|
|
9871
10012
|
return null;
|
|
9872
10013
|
}
|
|
9873
10014
|
}
|
|
9874
10015
|
function firstManifestIn(dir) {
|
|
9875
10016
|
for (const m3 of MANIFEST_PRIORITY) {
|
|
9876
|
-
if (
|
|
10017
|
+
if (existsSync8(join5(dir, m3))) return m3;
|
|
9877
10018
|
}
|
|
9878
10019
|
return null;
|
|
9879
10020
|
}
|
|
@@ -9938,7 +10079,7 @@ function genericWorkspaces(root) {
|
|
|
9938
10079
|
const out = [];
|
|
9939
10080
|
for (const parent of CONVENTIONAL_WORKSPACE_PARENTS) {
|
|
9940
10081
|
const p19 = join5(root, parent);
|
|
9941
|
-
if (!
|
|
10082
|
+
if (!existsSync8(p19)) continue;
|
|
9942
10083
|
for (const sub of listSubdirs2(p19)) {
|
|
9943
10084
|
const pkg = pkgFromDir(root, sub);
|
|
9944
10085
|
if (pkg) out.push(pkg);
|
|
@@ -9979,7 +10120,7 @@ function expandWorkspaceGlobs(root, globs) {
|
|
|
9979
10120
|
const parts = pattern.split("/");
|
|
9980
10121
|
if (parts.length === 2 && (parts[1] === "*" || parts[1] === "**")) {
|
|
9981
10122
|
const parent = join5(root, parts[0]);
|
|
9982
|
-
if (!
|
|
10123
|
+
if (!existsSync8(parent)) continue;
|
|
9983
10124
|
for (const sub of listSubdirs2(parent)) {
|
|
9984
10125
|
const pkg = pkgFromDir(root, sub);
|
|
9985
10126
|
if (pkg && !seen.has(pkg.path)) {
|
|
@@ -9990,7 +10131,7 @@ function expandWorkspaceGlobs(root, globs) {
|
|
|
9990
10131
|
continue;
|
|
9991
10132
|
}
|
|
9992
10133
|
const direct = join5(root, pattern);
|
|
9993
|
-
if (
|
|
10134
|
+
if (existsSync8(direct)) {
|
|
9994
10135
|
const pkg = pkgFromDir(root, direct);
|
|
9995
10136
|
if (pkg && !seen.has(pkg.path)) {
|
|
9996
10137
|
seen.add(pkg.path);
|
|
@@ -10001,16 +10142,16 @@ function expandWorkspaceGlobs(root, globs) {
|
|
|
10001
10142
|
return out;
|
|
10002
10143
|
}
|
|
10003
10144
|
function hasTurbo(root) {
|
|
10004
|
-
return
|
|
10145
|
+
return existsSync8(join5(root, "turbo.json"));
|
|
10005
10146
|
}
|
|
10006
10147
|
function hasNx(root) {
|
|
10007
|
-
return
|
|
10148
|
+
return existsSync8(join5(root, "nx.json"));
|
|
10008
10149
|
}
|
|
10009
10150
|
function hasLerna(root) {
|
|
10010
|
-
return
|
|
10151
|
+
return existsSync8(join5(root, "lerna.json"));
|
|
10011
10152
|
}
|
|
10012
10153
|
function hasBazel(root) {
|
|
10013
|
-
return
|
|
10154
|
+
return existsSync8(join5(root, "WORKSPACE")) || existsSync8(join5(root, "WORKSPACE.bazel")) || existsSync8(join5(root, "MODULE.bazel"));
|
|
10014
10155
|
}
|
|
10015
10156
|
function detectMonorepo(projectRoot) {
|
|
10016
10157
|
const nested = [];
|
|
@@ -10201,7 +10342,7 @@ var init_vr_command_map = __esm({
|
|
|
10201
10342
|
});
|
|
10202
10343
|
|
|
10203
10344
|
// src/detect/domain-inferrer.ts
|
|
10204
|
-
import { existsSync as
|
|
10345
|
+
import { existsSync as existsSync9, readdirSync as readdirSync5 } from "fs";
|
|
10205
10346
|
import { join as join6 } from "path";
|
|
10206
10347
|
function titleCase(s) {
|
|
10207
10348
|
if (!s) return s;
|
|
@@ -10223,7 +10364,7 @@ function topLevelSrcSubdirs(root, sourceDirs) {
|
|
|
10223
10364
|
const seen = /* @__PURE__ */ new Set();
|
|
10224
10365
|
for (const rel of effective) {
|
|
10225
10366
|
const abs = join6(root, rel);
|
|
10226
|
-
if (!
|
|
10367
|
+
if (!existsSync9(abs)) continue;
|
|
10227
10368
|
try {
|
|
10228
10369
|
for (const e2 of readdirSync5(abs, { withFileTypes: true })) {
|
|
10229
10370
|
if (!e2.isDirectory()) continue;
|
|
@@ -10310,8 +10451,8 @@ var init_domain_inferrer = __esm({
|
|
|
10310
10451
|
});
|
|
10311
10452
|
|
|
10312
10453
|
// src/detect/regex-fallback.ts
|
|
10313
|
-
import { existsSync as
|
|
10314
|
-
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";
|
|
10315
10456
|
function introspectPython(detection, projectRoot) {
|
|
10316
10457
|
const sourceDir = resolveSourceDir(detection, "python", projectRoot);
|
|
10317
10458
|
if (!sourceDir) return null;
|
|
@@ -10477,10 +10618,10 @@ function resolveSourceDir(detection, lang, projectRoot) {
|
|
|
10477
10618
|
const list = info?.source_dirs ?? [];
|
|
10478
10619
|
if (list.length > 0) {
|
|
10479
10620
|
const first = list[0];
|
|
10480
|
-
const abs =
|
|
10481
|
-
return
|
|
10621
|
+
const abs = resolve7(projectRoot, first);
|
|
10622
|
+
return existsSync10(abs) ? abs : null;
|
|
10482
10623
|
}
|
|
10483
|
-
return
|
|
10624
|
+
return existsSync10(projectRoot) ? projectRoot : null;
|
|
10484
10625
|
}
|
|
10485
10626
|
function sampleFiles(dir, nameRegex, pathFilter) {
|
|
10486
10627
|
const out = [];
|
|
@@ -10525,7 +10666,7 @@ function readSafe(path) {
|
|
|
10525
10666
|
try {
|
|
10526
10667
|
const st = statSync4(path);
|
|
10527
10668
|
if (st.size > MAX_FILE_BYTES) return null;
|
|
10528
|
-
return
|
|
10669
|
+
return readFileSync8(path, "utf-8");
|
|
10529
10670
|
} catch {
|
|
10530
10671
|
return null;
|
|
10531
10672
|
}
|
|
@@ -10606,7 +10747,7 @@ var init_parse_guard = __esm({
|
|
|
10606
10747
|
|
|
10607
10748
|
// src/detect/adapters/runner.ts
|
|
10608
10749
|
import { basename as basename3, relative as relative4 } from "path";
|
|
10609
|
-
import { existsSync as
|
|
10750
|
+
import { existsSync as existsSync11, readdirSync as readdirSync7, readFileSync as readFileSync9, statSync as statSync5 } from "fs";
|
|
10610
10751
|
import { join as join8 } from "path";
|
|
10611
10752
|
async function runAdapters(adapters, rootDir, signals, options = {}) {
|
|
10612
10753
|
const out = {
|
|
@@ -10741,9 +10882,9 @@ function tryReadGradleBuild(rootDir, presentFiles) {
|
|
|
10741
10882
|
return void 0;
|
|
10742
10883
|
}
|
|
10743
10884
|
function tryReadString(path) {
|
|
10744
|
-
if (!
|
|
10885
|
+
if (!existsSync11(path)) return void 0;
|
|
10745
10886
|
try {
|
|
10746
|
-
return
|
|
10887
|
+
return readFileSync9(path, "utf-8");
|
|
10747
10888
|
} catch {
|
|
10748
10889
|
return void 0;
|
|
10749
10890
|
}
|
|
@@ -10860,21 +11001,21 @@ ${querySource}`
|
|
|
10860
11001
|
// src/detect/adapters/tree-sitter-loader.ts
|
|
10861
11002
|
import { createHash as createHash3 } from "crypto";
|
|
10862
11003
|
import {
|
|
10863
|
-
mkdirSync as
|
|
11004
|
+
mkdirSync as mkdirSync5,
|
|
10864
11005
|
readdirSync as readdirSync8,
|
|
10865
|
-
readFileSync as
|
|
10866
|
-
writeFileSync,
|
|
11006
|
+
readFileSync as readFileSync10,
|
|
11007
|
+
writeFileSync as writeFileSync2,
|
|
10867
11008
|
renameSync as renameSync2,
|
|
10868
11009
|
unlinkSync,
|
|
10869
11010
|
lstatSync as lstatSync3,
|
|
10870
|
-
chmodSync,
|
|
11011
|
+
chmodSync as chmodSync2,
|
|
10871
11012
|
utimesSync
|
|
10872
11013
|
} from "fs";
|
|
10873
|
-
import { homedir as
|
|
11014
|
+
import { homedir as homedir4 } from "os";
|
|
10874
11015
|
import { dirname as dirname5, join as join9 } from "path";
|
|
10875
11016
|
import { Language, Parser } from "web-tree-sitter";
|
|
10876
11017
|
function getCacheDir() {
|
|
10877
|
-
return process.env.MASSU_WASM_CACHE_DIR ?? join9(
|
|
11018
|
+
return process.env.MASSU_WASM_CACHE_DIR ?? join9(homedir4(), ".massu", "wasm-cache");
|
|
10878
11019
|
}
|
|
10879
11020
|
function getCachedPath(language, sha) {
|
|
10880
11021
|
return join9(getCacheDir(), `${language}-${sha}.wasm`);
|
|
@@ -10962,7 +11103,7 @@ async function loadGrammar(language, options = {}) {
|
|
|
10962
11103
|
}
|
|
10963
11104
|
let bytes;
|
|
10964
11105
|
try {
|
|
10965
|
-
bytes =
|
|
11106
|
+
bytes = readFileSync10(cachePath);
|
|
10966
11107
|
} catch (e2) {
|
|
10967
11108
|
bytes = new Uint8Array(0);
|
|
10968
11109
|
}
|
|
@@ -11002,21 +11143,21 @@ async function loadGrammar(language, options = {}) {
|
|
|
11002
11143
|
throw new GrammarSHAMismatchError(language, manifest.sha256, downloadedSha);
|
|
11003
11144
|
}
|
|
11004
11145
|
try {
|
|
11005
|
-
|
|
11146
|
+
mkdirSync5(dirname5(cachePath), { recursive: true, mode: 448 });
|
|
11006
11147
|
try {
|
|
11007
|
-
|
|
11148
|
+
chmodSync2(dirname5(cachePath), 448);
|
|
11008
11149
|
} catch {
|
|
11009
11150
|
}
|
|
11010
11151
|
const tmpPath = `${cachePath}.tmp.${process.pid}`;
|
|
11011
|
-
|
|
11152
|
+
writeFileSync2(tmpPath, body, { mode: 384 });
|
|
11012
11153
|
try {
|
|
11013
|
-
|
|
11154
|
+
chmodSync2(tmpPath, 384);
|
|
11014
11155
|
} catch {
|
|
11015
11156
|
}
|
|
11016
11157
|
try {
|
|
11017
11158
|
renameSync2(tmpPath, cachePath);
|
|
11018
11159
|
try {
|
|
11019
|
-
|
|
11160
|
+
chmodSync2(cachePath, 384);
|
|
11020
11161
|
} catch {
|
|
11021
11162
|
}
|
|
11022
11163
|
} catch (e2) {
|
|
@@ -11880,7 +12021,7 @@ __export(file_sampler_exports, {
|
|
|
11880
12021
|
SAMPLE_TEST_FILE_PATTERNS: () => SAMPLE_TEST_FILE_PATTERNS,
|
|
11881
12022
|
sampleFilesForAdapter: () => sampleFilesForAdapter
|
|
11882
12023
|
});
|
|
11883
|
-
import { readdirSync as readdirSync9, readFileSync as
|
|
12024
|
+
import { readdirSync as readdirSync9, readFileSync as readFileSync11, lstatSync as lstatSync4 } from "node:fs";
|
|
11884
12025
|
import { join as join10, extname } from "node:path";
|
|
11885
12026
|
function sampleFilesForAdapter(adapter, projectRoot, detection, options = {}) {
|
|
11886
12027
|
const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
|
|
@@ -11941,7 +12082,7 @@ function walkDir(dir, exts, testPatterns, lang, maxDepth, curDepth, out, seen, m
|
|
|
11941
12082
|
seen.add(fullPath);
|
|
11942
12083
|
let content;
|
|
11943
12084
|
try {
|
|
11944
|
-
content =
|
|
12085
|
+
content = readFileSync11(fullPath, "utf-8");
|
|
11945
12086
|
} catch {
|
|
11946
12087
|
continue;
|
|
11947
12088
|
}
|
|
@@ -13365,10 +13506,10 @@ __export(init_exports, {
|
|
|
13365
13506
|
validateWrittenConfig: () => validateWrittenConfig,
|
|
13366
13507
|
writeConfigAtomic: () => writeConfigAtomic
|
|
13367
13508
|
});
|
|
13368
|
-
import { closeSync as closeSync2, existsSync as
|
|
13369
|
-
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";
|
|
13370
13511
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
13371
|
-
import { homedir as
|
|
13512
|
+
import { homedir as homedir5 } from "os";
|
|
13372
13513
|
import { stringify as yamlStringify, parse as yamlParse } from "yaml";
|
|
13373
13514
|
function detectFramework(projectRoot) {
|
|
13374
13515
|
const result = {
|
|
@@ -13377,10 +13518,10 @@ function detectFramework(projectRoot) {
|
|
|
13377
13518
|
orm: "none",
|
|
13378
13519
|
ui: "none"
|
|
13379
13520
|
};
|
|
13380
|
-
const pkgPath =
|
|
13381
|
-
if (!
|
|
13521
|
+
const pkgPath = resolve8(projectRoot, "package.json");
|
|
13522
|
+
if (!existsSync12(pkgPath)) return result;
|
|
13382
13523
|
try {
|
|
13383
|
-
const pkg = JSON.parse(
|
|
13524
|
+
const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
13384
13525
|
const allDeps = {
|
|
13385
13526
|
...pkg.dependencies,
|
|
13386
13527
|
...pkg.devDependencies
|
|
@@ -13414,7 +13555,7 @@ function detectPython(projectRoot) {
|
|
|
13414
13555
|
alembicDir: null
|
|
13415
13556
|
};
|
|
13416
13557
|
const markers = ["pyproject.toml", "setup.py", "requirements.txt", "Pipfile"];
|
|
13417
|
-
const hasMarker = markers.some((m3) =>
|
|
13558
|
+
const hasMarker = markers.some((m3) => existsSync12(resolve8(projectRoot, m3)));
|
|
13418
13559
|
if (!hasMarker) return result;
|
|
13419
13560
|
result.detected = true;
|
|
13420
13561
|
const depFiles = [
|
|
@@ -13424,33 +13565,33 @@ function detectPython(projectRoot) {
|
|
|
13424
13565
|
{ file: "Pipfile" }
|
|
13425
13566
|
];
|
|
13426
13567
|
for (const { file } of depFiles) {
|
|
13427
|
-
const filePath =
|
|
13428
|
-
if (
|
|
13568
|
+
const filePath = resolve8(projectRoot, file);
|
|
13569
|
+
if (existsSync12(filePath)) {
|
|
13429
13570
|
try {
|
|
13430
|
-
const content =
|
|
13571
|
+
const content = readFileSync12(filePath, "utf-8").toLowerCase();
|
|
13431
13572
|
if (content.includes("fastapi")) result.hasFastapi = true;
|
|
13432
13573
|
if (content.includes("sqlalchemy")) result.hasSqlalchemy = true;
|
|
13433
13574
|
} catch {
|
|
13434
13575
|
}
|
|
13435
13576
|
}
|
|
13436
13577
|
}
|
|
13437
|
-
if (
|
|
13578
|
+
if (existsSync12(resolve8(projectRoot, "alembic.ini"))) {
|
|
13438
13579
|
result.hasAlembic = true;
|
|
13439
|
-
if (
|
|
13580
|
+
if (existsSync12(resolve8(projectRoot, "alembic"))) {
|
|
13440
13581
|
result.alembicDir = "alembic";
|
|
13441
13582
|
}
|
|
13442
|
-
} else if (
|
|
13583
|
+
} else if (existsSync12(resolve8(projectRoot, "alembic"))) {
|
|
13443
13584
|
result.hasAlembic = true;
|
|
13444
13585
|
result.alembicDir = "alembic";
|
|
13445
13586
|
}
|
|
13446
13587
|
const candidateRoots = ["app", "src", "backend", "api"];
|
|
13447
13588
|
for (const candidate of candidateRoots) {
|
|
13448
|
-
const candidatePath =
|
|
13449
|
-
if (
|
|
13589
|
+
const candidatePath = resolve8(projectRoot, candidate);
|
|
13590
|
+
if (existsSync12(candidatePath) && existsSync12(resolve8(candidatePath, "__init__.py"))) {
|
|
13450
13591
|
result.root = candidate;
|
|
13451
13592
|
break;
|
|
13452
13593
|
}
|
|
13453
|
-
if (
|
|
13594
|
+
if (existsSync12(candidatePath)) {
|
|
13454
13595
|
try {
|
|
13455
13596
|
const files = readdirSync10(candidatePath);
|
|
13456
13597
|
if (files.some((f2) => f2.endsWith(".py"))) {
|
|
@@ -13470,8 +13611,8 @@ function generateConfig(projectRoot, framework) {
|
|
|
13470
13611
|
console.warn(
|
|
13471
13612
|
"[@massu/core] generateConfig() is deprecated since 1.2.1 \u2014 use buildConfigFromDetection instead. It cannot produce valid configs for monorepos."
|
|
13472
13613
|
);
|
|
13473
|
-
const configPath =
|
|
13474
|
-
if (
|
|
13614
|
+
const configPath = resolve8(projectRoot, "massu.config.yaml");
|
|
13615
|
+
if (existsSync12(configPath)) {
|
|
13475
13616
|
return false;
|
|
13476
13617
|
}
|
|
13477
13618
|
const projectName = basename4(projectRoot);
|
|
@@ -13517,7 +13658,7 @@ function generateConfig(projectRoot, framework) {
|
|
|
13517
13658
|
# Documentation: https://massu.ai/docs/getting-started/configuration
|
|
13518
13659
|
|
|
13519
13660
|
${yamlStringify(config)}`;
|
|
13520
|
-
|
|
13661
|
+
writeFileSync3(configPath, yamlContent, "utf-8");
|
|
13521
13662
|
return true;
|
|
13522
13663
|
}
|
|
13523
13664
|
function monorepoCommonRoot(packages) {
|
|
@@ -13582,10 +13723,10 @@ function buildConfigFromDetection(opts) {
|
|
|
13582
13723
|
pathsSource = monorepoCommonRoot(detection.monorepo.packages);
|
|
13583
13724
|
}
|
|
13584
13725
|
}
|
|
13585
|
-
if (pathsSource === "src" && !
|
|
13726
|
+
if (pathsSource === "src" && !existsSync12(resolve8(projectRoot, "src"))) {
|
|
13586
13727
|
const fallbacks = ["app", "pages", "."];
|
|
13587
13728
|
for (const fallback of fallbacks) {
|
|
13588
|
-
if (fallback === "." ||
|
|
13729
|
+
if (fallback === "." || existsSync12(resolve8(projectRoot, fallback))) {
|
|
13589
13730
|
pathsSource = fallback;
|
|
13590
13731
|
break;
|
|
13591
13732
|
}
|
|
@@ -13669,7 +13810,7 @@ function buildConfigFromDetection(opts) {
|
|
|
13669
13810
|
};
|
|
13670
13811
|
if (pyFw?.framework) pythonBlock.framework = pyFw.framework;
|
|
13671
13812
|
if (pyFw?.orm) pythonBlock.orm = pyFw.orm;
|
|
13672
|
-
if (
|
|
13813
|
+
if (existsSync12(resolve8(projectRoot, "alembic.ini")) || existsSync12(resolve8(projectRoot, "alembic"))) {
|
|
13673
13814
|
pythonBlock.alembic_dir = "alembic";
|
|
13674
13815
|
}
|
|
13675
13816
|
config.python = pythonBlock;
|
|
@@ -13693,11 +13834,11 @@ function applyVariantTemplate(config, templatesDir) {
|
|
|
13693
13834
|
}
|
|
13694
13835
|
}
|
|
13695
13836
|
if (templateId === null) return config;
|
|
13696
|
-
const templatePath =
|
|
13697
|
-
if (!
|
|
13837
|
+
const templatePath = resolve8(templatesDir, templateId, "massu.config.yaml");
|
|
13838
|
+
if (!existsSync12(templatePath)) return config;
|
|
13698
13839
|
let template;
|
|
13699
13840
|
try {
|
|
13700
|
-
template = yamlParse(
|
|
13841
|
+
template = yamlParse(readFileSync12(templatePath, "utf-8"));
|
|
13701
13842
|
} catch {
|
|
13702
13843
|
return config;
|
|
13703
13844
|
}
|
|
@@ -13756,7 +13897,7 @@ ${yamlStringify(config)}`;
|
|
|
13756
13897
|
function writeConfigAtomic(configPath, content) {
|
|
13757
13898
|
const tmpPath = `${configPath}.tmp`;
|
|
13758
13899
|
let existingMode;
|
|
13759
|
-
if (
|
|
13900
|
+
if (existsSync12(configPath)) {
|
|
13760
13901
|
try {
|
|
13761
13902
|
existingMode = statSync7(configPath).mode;
|
|
13762
13903
|
} catch {
|
|
@@ -13764,7 +13905,7 @@ function writeConfigAtomic(configPath, content) {
|
|
|
13764
13905
|
}
|
|
13765
13906
|
}
|
|
13766
13907
|
try {
|
|
13767
|
-
|
|
13908
|
+
mkdirSync6(dirname6(configPath), { recursive: true });
|
|
13768
13909
|
const fd = openSync2(tmpPath, "w", 420);
|
|
13769
13910
|
try {
|
|
13770
13911
|
const buf = Buffer.from(content, "utf-8");
|
|
@@ -13780,15 +13921,15 @@ function writeConfigAtomic(configPath, content) {
|
|
|
13780
13921
|
renameSync3(tmpPath, configPath);
|
|
13781
13922
|
if (existingMode !== void 0) {
|
|
13782
13923
|
try {
|
|
13783
|
-
|
|
13924
|
+
chmodSync3(configPath, existingMode);
|
|
13784
13925
|
} catch {
|
|
13785
13926
|
}
|
|
13786
13927
|
}
|
|
13787
13928
|
return { validated: true };
|
|
13788
13929
|
} catch (err) {
|
|
13789
|
-
if (
|
|
13930
|
+
if (existsSync12(tmpPath)) {
|
|
13790
13931
|
try {
|
|
13791
|
-
|
|
13932
|
+
rmSync3(tmpPath, { force: true });
|
|
13792
13933
|
} catch {
|
|
13793
13934
|
}
|
|
13794
13935
|
}
|
|
@@ -13797,8 +13938,8 @@ function writeConfigAtomic(configPath, content) {
|
|
|
13797
13938
|
}
|
|
13798
13939
|
function validateWrittenConfig(configPath, projectRoot, checkPaths = true) {
|
|
13799
13940
|
try {
|
|
13800
|
-
if (!
|
|
13801
|
-
const content =
|
|
13941
|
+
if (!existsSync12(configPath)) return "Config file does not exist after write";
|
|
13942
|
+
const content = readFileSync12(configPath, "utf-8");
|
|
13802
13943
|
const parsed = yamlParse(content);
|
|
13803
13944
|
if (parsed === null || typeof parsed !== "object") {
|
|
13804
13945
|
return "Config is not a valid YAML object";
|
|
@@ -13818,8 +13959,8 @@ function validateWrittenConfig(configPath, projectRoot, checkPaths = true) {
|
|
|
13818
13959
|
if (checkPaths) {
|
|
13819
13960
|
const src = cfg.paths.source;
|
|
13820
13961
|
if (src && src !== ".") {
|
|
13821
|
-
const srcAbs =
|
|
13822
|
-
if (!
|
|
13962
|
+
const srcAbs = resolve8(projectRoot, src);
|
|
13963
|
+
if (!existsSync12(srcAbs)) {
|
|
13823
13964
|
return `paths.source '${src}' does not exist on disk`;
|
|
13824
13965
|
}
|
|
13825
13966
|
}
|
|
@@ -13829,8 +13970,8 @@ function validateWrittenConfig(configPath, projectRoot, checkPaths = true) {
|
|
|
13829
13970
|
if (!Array.isArray(rawDirs)) continue;
|
|
13830
13971
|
for (const d2 of rawDirs) {
|
|
13831
13972
|
if (typeof d2 !== "string" || d2 === ".") continue;
|
|
13832
|
-
const abs =
|
|
13833
|
-
if (!
|
|
13973
|
+
const abs = resolve8(projectRoot, d2);
|
|
13974
|
+
if (!existsSync12(abs)) {
|
|
13834
13975
|
return `framework.languages.${lang}.source_dirs '${d2}' does not exist on disk`;
|
|
13835
13976
|
}
|
|
13836
13977
|
}
|
|
@@ -13839,7 +13980,7 @@ function validateWrittenConfig(configPath, projectRoot, checkPaths = true) {
|
|
|
13839
13980
|
if (Array.isArray(mRoots)) {
|
|
13840
13981
|
for (const r2 of mRoots) {
|
|
13841
13982
|
if (typeof r2 !== "string" || r2 === ".") continue;
|
|
13842
|
-
if (!
|
|
13983
|
+
if (!existsSync12(resolve8(projectRoot, r2))) {
|
|
13843
13984
|
return `paths.monorepo_roots '${r2}' does not exist on disk`;
|
|
13844
13985
|
}
|
|
13845
13986
|
}
|
|
@@ -13871,21 +14012,21 @@ function resolveTemplatesDir() {
|
|
|
13871
14012
|
const cwd = process.cwd();
|
|
13872
14013
|
const candidates = [
|
|
13873
14014
|
// Project-local install: `<project>/node_modules/@massu/core/templates`.
|
|
13874
|
-
|
|
14015
|
+
resolve8(cwd, "node_modules/@massu/core/templates"),
|
|
13875
14016
|
// Bundled cli.js layout: cli.js sits at `<package>/dist/cli.js`, so
|
|
13876
14017
|
// templates live one level up at `<package>/templates`. (Plan 1.5.1
|
|
13877
14018
|
// bug discovery: pre-existing layout assumed `dist/commands/init.js`
|
|
13878
14019
|
// depth which never matched the bundled cli, so resolveTemplatesDir
|
|
13879
14020
|
// returned null in production for both `--template` mode AND the
|
|
13880
14021
|
// applyVariantTemplate path.)
|
|
13881
|
-
|
|
14022
|
+
resolve8(__dirname2, "../templates"),
|
|
13882
14023
|
// Legacy nested layouts retained as fallbacks (in case a future
|
|
13883
14024
|
// build moves cli.js back into a subdirectory).
|
|
13884
|
-
|
|
13885
|
-
|
|
14025
|
+
resolve8(__dirname2, "../../templates"),
|
|
14026
|
+
resolve8(__dirname2, "../../../templates")
|
|
13886
14027
|
];
|
|
13887
14028
|
for (const c2 of candidates) {
|
|
13888
|
-
if (
|
|
14029
|
+
if (existsSync12(c2)) return c2;
|
|
13889
14030
|
}
|
|
13890
14031
|
return null;
|
|
13891
14032
|
}
|
|
@@ -13894,14 +14035,14 @@ function copyTemplateConfig(templateName, targetPath, projectName) {
|
|
|
13894
14035
|
if (!templatesDir) {
|
|
13895
14036
|
return { success: false, error: `Templates directory not found (looked in node_modules and dist/src)` };
|
|
13896
14037
|
}
|
|
13897
|
-
const srcPath =
|
|
13898
|
-
if (!
|
|
14038
|
+
const srcPath = resolve8(templatesDir, templateName, "massu.config.yaml");
|
|
14039
|
+
if (!existsSync12(srcPath)) {
|
|
13899
14040
|
return { success: false, error: `Template '${templateName}' not found at ${srcPath}` };
|
|
13900
14041
|
}
|
|
13901
14042
|
try {
|
|
13902
|
-
let content =
|
|
14043
|
+
let content = readFileSync12(srcPath, "utf-8");
|
|
13903
14044
|
content = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
|
|
13904
|
-
|
|
14045
|
+
writeFileSync3(targetPath, content, "utf-8");
|
|
13905
14046
|
return { success: true };
|
|
13906
14047
|
} catch (err) {
|
|
13907
14048
|
return { success: false, error: err instanceof Error ? err.message : String(err) };
|
|
@@ -13909,13 +14050,13 @@ function copyTemplateConfig(templateName, targetPath, projectName) {
|
|
|
13909
14050
|
}
|
|
13910
14051
|
function getInstallerVersion() {
|
|
13911
14052
|
const candidates = [
|
|
13912
|
-
|
|
13913
|
-
|
|
14053
|
+
resolve8(__dirname2, "../package.json"),
|
|
14054
|
+
resolve8(__dirname2, "../../package.json")
|
|
13914
14055
|
];
|
|
13915
14056
|
for (const candidate of candidates) {
|
|
13916
|
-
if (
|
|
14057
|
+
if (existsSync12(candidate)) {
|
|
13917
14058
|
try {
|
|
13918
|
-
const pkg = JSON.parse(
|
|
14059
|
+
const pkg = JSON.parse(readFileSync12(candidate, "utf-8"));
|
|
13919
14060
|
if (typeof pkg.version === "string" && pkg.version.length > 0 && pkg.name === "@massu/core") {
|
|
13920
14061
|
return pkg.version;
|
|
13921
14062
|
}
|
|
@@ -13928,11 +14069,11 @@ function getInstallerVersion() {
|
|
|
13928
14069
|
);
|
|
13929
14070
|
}
|
|
13930
14071
|
function registerMcpServer(projectRoot) {
|
|
13931
|
-
const mcpPath =
|
|
14072
|
+
const mcpPath = resolve8(projectRoot, ".mcp.json");
|
|
13932
14073
|
let existing = {};
|
|
13933
|
-
if (
|
|
14074
|
+
if (existsSync12(mcpPath)) {
|
|
13934
14075
|
try {
|
|
13935
|
-
existing = JSON.parse(
|
|
14076
|
+
existing = JSON.parse(readFileSync12(mcpPath, "utf-8"));
|
|
13936
14077
|
} catch {
|
|
13937
14078
|
existing = {};
|
|
13938
14079
|
}
|
|
@@ -13948,17 +14089,17 @@ function registerMcpServer(projectRoot) {
|
|
|
13948
14089
|
args: ["-y", `@massu/core@${version}`]
|
|
13949
14090
|
};
|
|
13950
14091
|
existing.mcpServers = servers;
|
|
13951
|
-
|
|
14092
|
+
writeFileSync3(mcpPath, JSON.stringify(existing, null, 2) + "\n", "utf-8");
|
|
13952
14093
|
return true;
|
|
13953
14094
|
}
|
|
13954
14095
|
function resolveHooksDir() {
|
|
13955
14096
|
const cwd = process.cwd();
|
|
13956
|
-
const nodeModulesPath =
|
|
13957
|
-
if (
|
|
14097
|
+
const nodeModulesPath = resolve8(cwd, "node_modules/@massu/core/dist/hooks");
|
|
14098
|
+
if (existsSync12(nodeModulesPath)) {
|
|
13958
14099
|
return "node_modules/@massu/core/dist/hooks";
|
|
13959
14100
|
}
|
|
13960
|
-
const localPath =
|
|
13961
|
-
if (
|
|
14101
|
+
const localPath = resolve8(__dirname2, "../dist/hooks");
|
|
14102
|
+
if (existsSync12(localPath)) {
|
|
13962
14103
|
return localPath;
|
|
13963
14104
|
}
|
|
13964
14105
|
return "node_modules/@massu/core/dist/hooks";
|
|
@@ -14104,9 +14245,9 @@ function installHooks(projectRoot) {
|
|
|
14104
14245
|
} catch {
|
|
14105
14246
|
claudeDirName = ".claude";
|
|
14106
14247
|
}
|
|
14107
|
-
const claudeDir =
|
|
14108
|
-
if (!
|
|
14109
|
-
|
|
14248
|
+
const claudeDir = resolve8(projectRoot, claudeDirName);
|
|
14249
|
+
if (!existsSync12(claudeDir)) {
|
|
14250
|
+
mkdirSync6(claudeDir, { recursive: true });
|
|
14110
14251
|
}
|
|
14111
14252
|
const settings = readSettingsLocal(claudeDir);
|
|
14112
14253
|
const hooksConfig = buildHooksConfig(resolveHooksDir());
|
|
@@ -14124,17 +14265,17 @@ function installHooks(projectRoot) {
|
|
|
14124
14265
|
}
|
|
14125
14266
|
function initMemoryDir(projectRoot) {
|
|
14126
14267
|
const encodedRoot = encodeMemoryDirName(projectRoot);
|
|
14127
|
-
const memoryDir =
|
|
14268
|
+
const memoryDir = resolve8(homedir5(), `.claude/projects/${encodedRoot}/memory`);
|
|
14128
14269
|
let migratedFromLegacy = false;
|
|
14129
|
-
const legacyDir =
|
|
14130
|
-
if (
|
|
14270
|
+
const legacyDir = resolve8(homedir5(), `.claude/projects/-${encodedRoot}/memory`);
|
|
14271
|
+
if (existsSync12(legacyDir) && !existsSync12(memoryDir)) {
|
|
14131
14272
|
try {
|
|
14132
|
-
|
|
14273
|
+
mkdirSync6(resolve8(memoryDir, ".."), { recursive: true });
|
|
14133
14274
|
renameSync3(legacyDir, memoryDir);
|
|
14134
14275
|
try {
|
|
14135
|
-
const legacyParent =
|
|
14136
|
-
if (
|
|
14137
|
-
|
|
14276
|
+
const legacyParent = resolve8(legacyDir, "..");
|
|
14277
|
+
if (existsSync12(legacyParent) && readdirSync10(legacyParent).length === 0) {
|
|
14278
|
+
rmSync3(legacyParent, { recursive: false });
|
|
14138
14279
|
}
|
|
14139
14280
|
} catch {
|
|
14140
14281
|
}
|
|
@@ -14143,13 +14284,13 @@ function initMemoryDir(projectRoot) {
|
|
|
14143
14284
|
}
|
|
14144
14285
|
}
|
|
14145
14286
|
let created = false;
|
|
14146
|
-
if (!
|
|
14147
|
-
|
|
14287
|
+
if (!existsSync12(memoryDir)) {
|
|
14288
|
+
mkdirSync6(memoryDir, { recursive: true });
|
|
14148
14289
|
created = true;
|
|
14149
14290
|
}
|
|
14150
|
-
const memoryMdPath =
|
|
14291
|
+
const memoryMdPath = resolve8(memoryDir, "MEMORY.md");
|
|
14151
14292
|
let memoryMdCreated = false;
|
|
14152
|
-
if (!
|
|
14293
|
+
if (!existsSync12(memoryMdPath)) {
|
|
14153
14294
|
const projectName = basename4(projectRoot);
|
|
14154
14295
|
const memoryContent = `# ${projectName} - Massu Memory
|
|
14155
14296
|
|
|
@@ -14165,7 +14306,7 @@ function initMemoryDir(projectRoot) {
|
|
|
14165
14306
|
## File Index
|
|
14166
14307
|
<!-- Significant files and directories -->
|
|
14167
14308
|
`;
|
|
14168
|
-
|
|
14309
|
+
writeFileSync3(memoryMdPath, memoryContent, "utf-8");
|
|
14169
14310
|
memoryMdCreated = true;
|
|
14170
14311
|
}
|
|
14171
14312
|
return { created, memoryMdCreated, migratedFromLegacy };
|
|
@@ -14263,8 +14404,8 @@ async function runInit(argv, overrides) {
|
|
|
14263
14404
|
log("Massu AI - Project Setup");
|
|
14264
14405
|
log("========================");
|
|
14265
14406
|
log("");
|
|
14266
|
-
const configPath =
|
|
14267
|
-
if (
|
|
14407
|
+
const configPath = resolve8(projectRoot, "massu.config.yaml");
|
|
14408
|
+
if (existsSync12(configPath)) {
|
|
14268
14409
|
if (opts.ci && !opts.force) {
|
|
14269
14410
|
errLog(`error: massu.config.yaml already exists at ${configPath}`);
|
|
14270
14411
|
errLog(" rerun with --force to overwrite, or remove the file first");
|
|
@@ -14292,7 +14433,7 @@ async function runInit(argv, overrides) {
|
|
|
14292
14433
|
const validation2 = validateWrittenConfig(configPath, projectRoot, false);
|
|
14293
14434
|
if (validation2 !== null) {
|
|
14294
14435
|
try {
|
|
14295
|
-
|
|
14436
|
+
rmSync3(configPath, { force: true });
|
|
14296
14437
|
} catch {
|
|
14297
14438
|
}
|
|
14298
14439
|
errLog(`error: template config failed validation: ${validation2}`);
|
|
@@ -14370,7 +14511,7 @@ async function runInit(argv, overrides) {
|
|
|
14370
14511
|
const validation = validateWrittenConfig(configPath, projectRoot, !emptyStack);
|
|
14371
14512
|
if (validation !== null) {
|
|
14372
14513
|
try {
|
|
14373
|
-
|
|
14514
|
+
rmSync3(configPath, { force: true });
|
|
14374
14515
|
} catch {
|
|
14375
14516
|
}
|
|
14376
14517
|
errLog(`error: generated config failed validation: ${validation}`);
|
|
@@ -14403,8 +14544,8 @@ function installSideEffects(projectRoot, log, skipCommands = false, emptyStack =
|
|
|
14403
14544
|
const commandStats = cmdResult.assets.commands;
|
|
14404
14545
|
const stackResolved = !emptyStack && commandStats && (commandStats.installed > 0 || commandStats.updated > 0 || commandStats.kept > 0);
|
|
14405
14546
|
if (!stackResolved) {
|
|
14406
|
-
const placeholderPath =
|
|
14407
|
-
if (!
|
|
14547
|
+
const placeholderPath = resolve8(cmdResult.claudeDir, "commands", "_massu-needs-stack.md");
|
|
14548
|
+
if (!existsSync12(placeholderPath)) {
|
|
14408
14549
|
const placeholderBody = [
|
|
14409
14550
|
"# Massu \u2014 stack not yet detected",
|
|
14410
14551
|
"",
|
|
@@ -14425,8 +14566,8 @@ function installSideEffects(projectRoot, log, skipCommands = false, emptyStack =
|
|
|
14425
14566
|
"\u2014 Massu"
|
|
14426
14567
|
].join("\n");
|
|
14427
14568
|
try {
|
|
14428
|
-
|
|
14429
|
-
|
|
14569
|
+
mkdirSync6(resolve8(cmdResult.claudeDir, "commands"), { recursive: true });
|
|
14570
|
+
writeFileSync3(placeholderPath, placeholderBody, "utf-8");
|
|
14430
14571
|
log(" Wrote _massu-needs-stack.md placeholder (no stack detected yet)");
|
|
14431
14572
|
} catch {
|
|
14432
14573
|
}
|
|
@@ -14448,8 +14589,8 @@ function installSideEffects(projectRoot, log, skipCommands = false, emptyStack =
|
|
|
14448
14589
|
(async () => {
|
|
14449
14590
|
try {
|
|
14450
14591
|
const encodedRoot = encodeMemoryDirName(projectRoot);
|
|
14451
|
-
const memoryDir =
|
|
14452
|
-
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") : [];
|
|
14453
14594
|
if (memFiles.length > 0) {
|
|
14454
14595
|
const { getMemoryDb: getMemoryDb2 } = await Promise.resolve().then(() => (init_memory_db(), memory_db_exports));
|
|
14455
14596
|
const db = getMemoryDb2();
|
|
@@ -14639,6 +14780,28 @@ var init_license_response_verifier = __esm({
|
|
|
14639
14780
|
});
|
|
14640
14781
|
|
|
14641
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
|
+
});
|
|
14642
14805
|
import { createHash as createHash5 } from "crypto";
|
|
14643
14806
|
function warnLicenseSigOnce(reason) {
|
|
14644
14807
|
if (_warnedLicenseSig) return;
|
|
@@ -14704,11 +14867,12 @@ async function validateLicense(apiKey) {
|
|
|
14704
14867
|
const lastValidated = new Date(cached.last_validated);
|
|
14705
14868
|
const hourAgo = new Date(Date.now() - 60 * 60 * 1e3);
|
|
14706
14869
|
if (lastValidated > hourAgo) {
|
|
14707
|
-
return trusted;
|
|
14870
|
+
return { ...trusted, outcome: "cache_fresh" };
|
|
14708
14871
|
}
|
|
14709
14872
|
}
|
|
14710
14873
|
const config = getConfig();
|
|
14711
14874
|
const endpoint = config.cloud?.endpoint;
|
|
14875
|
+
let fallbackOutcome = "no_endpoint";
|
|
14712
14876
|
if (endpoint && /^https?:\/\/.+/.test(endpoint)) {
|
|
14713
14877
|
try {
|
|
14714
14878
|
const response = await fetch(`${endpoint}/validate-key`, {
|
|
@@ -14740,21 +14904,23 @@ async function validateLicense(apiKey) {
|
|
|
14740
14904
|
features,
|
|
14741
14905
|
sigResult.kind === "valid" ? data : null
|
|
14742
14906
|
);
|
|
14743
|
-
return { tier, validUntil, features };
|
|
14907
|
+
return { tier, validUntil, features, outcome: "validated" };
|
|
14744
14908
|
}
|
|
14745
|
-
return { tier: "free", validUntil: "", features: [] };
|
|
14909
|
+
return { tier: "free", validUntil: "", features: [], outcome: "rejected" };
|
|
14746
14910
|
}
|
|
14911
|
+
fallbackOutcome = "server_error";
|
|
14747
14912
|
} catch {
|
|
14913
|
+
fallbackOutcome = "network_error";
|
|
14748
14914
|
}
|
|
14749
14915
|
}
|
|
14750
14916
|
if (cached && trusted) {
|
|
14751
14917
|
const lastValidated = new Date(cached.last_validated);
|
|
14752
14918
|
const sevenDaysAgo = new Date(Date.now() - GRACE_PERIOD_MS);
|
|
14753
14919
|
if (lastValidated > sevenDaysAgo) {
|
|
14754
|
-
return trusted;
|
|
14920
|
+
return { ...trusted, outcome: "grace" };
|
|
14755
14921
|
}
|
|
14756
14922
|
}
|
|
14757
|
-
return { tier: "free", validUntil: "", features: [] };
|
|
14923
|
+
return { tier: "free", validUntil: "", features: [], outcome: fallbackOutcome };
|
|
14758
14924
|
} finally {
|
|
14759
14925
|
memDb.close();
|
|
14760
14926
|
}
|
|
@@ -14810,7 +14976,7 @@ async function getCurrentTier() {
|
|
|
14810
14976
|
const config = getConfig();
|
|
14811
14977
|
const apiKey = config.cloud?.apiKey;
|
|
14812
14978
|
if (!apiKey) {
|
|
14813
|
-
cachedTier = { tier: "free", validUntil: "", features: [] };
|
|
14979
|
+
cachedTier = { tier: "free", validUntil: "", features: [], outcome: "no_key" };
|
|
14814
14980
|
cachedTierTimestamp = Date.now();
|
|
14815
14981
|
return "free";
|
|
14816
14982
|
}
|
|
@@ -14943,6 +15109,14 @@ async function handleLicenseToolCall(name, _args, _memDb) {
|
|
|
14943
15109
|
}
|
|
14944
15110
|
return { content: [{ type: "text", text: `Unknown license tool: ${name}` }] };
|
|
14945
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
|
+
}
|
|
14946
15120
|
var _warnedLicenseSig, TIER_LEVELS, TOOL_TIER_MAP, PLAN_TO_TIER_MAP, TIER_LABELS, cachedTier, cachedTierTimestamp, IN_MEMORY_CACHE_TTL_MS, GRACE_PERIOD_MS;
|
|
14947
15121
|
var init_license = __esm({
|
|
14948
15122
|
"src/license.ts"() {
|
|
@@ -15098,20 +15272,21 @@ var init_hook_registry = __esm({
|
|
|
15098
15272
|
// src/commands/doctor.ts
|
|
15099
15273
|
var doctor_exports = {};
|
|
15100
15274
|
__export(doctor_exports, {
|
|
15275
|
+
formatLicenseCheck: () => formatLicenseCheck,
|
|
15101
15276
|
runDoctor: () => runDoctor,
|
|
15102
15277
|
runValidateConfig: () => runValidateConfig
|
|
15103
15278
|
});
|
|
15104
|
-
import { existsSync as
|
|
15105
|
-
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";
|
|
15106
15281
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
15107
15282
|
import { parse as parseYaml4 } from "yaml";
|
|
15108
15283
|
function checkConfig(projectRoot) {
|
|
15109
|
-
const configPath =
|
|
15110
|
-
if (!
|
|
15284
|
+
const configPath = resolve9(projectRoot, "massu.config.yaml");
|
|
15285
|
+
if (!existsSync13(configPath)) {
|
|
15111
15286
|
return { name: "Configuration", status: "fail", detail: "massu.config.yaml not found. Run: npx massu init" };
|
|
15112
15287
|
}
|
|
15113
15288
|
try {
|
|
15114
|
-
const content =
|
|
15289
|
+
const content = readFileSync13(configPath, "utf-8");
|
|
15115
15290
|
const parsed = parseYaml4(content);
|
|
15116
15291
|
if (!parsed || typeof parsed !== "object") {
|
|
15117
15292
|
return { name: "Configuration", status: "fail", detail: "massu.config.yaml is empty or invalid YAML" };
|
|
@@ -15123,11 +15298,11 @@ function checkConfig(projectRoot) {
|
|
|
15123
15298
|
}
|
|
15124
15299
|
function checkMcpServer(projectRoot) {
|
|
15125
15300
|
const mcpPath = getResolvedPaths().mcpJsonPath;
|
|
15126
|
-
if (!
|
|
15301
|
+
if (!existsSync13(mcpPath)) {
|
|
15127
15302
|
return { name: "MCP Server", status: "fail", detail: ".mcp.json not found. Run: npx massu init" };
|
|
15128
15303
|
}
|
|
15129
15304
|
try {
|
|
15130
|
-
const content = JSON.parse(
|
|
15305
|
+
const content = JSON.parse(readFileSync13(mcpPath, "utf-8"));
|
|
15131
15306
|
const servers = content.mcpServers ?? {};
|
|
15132
15307
|
if (!servers.massu) {
|
|
15133
15308
|
return { name: "MCP Server", status: "fail", detail: "massu not registered in .mcp.json. Run: npx massu init" };
|
|
@@ -15139,7 +15314,7 @@ function checkMcpServer(projectRoot) {
|
|
|
15139
15314
|
}
|
|
15140
15315
|
function checkHooksConfig(projectRoot) {
|
|
15141
15316
|
const settingsPath = getResolvedPaths().settingsLocalPath;
|
|
15142
|
-
if (!
|
|
15317
|
+
if (!existsSync13(settingsPath)) {
|
|
15143
15318
|
return { name: "Hooks Config", status: "fail", detail: ".claude/settings.local.json not found. Run: npx massu init" };
|
|
15144
15319
|
}
|
|
15145
15320
|
try {
|
|
@@ -15167,11 +15342,11 @@ function checkHooksConfig(projectRoot) {
|
|
|
15167
15342
|
}
|
|
15168
15343
|
}
|
|
15169
15344
|
function checkHookFiles(projectRoot) {
|
|
15170
|
-
const nodeModulesHooksDir =
|
|
15345
|
+
const nodeModulesHooksDir = resolve9(projectRoot, "node_modules/@massu/core/dist/hooks");
|
|
15171
15346
|
let hooksDir = nodeModulesHooksDir;
|
|
15172
|
-
if (!
|
|
15173
|
-
const devHooksDir =
|
|
15174
|
-
if (
|
|
15347
|
+
if (!existsSync13(nodeModulesHooksDir)) {
|
|
15348
|
+
const devHooksDir = resolve9(__dirname3, "../../dist/hooks");
|
|
15349
|
+
if (existsSync13(devHooksDir)) {
|
|
15175
15350
|
hooksDir = devHooksDir;
|
|
15176
15351
|
} else {
|
|
15177
15352
|
return { name: "Hook Files", status: "fail", detail: "Compiled hooks not found. Run: npm install @massu/core" };
|
|
@@ -15179,7 +15354,7 @@ function checkHookFiles(projectRoot) {
|
|
|
15179
15354
|
}
|
|
15180
15355
|
const missing = [];
|
|
15181
15356
|
for (const hookFile of EXPECTED_HOOKS) {
|
|
15182
|
-
if (!
|
|
15357
|
+
if (!existsSync13(resolve9(hooksDir, hookFile))) {
|
|
15183
15358
|
missing.push(hookFile);
|
|
15184
15359
|
}
|
|
15185
15360
|
}
|
|
@@ -15205,8 +15380,8 @@ function checkNodeVersion() {
|
|
|
15205
15380
|
return { name: "Node.js", status: "fail", detail: `v${version} \u2014 Node.js 18+ is required` };
|
|
15206
15381
|
}
|
|
15207
15382
|
async function checkGitRepo(projectRoot) {
|
|
15208
|
-
const gitDir =
|
|
15209
|
-
if (!
|
|
15383
|
+
const gitDir = resolve9(projectRoot, ".git");
|
|
15384
|
+
if (!existsSync13(gitDir)) {
|
|
15210
15385
|
return { name: "Git Repository", status: "warn", detail: "Not a git repository (optional but recommended)" };
|
|
15211
15386
|
}
|
|
15212
15387
|
try {
|
|
@@ -15224,7 +15399,7 @@ async function checkGitRepo(projectRoot) {
|
|
|
15224
15399
|
}
|
|
15225
15400
|
function checkKnowledgeDb(projectRoot) {
|
|
15226
15401
|
const knowledgeDbPath = getResolvedPaths().memoryDbPath;
|
|
15227
|
-
if (!
|
|
15402
|
+
if (!existsSync13(knowledgeDbPath)) {
|
|
15228
15403
|
return {
|
|
15229
15404
|
name: "Knowledge DB",
|
|
15230
15405
|
status: "warn",
|
|
@@ -15235,7 +15410,7 @@ function checkKnowledgeDb(projectRoot) {
|
|
|
15235
15410
|
}
|
|
15236
15411
|
function checkMemoryDir(_projectRoot2) {
|
|
15237
15412
|
const memoryDir = getResolvedPaths().memoryDir;
|
|
15238
|
-
if (!
|
|
15413
|
+
if (!existsSync13(memoryDir)) {
|
|
15239
15414
|
return {
|
|
15240
15415
|
name: "Memory Directory",
|
|
15241
15416
|
status: "warn",
|
|
@@ -15246,7 +15421,7 @@ function checkMemoryDir(_projectRoot2) {
|
|
|
15246
15421
|
}
|
|
15247
15422
|
function checkShellHooksWired(_projectRoot2) {
|
|
15248
15423
|
const settingsPath = getResolvedPaths().settingsLocalPath;
|
|
15249
|
-
if (!
|
|
15424
|
+
if (!existsSync13(settingsPath)) {
|
|
15250
15425
|
return {
|
|
15251
15426
|
name: "Shell Hooks",
|
|
15252
15427
|
status: "fail",
|
|
@@ -15274,26 +15449,43 @@ function checkShellHooksWired(_projectRoot2) {
|
|
|
15274
15449
|
};
|
|
15275
15450
|
}
|
|
15276
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
|
+
}
|
|
15277
15483
|
async function checkLicenseStatus() {
|
|
15278
15484
|
try {
|
|
15485
|
+
const source = getResolvedApiKeySource();
|
|
15279
15486
|
const tier = await getCurrentTier();
|
|
15280
15487
|
const info = await getLicenseInfo();
|
|
15281
|
-
|
|
15282
|
-
return { name: "License", status: "pass", detail: "Free (no API key configured)" };
|
|
15283
|
-
}
|
|
15284
|
-
const days = await daysUntilExpiry();
|
|
15285
|
-
if (days >= 0 && info.validUntil) {
|
|
15286
|
-
return {
|
|
15287
|
-
name: "License",
|
|
15288
|
-
status: "pass",
|
|
15289
|
-
detail: `${tier.charAt(0).toUpperCase() + tier.slice(1)} (valid until ${info.validUntil})`
|
|
15290
|
-
};
|
|
15291
|
-
}
|
|
15292
|
-
return {
|
|
15293
|
-
name: "License",
|
|
15294
|
-
status: "pass",
|
|
15295
|
-
detail: `${tier.charAt(0).toUpperCase() + tier.slice(1)} (valid)`
|
|
15296
|
-
};
|
|
15488
|
+
return formatLicenseCheck({ source, tier, validUntil: info.validUntil, outcome: info.outcome });
|
|
15297
15489
|
} catch (err) {
|
|
15298
15490
|
return {
|
|
15299
15491
|
name: "License",
|
|
@@ -15302,11 +15494,31 @@ async function checkLicenseStatus() {
|
|
|
15302
15494
|
};
|
|
15303
15495
|
}
|
|
15304
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
|
+
}
|
|
15305
15517
|
function checkPythonHealth(projectRoot) {
|
|
15306
15518
|
const config = getConfig();
|
|
15307
15519
|
if (!config.python?.root) return null;
|
|
15308
|
-
const pythonRoot =
|
|
15309
|
-
if (!
|
|
15520
|
+
const pythonRoot = resolve9(projectRoot, config.python.root);
|
|
15521
|
+
if (!existsSync13(pythonRoot)) {
|
|
15310
15522
|
return {
|
|
15311
15523
|
name: "Python",
|
|
15312
15524
|
status: "fail",
|
|
@@ -15325,8 +15537,8 @@ function checkPythonHealth(projectRoot) {
|
|
|
15325
15537
|
if (entry.isDirectory()) {
|
|
15326
15538
|
const excludeDirs = config.python?.exclude_dirs || ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"];
|
|
15327
15539
|
if (!excludeDirs.includes(entry.name)) {
|
|
15328
|
-
const subdir =
|
|
15329
|
-
if (depth <= 2 && !
|
|
15540
|
+
const subdir = resolve9(dir, entry.name);
|
|
15541
|
+
if (depth <= 2 && !existsSync13(resolve9(subdir, "__init__.py"))) {
|
|
15330
15542
|
try {
|
|
15331
15543
|
const subEntries = readdirSync11(subdir);
|
|
15332
15544
|
if (subEntries.some((f2) => f2.endsWith(".py") && f2 !== "__init__.py")) {
|
|
@@ -15396,6 +15608,8 @@ async function runDoctor() {
|
|
|
15396
15608
|
];
|
|
15397
15609
|
const pythonCheck = checkPythonHealth(projectRoot);
|
|
15398
15610
|
if (pythonCheck) checks.push(pythonCheck);
|
|
15611
|
+
const hygieneCheck = await checkApiKeyHygiene(projectRoot);
|
|
15612
|
+
if (hygieneCheck) checks.push(hygieneCheck);
|
|
15399
15613
|
let passed = 0;
|
|
15400
15614
|
let failed = 0;
|
|
15401
15615
|
let warned = 0;
|
|
@@ -15421,15 +15635,15 @@ async function runDoctor() {
|
|
|
15421
15635
|
}
|
|
15422
15636
|
async function runValidateConfig() {
|
|
15423
15637
|
const projectRoot = process.cwd();
|
|
15424
|
-
const configPath =
|
|
15425
|
-
if (!
|
|
15638
|
+
const configPath = resolve9(projectRoot, "massu.config.yaml");
|
|
15639
|
+
if (!existsSync13(configPath)) {
|
|
15426
15640
|
console.error("Error: massu.config.yaml not found in current directory");
|
|
15427
15641
|
console.error("Run: npx massu init");
|
|
15428
15642
|
process.exit(1);
|
|
15429
15643
|
return;
|
|
15430
15644
|
}
|
|
15431
15645
|
try {
|
|
15432
|
-
const content =
|
|
15646
|
+
const content = readFileSync13(configPath, "utf-8");
|
|
15433
15647
|
const parsed = parseYaml4(content);
|
|
15434
15648
|
if (!parsed || typeof parsed !== "object") {
|
|
15435
15649
|
console.error("Error: massu.config.yaml is empty or not a valid YAML object");
|
|
@@ -15467,6 +15681,7 @@ var init_doctor = __esm({
|
|
|
15467
15681
|
"use strict";
|
|
15468
15682
|
init_config();
|
|
15469
15683
|
init_license();
|
|
15684
|
+
init_credentials();
|
|
15470
15685
|
init_settings_local();
|
|
15471
15686
|
init_hook_registry();
|
|
15472
15687
|
__filename3 = fileURLToPath3(import.meta.url);
|
|
@@ -15475,6 +15690,114 @@ var init_doctor = __esm({
|
|
|
15475
15690
|
}
|
|
15476
15691
|
});
|
|
15477
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
|
+
|
|
15478
15801
|
// src/commands/install-hooks.ts
|
|
15479
15802
|
var install_hooks_exports = {};
|
|
15480
15803
|
__export(install_hooks_exports, {
|
|
@@ -15506,8 +15829,8 @@ __export(hook_runner_exports, {
|
|
|
15506
15829
|
resolveHookFile: () => resolveHookFile,
|
|
15507
15830
|
runHookRunner: () => runHookRunner
|
|
15508
15831
|
});
|
|
15509
|
-
import { existsSync as
|
|
15510
|
-
import { resolve as
|
|
15832
|
+
import { existsSync as existsSync14 } from "fs";
|
|
15833
|
+
import { resolve as resolve10, dirname as dirname8 } from "path";
|
|
15511
15834
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
15512
15835
|
import { spawn } from "child_process";
|
|
15513
15836
|
function resolveHookFile(hookName) {
|
|
@@ -15519,14 +15842,14 @@ function resolveHookFile(hookName) {
|
|
|
15519
15842
|
}
|
|
15520
15843
|
const candidates = [
|
|
15521
15844
|
// Bundled compiled layout: dist/cli.js → ./hooks/<file>.js
|
|
15522
|
-
|
|
15845
|
+
resolve10(__dirname4, "hooks", file),
|
|
15523
15846
|
// TS-source dev / sibling layout: src/commands/ → ../hooks/<file>
|
|
15524
|
-
|
|
15847
|
+
resolve10(__dirname4, "../hooks", file),
|
|
15525
15848
|
// TS-source dev fallback: src/commands/ → ../../dist/hooks/<file>
|
|
15526
|
-
|
|
15849
|
+
resolve10(__dirname4, "../../dist/hooks", file)
|
|
15527
15850
|
];
|
|
15528
15851
|
for (const candidate of candidates) {
|
|
15529
|
-
if (
|
|
15852
|
+
if (existsSync14(candidate)) {
|
|
15530
15853
|
return candidate;
|
|
15531
15854
|
}
|
|
15532
15855
|
}
|
|
@@ -15591,7 +15914,7 @@ __export(permissions_exports, {
|
|
|
15591
15914
|
handlePermissionsSubcommand: () => handlePermissionsSubcommand,
|
|
15592
15915
|
printPermissionsHelp: () => printPermissionsHelp
|
|
15593
15916
|
});
|
|
15594
|
-
import { resolve as
|
|
15917
|
+
import { resolve as resolve11 } from "path";
|
|
15595
15918
|
function resolveClaudeDir2() {
|
|
15596
15919
|
let claudeDirName = ".claude";
|
|
15597
15920
|
try {
|
|
@@ -15599,7 +15922,7 @@ function resolveClaudeDir2() {
|
|
|
15599
15922
|
} catch {
|
|
15600
15923
|
claudeDirName = ".claude";
|
|
15601
15924
|
}
|
|
15602
|
-
return
|
|
15925
|
+
return resolve11(process.cwd(), claudeDirName);
|
|
15603
15926
|
}
|
|
15604
15927
|
async function handlePermissionsSubcommand(args2) {
|
|
15605
15928
|
const sub = args2[0];
|
|
@@ -15729,8 +16052,8 @@ var init_auto_learning_entitlement = __esm({
|
|
|
15729
16052
|
});
|
|
15730
16053
|
|
|
15731
16054
|
// src/commands/license.ts
|
|
15732
|
-
var
|
|
15733
|
-
__export(
|
|
16055
|
+
var license_exports2 = {};
|
|
16056
|
+
__export(license_exports2, {
|
|
15734
16057
|
handleLicenseSubcommand: () => handleLicenseSubcommand,
|
|
15735
16058
|
printLicenseHelp: () => printLicenseHelp
|
|
15736
16059
|
});
|
|
@@ -15818,8 +16141,8 @@ var init_license2 = __esm({
|
|
|
15818
16141
|
});
|
|
15819
16142
|
|
|
15820
16143
|
// src/changelog-generator.ts
|
|
15821
|
-
import { existsSync as
|
|
15822
|
-
import { resolve as
|
|
16144
|
+
import { existsSync as existsSync15, readFileSync as readFileSync14, readdirSync as readdirSync12 } from "fs";
|
|
16145
|
+
import { resolve as resolve12 } from "path";
|
|
15823
16146
|
function parseCommitsForPlanTokens(subjects) {
|
|
15824
16147
|
const tokens = /* @__PURE__ */ new Set();
|
|
15825
16148
|
const maintenance = [];
|
|
@@ -15836,7 +16159,7 @@ function parseCommitsForPlanTokens(subjects) {
|
|
|
15836
16159
|
function loadPlanSummaries(tokens, planDir) {
|
|
15837
16160
|
const result = /* @__PURE__ */ new Map();
|
|
15838
16161
|
if (tokens.size === 0) return result;
|
|
15839
|
-
if (!
|
|
16162
|
+
if (!existsSync15(planDir)) {
|
|
15840
16163
|
throw new Error(`Plan directory does not exist: ${planDir}`);
|
|
15841
16164
|
}
|
|
15842
16165
|
const files = readdirSync12(planDir).filter((f2) => f2.endsWith(".md"));
|
|
@@ -15844,8 +16167,8 @@ function loadPlanSummaries(tokens, planDir) {
|
|
|
15844
16167
|
let matchedFile = null;
|
|
15845
16168
|
let content = "";
|
|
15846
16169
|
for (const file of files) {
|
|
15847
|
-
const path =
|
|
15848
|
-
const text18 =
|
|
16170
|
+
const path = resolve12(planDir, file);
|
|
16171
|
+
const text18 = readFileSync14(path, "utf-8");
|
|
15849
16172
|
const tokenRe = new RegExp(
|
|
15850
16173
|
`^\\*\\*Plan Token\\*\\*:\\s*\`?${token.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")}\`?(\\s|$)`,
|
|
15851
16174
|
"m"
|
|
@@ -15926,8 +16249,8 @@ __export(changelog_exports, {
|
|
|
15926
16249
|
printChangelogHelp: () => printChangelogHelp
|
|
15927
16250
|
});
|
|
15928
16251
|
import { execSync } from "child_process";
|
|
15929
|
-
import { existsSync as
|
|
15930
|
-
import { resolve as
|
|
16252
|
+
import { existsSync as existsSync16, readFileSync as readFileSync15 } from "fs";
|
|
16253
|
+
import { resolve as resolve13 } from "path";
|
|
15931
16254
|
function resolveRepoRoot() {
|
|
15932
16255
|
try {
|
|
15933
16256
|
return execSync("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
|
|
@@ -15951,25 +16274,25 @@ function getCommitSubjects(range) {
|
|
|
15951
16274
|
}
|
|
15952
16275
|
}
|
|
15953
16276
|
function getCurrentVersion(repoRoot) {
|
|
15954
|
-
const pkgPath =
|
|
15955
|
-
if (!
|
|
15956
|
-
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"));
|
|
15957
16280
|
return pkg.version || "0.0.0";
|
|
15958
16281
|
}
|
|
15959
16282
|
function todayDate() {
|
|
15960
16283
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
15961
16284
|
}
|
|
15962
16285
|
function getLatestChangelogEntryBody(repoRoot) {
|
|
15963
|
-
const path =
|
|
15964
|
-
if (!
|
|
15965
|
-
const content =
|
|
16286
|
+
const path = resolve13(repoRoot, "CHANGELOG.md");
|
|
16287
|
+
if (!existsSync16(path)) return "";
|
|
16288
|
+
const content = readFileSync15(path, "utf-8");
|
|
15966
16289
|
const m3 = content.match(/^## \[[\d.]+\][^\n]*\n([\s\S]*?)(?=\n## \[|$)/m);
|
|
15967
16290
|
return m3 ? m3[1] : "";
|
|
15968
16291
|
}
|
|
15969
16292
|
async function handleChangelogSubcommand(args2) {
|
|
15970
16293
|
const sub = args2[0];
|
|
15971
16294
|
const repoRoot = resolveRepoRoot();
|
|
15972
|
-
const planDir =
|
|
16295
|
+
const planDir = resolve13(repoRoot, "docs/plans");
|
|
15973
16296
|
switch (sub) {
|
|
15974
16297
|
case "generate": {
|
|
15975
16298
|
const lastTag = getLastTag();
|
|
@@ -16180,7 +16503,7 @@ var init_rule_pack_schema = __esm({
|
|
|
16180
16503
|
});
|
|
16181
16504
|
|
|
16182
16505
|
// src/rule-pack-sync.ts
|
|
16183
|
-
import { existsSync as
|
|
16506
|
+
import { existsSync as existsSync17, writeFileSync as writeFileSync4, mkdirSync as mkdirSync7 } from "fs";
|
|
16184
16507
|
import { join as join11, dirname as dirname9 } from "path";
|
|
16185
16508
|
async function pullInstalledPackRules(db, opts = {}) {
|
|
16186
16509
|
const config = getConfig();
|
|
@@ -16243,7 +16566,7 @@ async function pullInstalledPackRules(db, opts = {}) {
|
|
|
16243
16566
|
result.pulled += 1;
|
|
16244
16567
|
const promptHash = packRulePromptHash(pack.slug, rule);
|
|
16245
16568
|
const candidatePath = sidecarPath(projectRoot, promptHash);
|
|
16246
|
-
if (
|
|
16569
|
+
if (existsSync17(candidatePath) || alreadyApplied(db, promptHash)) {
|
|
16247
16570
|
result.skipped += 1;
|
|
16248
16571
|
continue;
|
|
16249
16572
|
}
|
|
@@ -16331,8 +16654,8 @@ function materializeCandidate(projectRoot, candidatePath, promptHash, rule, pack
|
|
|
16331
16654
|
draft_text: draftText
|
|
16332
16655
|
};
|
|
16333
16656
|
const dir = dirname9(candidatePath);
|
|
16334
|
-
if (!
|
|
16335
|
-
|
|
16657
|
+
if (!existsSync17(dir)) mkdirSync7(dir, { recursive: true });
|
|
16658
|
+
writeFileSync4(candidatePath, JSON.stringify(sidecar, null, 2), "utf-8");
|
|
16336
16659
|
}
|
|
16337
16660
|
function emitDropTelemetry(db, eventType, data) {
|
|
16338
16661
|
recordTelemetry(db, eventType, data);
|
|
@@ -16446,8 +16769,8 @@ var show_template_exports = {};
|
|
|
16446
16769
|
__export(show_template_exports, {
|
|
16447
16770
|
runShowTemplate: () => runShowTemplate
|
|
16448
16771
|
});
|
|
16449
|
-
import { existsSync as
|
|
16450
|
-
import { resolve as
|
|
16772
|
+
import { existsSync as existsSync18, readFileSync as readFileSync16 } from "fs";
|
|
16773
|
+
import { resolve as resolve14 } from "path";
|
|
16451
16774
|
function normalizeBaseName(input) {
|
|
16452
16775
|
return input.endsWith(".md") ? input.slice(0, -".md".length) : input;
|
|
16453
16776
|
}
|
|
@@ -16475,14 +16798,14 @@ async function runShowTemplate(args2) {
|
|
|
16475
16798
|
return;
|
|
16476
16799
|
}
|
|
16477
16800
|
const suffix = choice.kind === "hit" ? choice.suffix : "";
|
|
16478
|
-
const file = suffix === "" ?
|
|
16479
|
-
if (!
|
|
16801
|
+
const file = suffix === "" ? resolve14(sourceDir, `${baseName}.md`) : resolve14(sourceDir, `${baseName}${suffix}.md`);
|
|
16802
|
+
if (!existsSync18(file)) {
|
|
16480
16803
|
process.stderr.write(`massu: resolved template "${file}" no longer exists
|
|
16481
16804
|
`);
|
|
16482
16805
|
process.exit(1);
|
|
16483
16806
|
return;
|
|
16484
16807
|
}
|
|
16485
|
-
process.stdout.write(
|
|
16808
|
+
process.stdout.write(readFileSync16(file, "utf-8"));
|
|
16486
16809
|
}
|
|
16487
16810
|
var init_show_template = __esm({
|
|
16488
16811
|
"src/commands/show-template.ts"() {
|
|
@@ -16535,12 +16858,12 @@ var init_passthrough = __esm({
|
|
|
16535
16858
|
});
|
|
16536
16859
|
|
|
16537
16860
|
// src/lib/fileLock.ts
|
|
16538
|
-
import { mkdirSync as
|
|
16861
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync17, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
16539
16862
|
import { dirname as dirname10 } from "path";
|
|
16540
16863
|
import * as lockfile from "proper-lockfile";
|
|
16541
16864
|
function readLockHolderPid(lockPath) {
|
|
16542
16865
|
try {
|
|
16543
|
-
const raw =
|
|
16866
|
+
const raw = readFileSync17(`${lockPath}.pid`, "utf-8").trim();
|
|
16544
16867
|
const pid = Number.parseInt(raw, 10);
|
|
16545
16868
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
16546
16869
|
return pid;
|
|
@@ -16559,7 +16882,7 @@ function busyWaitSync(ms) {
|
|
|
16559
16882
|
Atomics.wait(view, 0, 0, ms);
|
|
16560
16883
|
}
|
|
16561
16884
|
function withFileLockSync(lockPath, fn, opts = {}) {
|
|
16562
|
-
|
|
16885
|
+
mkdirSync8(dirname10(lockPath), { recursive: true });
|
|
16563
16886
|
const staleMs = opts.staleMs ?? 3e4;
|
|
16564
16887
|
const blockMs = opts.retries === 0 ? 0 : opts.blockMs ?? 3e4;
|
|
16565
16888
|
const pollIntervalMs = opts.pollIntervalMs ?? 100;
|
|
@@ -16576,7 +16899,7 @@ function withFileLockSync(lockPath, fn, opts = {}) {
|
|
|
16576
16899
|
realpath: false
|
|
16577
16900
|
});
|
|
16578
16901
|
try {
|
|
16579
|
-
|
|
16902
|
+
writeFileSync5(`${lockPath}.pid`, String(process.pid), "utf-8");
|
|
16580
16903
|
} catch {
|
|
16581
16904
|
}
|
|
16582
16905
|
break;
|
|
@@ -16603,7 +16926,7 @@ function withFileLockSync(lockPath, fn, opts = {}) {
|
|
|
16603
16926
|
} catch {
|
|
16604
16927
|
}
|
|
16605
16928
|
try {
|
|
16606
|
-
|
|
16929
|
+
rmSync4(`${lockPath}.pid`, { force: true });
|
|
16607
16930
|
} catch {
|
|
16608
16931
|
}
|
|
16609
16932
|
}
|
|
@@ -16622,14 +16945,18 @@ var init_fileLock = __esm({
|
|
|
16622
16945
|
this.causeCode = causeCode;
|
|
16623
16946
|
this.name = "FileLockBusyError";
|
|
16624
16947
|
}
|
|
16948
|
+
lockPath;
|
|
16949
|
+
holderPid;
|
|
16950
|
+
retryAfterSeconds;
|
|
16951
|
+
causeCode;
|
|
16625
16952
|
};
|
|
16626
16953
|
}
|
|
16627
16954
|
});
|
|
16628
16955
|
|
|
16629
16956
|
// src/lib/installLock.ts
|
|
16630
|
-
import { resolve as
|
|
16957
|
+
import { resolve as resolve15 } from "path";
|
|
16631
16958
|
function withInstallLock(projectRoot, fn, opts = {}) {
|
|
16632
|
-
const lockPath =
|
|
16959
|
+
const lockPath = resolve15(projectRoot, ".massu", "installAll.lock");
|
|
16633
16960
|
return withFileLockSync(
|
|
16634
16961
|
lockPath,
|
|
16635
16962
|
fn,
|
|
@@ -16654,6 +16981,10 @@ var init_installLock = __esm({
|
|
|
16654
16981
|
this.causeCode = causeCode;
|
|
16655
16982
|
this.name = "InstallLockBusyError";
|
|
16656
16983
|
}
|
|
16984
|
+
lockPath;
|
|
16985
|
+
holderPid;
|
|
16986
|
+
retryAfterSeconds;
|
|
16987
|
+
causeCode;
|
|
16657
16988
|
};
|
|
16658
16989
|
}
|
|
16659
16990
|
});
|
|
@@ -16665,8 +16996,8 @@ __export(config_refresh_exports, {
|
|
|
16665
16996
|
mergeRefresh: () => mergeRefresh,
|
|
16666
16997
|
runConfigRefresh: () => runConfigRefresh
|
|
16667
16998
|
});
|
|
16668
|
-
import { existsSync as
|
|
16669
|
-
import { resolve as
|
|
16999
|
+
import { existsSync as existsSync19, readFileSync as readFileSync18, rmSync as rmSync5 } from "fs";
|
|
17000
|
+
import { resolve as resolve16 } from "path";
|
|
16670
17001
|
import { parse as parseYaml5 } from "yaml";
|
|
16671
17002
|
function flatten(obj, prefix3 = "") {
|
|
16672
17003
|
const out = {};
|
|
@@ -16794,17 +17125,17 @@ function renderDiff(diff) {
|
|
|
16794
17125
|
}
|
|
16795
17126
|
async function runConfigRefresh(opts = {}) {
|
|
16796
17127
|
const cwd = opts.cwd ?? process.cwd();
|
|
16797
|
-
const configPath =
|
|
17128
|
+
const configPath = resolve16(cwd, "massu.config.yaml");
|
|
16798
17129
|
const log = opts.silent ? () => {
|
|
16799
17130
|
} : (s) => process.stdout.write(s);
|
|
16800
|
-
if (!
|
|
17131
|
+
if (!existsSync19(configPath)) {
|
|
16801
17132
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
16802
17133
|
if (!opts.silent) process.stderr.write(message + "\n");
|
|
16803
17134
|
return { exitCode: 1, applied: false, dryRun: !!opts.dryRun, diff: [], message };
|
|
16804
17135
|
}
|
|
16805
17136
|
let existing;
|
|
16806
17137
|
try {
|
|
16807
|
-
const content =
|
|
17138
|
+
const content = readFileSync18(configPath, "utf-8");
|
|
16808
17139
|
const parsed = parseYaml5(content);
|
|
16809
17140
|
if (!parsed || typeof parsed !== "object") {
|
|
16810
17141
|
throw new Error("config is not a YAML object");
|
|
@@ -16877,10 +17208,10 @@ async function runConfigRefresh(opts = {}) {
|
|
|
16877
17208
|
`);
|
|
16878
17209
|
const stackResolved = installResult.totalInstalled > 0 || installResult.totalUpdated > 0;
|
|
16879
17210
|
if (stackResolved) {
|
|
16880
|
-
const placeholderPath =
|
|
16881
|
-
if (
|
|
17211
|
+
const placeholderPath = resolve16(installResult.claudeDir, "commands", "_massu-needs-stack.md");
|
|
17212
|
+
if (existsSync19(placeholderPath)) {
|
|
16882
17213
|
try {
|
|
16883
|
-
|
|
17214
|
+
rmSync5(placeholderPath, { force: true });
|
|
16884
17215
|
log("Removed _massu-needs-stack.md (stack now declared).\n");
|
|
16885
17216
|
} catch {
|
|
16886
17217
|
}
|
|
@@ -16987,12 +17318,12 @@ var init_gitToplevel = __esm({
|
|
|
16987
17318
|
});
|
|
16988
17319
|
|
|
16989
17320
|
// src/watch/lockfile-detector.ts
|
|
16990
|
-
import { existsSync as
|
|
16991
|
-
import { resolve as
|
|
17321
|
+
import { existsSync as existsSync20, statSync as statSync8 } from "fs";
|
|
17322
|
+
import { resolve as resolve17 } from "path";
|
|
16992
17323
|
function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WINDOW_MS) {
|
|
16993
17324
|
for (const lf of KNOWN_LOCKFILES) {
|
|
16994
|
-
const p19 =
|
|
16995
|
-
if (!
|
|
17325
|
+
const p19 = resolve17(projectRoot, lf);
|
|
17326
|
+
if (!existsSync20(p19)) continue;
|
|
16996
17327
|
try {
|
|
16997
17328
|
const stat = statSync8(p19);
|
|
16998
17329
|
const delta = now - stat.mtimeMs;
|
|
@@ -17005,7 +17336,7 @@ function lockfileMidWrite(projectRoot, now = Date.now(), windowMs = LOCKFILE_WIN
|
|
|
17005
17336
|
function gitMidOperation(projectRoot) {
|
|
17006
17337
|
const sentinels = ["MERGE_HEAD", "REBASE_HEAD", "CHERRY_PICK_HEAD", "rebase-apply", "rebase-merge"];
|
|
17007
17338
|
for (const s of sentinels) {
|
|
17008
|
-
if (
|
|
17339
|
+
if (existsSync20(resolve17(projectRoot, ".git", s))) return true;
|
|
17009
17340
|
}
|
|
17010
17341
|
return false;
|
|
17011
17342
|
}
|
|
@@ -17197,23 +17528,25 @@ var init_paths = __esm({
|
|
|
17197
17528
|
this.cap = cap;
|
|
17198
17529
|
this.name = "WatchSurfaceTooLargeError";
|
|
17199
17530
|
}
|
|
17531
|
+
fileCount;
|
|
17532
|
+
cap;
|
|
17200
17533
|
};
|
|
17201
17534
|
}
|
|
17202
17535
|
});
|
|
17203
17536
|
|
|
17204
17537
|
// src/watch/state.ts
|
|
17205
|
-
import { closeSync as closeSync3, existsSync as
|
|
17206
|
-
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";
|
|
17207
17540
|
function watchStatePath(projectRoot) {
|
|
17208
|
-
return
|
|
17541
|
+
return resolve18(projectRoot, ".massu", "watch-state.json");
|
|
17209
17542
|
}
|
|
17210
17543
|
function backupStatePath(projectRoot) {
|
|
17211
|
-
return
|
|
17544
|
+
return resolve18(projectRoot, ".massu", "watch-state.v0.bak.json");
|
|
17212
17545
|
}
|
|
17213
17546
|
function readState(projectRoot) {
|
|
17214
17547
|
const path = watchStatePath(projectRoot);
|
|
17215
|
-
if (!
|
|
17216
|
-
const content =
|
|
17548
|
+
if (!existsSync21(path)) return { ...DEFAULT_STATE };
|
|
17549
|
+
const content = readFileSync19(path, "utf-8");
|
|
17217
17550
|
let raw;
|
|
17218
17551
|
try {
|
|
17219
17552
|
raw = JSON.parse(content);
|
|
@@ -17255,14 +17588,14 @@ function readState(projectRoot) {
|
|
|
17255
17588
|
}
|
|
17256
17589
|
function archiveCorrupt(projectRoot, content) {
|
|
17257
17590
|
const bak = backupStatePath(projectRoot);
|
|
17258
|
-
|
|
17259
|
-
|
|
17591
|
+
mkdirSync9(dirname11(bak), { recursive: true });
|
|
17592
|
+
writeFileSync6(bak, content, "utf-8");
|
|
17260
17593
|
}
|
|
17261
17594
|
function writeStateAtomic(projectRoot, state) {
|
|
17262
17595
|
const path = watchStatePath(projectRoot);
|
|
17263
17596
|
writeStateAtomicCounter = writeStateAtomicCounter + 1 >>> 0;
|
|
17264
17597
|
const tmp = `${path}.${process.pid}.${writeStateAtomicCounter}.tmp`;
|
|
17265
|
-
|
|
17598
|
+
mkdirSync9(dirname11(path), { recursive: true });
|
|
17266
17599
|
let renamed = false;
|
|
17267
17600
|
try {
|
|
17268
17601
|
const fd = openSync3(tmp, "w");
|
|
@@ -17276,9 +17609,9 @@ function writeStateAtomic(projectRoot, state) {
|
|
|
17276
17609
|
renameSync4(tmp, path);
|
|
17277
17610
|
renamed = true;
|
|
17278
17611
|
} finally {
|
|
17279
|
-
if (!renamed &&
|
|
17612
|
+
if (!renamed && existsSync21(tmp)) {
|
|
17280
17613
|
try {
|
|
17281
|
-
|
|
17614
|
+
rmSync6(tmp, { force: true });
|
|
17282
17615
|
} catch {
|
|
17283
17616
|
}
|
|
17284
17617
|
}
|
|
@@ -17312,6 +17645,8 @@ var init_state = __esm({
|
|
|
17312
17645
|
this.daemonMax = daemonMax;
|
|
17313
17646
|
this.name = "WatchStateNewerError";
|
|
17314
17647
|
}
|
|
17648
|
+
stateVersion;
|
|
17649
|
+
daemonMax;
|
|
17315
17650
|
};
|
|
17316
17651
|
writeStateAtomicCounter = 0;
|
|
17317
17652
|
}
|
|
@@ -17556,8 +17891,8 @@ __export(watch_exports, {
|
|
|
17556
17891
|
runWatch: () => runWatch
|
|
17557
17892
|
});
|
|
17558
17893
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
17559
|
-
import { basename as basename5, dirname as dirname12, resolve as
|
|
17560
|
-
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";
|
|
17561
17896
|
function parseFlags(args2) {
|
|
17562
17897
|
const out = {
|
|
17563
17898
|
foreground: false,
|
|
@@ -17582,8 +17917,8 @@ function parseFlags(args2) {
|
|
|
17582
17917
|
}
|
|
17583
17918
|
function findClaudeBg() {
|
|
17584
17919
|
const home = process.env.HOME ?? "";
|
|
17585
|
-
const fixed = home ?
|
|
17586
|
-
if (fixed &&
|
|
17920
|
+
const fixed = home ? resolve19(home, ".claude", "bin", "claude-bg") : null;
|
|
17921
|
+
if (fixed && existsSync22(fixed)) return fixed;
|
|
17587
17922
|
const which = spawnSync3("which", ["claude-bg"], { encoding: "utf-8" });
|
|
17588
17923
|
if (which.status === 0 && which.stdout) {
|
|
17589
17924
|
const p19 = which.stdout.trim();
|
|
@@ -17644,7 +17979,7 @@ async function runWatch(args2) {
|
|
|
17644
17979
|
}
|
|
17645
17980
|
function runStatus(root) {
|
|
17646
17981
|
const path = watchStatePath(root);
|
|
17647
|
-
if (!
|
|
17982
|
+
if (!existsSync22(path)) {
|
|
17648
17983
|
process.stdout.write("massu watch: not running (no state file)\n");
|
|
17649
17984
|
return { exitCode: 0 };
|
|
17650
17985
|
}
|
|
@@ -17726,7 +18061,7 @@ async function runForeground(root) {
|
|
|
17726
18061
|
}
|
|
17727
18062
|
throw err;
|
|
17728
18063
|
}
|
|
17729
|
-
return new Promise((
|
|
18064
|
+
return new Promise((resolve42) => {
|
|
17730
18065
|
const shutdown = async () => {
|
|
17731
18066
|
if (stopped) return;
|
|
17732
18067
|
stopped = true;
|
|
@@ -17736,7 +18071,7 @@ async function runForeground(root) {
|
|
|
17736
18071
|
process.chdir(priorCwd);
|
|
17737
18072
|
} catch {
|
|
17738
18073
|
}
|
|
17739
|
-
|
|
18074
|
+
resolve42({ exitCode: 0 });
|
|
17740
18075
|
};
|
|
17741
18076
|
process.on("SIGINT", () => {
|
|
17742
18077
|
void shutdown();
|
|
@@ -17797,23 +18132,23 @@ async function runOnQuiescent(projectRoot) {
|
|
|
17797
18132
|
);
|
|
17798
18133
|
}
|
|
17799
18134
|
function refreshLogPath(projectRoot) {
|
|
17800
|
-
return
|
|
18135
|
+
return resolve19(projectRoot, ".massu", "refresh-log.jsonl");
|
|
17801
18136
|
}
|
|
17802
18137
|
function appendRefreshLog(projectRoot, event) {
|
|
17803
18138
|
const path = refreshLogPath(projectRoot);
|
|
17804
18139
|
try {
|
|
17805
|
-
|
|
18140
|
+
mkdirSync10(dirname12(path), { recursive: true });
|
|
17806
18141
|
appendFileSync(path, JSON.stringify(event) + "\n", "utf-8");
|
|
17807
18142
|
} catch {
|
|
17808
18143
|
}
|
|
17809
18144
|
}
|
|
17810
18145
|
function readRefreshLog(projectRoot, limit = 10, opts = {}) {
|
|
17811
18146
|
const path = refreshLogPath(projectRoot);
|
|
17812
|
-
if (!
|
|
18147
|
+
if (!existsSync22(path)) return [];
|
|
17813
18148
|
const warn = opts.warn ?? ((s) => {
|
|
17814
18149
|
process.stderr.write(s);
|
|
17815
18150
|
});
|
|
17816
|
-
const lines =
|
|
18151
|
+
const lines = readFileSync20(path, "utf-8").split("\n").filter(Boolean);
|
|
17817
18152
|
const tail = lines.slice(-limit);
|
|
17818
18153
|
const out = [];
|
|
17819
18154
|
let corrupt = 0;
|
|
@@ -17884,14 +18219,14 @@ var init_refresh_log = __esm({
|
|
|
17884
18219
|
|
|
17885
18220
|
// src/security/atomic-write.ts
|
|
17886
18221
|
import {
|
|
17887
|
-
chmodSync as
|
|
18222
|
+
chmodSync as chmodSync4,
|
|
17888
18223
|
closeSync as closeSync4,
|
|
17889
|
-
existsSync as
|
|
18224
|
+
existsSync as existsSync23,
|
|
17890
18225
|
fsyncSync as fsyncSync4,
|
|
17891
|
-
mkdirSync as
|
|
18226
|
+
mkdirSync as mkdirSync11,
|
|
17892
18227
|
openSync as openSync4,
|
|
17893
18228
|
renameSync as renameSync5,
|
|
17894
|
-
rmSync as
|
|
18229
|
+
rmSync as rmSync7,
|
|
17895
18230
|
statSync as statSync9,
|
|
17896
18231
|
writeSync as writeSync4
|
|
17897
18232
|
} from "node:fs";
|
|
@@ -17900,12 +18235,12 @@ function atomicWrite(path, content, opts = {}) {
|
|
|
17900
18235
|
const tmpPath = `${path}.tmp`;
|
|
17901
18236
|
const parentDir = dirname13(path);
|
|
17902
18237
|
try {
|
|
17903
|
-
if (!
|
|
18238
|
+
if (!existsSync23(parentDir)) {
|
|
17904
18239
|
const mkdirOpts = { recursive: true };
|
|
17905
18240
|
if (opts.ensureParentDirMode !== void 0) {
|
|
17906
18241
|
mkdirOpts.mode = opts.ensureParentDirMode;
|
|
17907
18242
|
}
|
|
17908
|
-
|
|
18243
|
+
mkdirSync11(parentDir, mkdirOpts);
|
|
17909
18244
|
}
|
|
17910
18245
|
const buf = typeof content === "string" ? Buffer.from(content, "utf-8") : content;
|
|
17911
18246
|
const openMode = opts.mode ?? 420;
|
|
@@ -17917,14 +18252,14 @@ function atomicWrite(path, content, opts = {}) {
|
|
|
17917
18252
|
closeSync4(fd);
|
|
17918
18253
|
}
|
|
17919
18254
|
if (opts.mode !== void 0) {
|
|
17920
|
-
|
|
18255
|
+
chmodSync4(tmpPath, opts.mode);
|
|
17921
18256
|
}
|
|
17922
18257
|
renameSync5(tmpPath, path);
|
|
17923
18258
|
return { written: true };
|
|
17924
18259
|
} catch (err) {
|
|
17925
|
-
if (
|
|
18260
|
+
if (existsSync23(tmpPath)) {
|
|
17926
18261
|
try {
|
|
17927
|
-
|
|
18262
|
+
rmSync7(tmpPath, { force: true });
|
|
17928
18263
|
} catch {
|
|
17929
18264
|
}
|
|
17930
18265
|
}
|
|
@@ -18242,6 +18577,8 @@ var init_fetcher = __esm({
|
|
|
18242
18577
|
this.host = host;
|
|
18243
18578
|
this.name = "FetchAllowlistError";
|
|
18244
18579
|
}
|
|
18580
|
+
url;
|
|
18581
|
+
host;
|
|
18245
18582
|
};
|
|
18246
18583
|
FetchTimeoutError = class extends Error {
|
|
18247
18584
|
constructor(url, timeoutMs) {
|
|
@@ -18250,6 +18587,8 @@ var init_fetcher = __esm({
|
|
|
18250
18587
|
this.timeoutMs = timeoutMs;
|
|
18251
18588
|
this.name = "FetchTimeoutError";
|
|
18252
18589
|
}
|
|
18590
|
+
url;
|
|
18591
|
+
timeoutMs;
|
|
18253
18592
|
};
|
|
18254
18593
|
FetchBodySizeError = class extends Error {
|
|
18255
18594
|
constructor(url, maxBodyBytes) {
|
|
@@ -18260,29 +18599,31 @@ var init_fetcher = __esm({
|
|
|
18260
18599
|
this.maxBodyBytes = maxBodyBytes;
|
|
18261
18600
|
this.name = "FetchBodySizeError";
|
|
18262
18601
|
}
|
|
18602
|
+
url;
|
|
18603
|
+
maxBodyBytes;
|
|
18263
18604
|
};
|
|
18264
18605
|
}
|
|
18265
18606
|
});
|
|
18266
18607
|
|
|
18267
18608
|
// src/security/manifest-cache.ts
|
|
18268
|
-
import { existsSync as
|
|
18269
|
-
import { homedir as
|
|
18270
|
-
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";
|
|
18271
18612
|
import { z as z4 } from "zod";
|
|
18272
18613
|
function defaultCachePaths() {
|
|
18273
|
-
const dir =
|
|
18614
|
+
const dir = resolve20(homedir6(), ".massu");
|
|
18274
18615
|
return {
|
|
18275
|
-
cachePath:
|
|
18276
|
-
lockPath:
|
|
18616
|
+
cachePath: resolve20(dir, "adapter-manifest.json"),
|
|
18617
|
+
lockPath: resolve20(dir, ".adapter-manifest.lock")
|
|
18277
18618
|
};
|
|
18278
18619
|
}
|
|
18279
18620
|
function loadCachedManifest(paths = defaultCachePaths()) {
|
|
18280
|
-
if (!
|
|
18621
|
+
if (!existsSync24(paths.cachePath)) {
|
|
18281
18622
|
return { kind: "absent" };
|
|
18282
18623
|
}
|
|
18283
18624
|
let raw;
|
|
18284
18625
|
try {
|
|
18285
|
-
const content =
|
|
18626
|
+
const content = readFileSync21(paths.cachePath, "utf-8");
|
|
18286
18627
|
raw = JSON.parse(content);
|
|
18287
18628
|
} catch (err) {
|
|
18288
18629
|
return {
|
|
@@ -18471,15 +18812,15 @@ var init_adapter_origin = __esm({
|
|
|
18471
18812
|
});
|
|
18472
18813
|
|
|
18473
18814
|
// src/security/local-fingerprint.ts
|
|
18474
|
-
import { existsSync as
|
|
18475
|
-
import { homedir as
|
|
18476
|
-
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";
|
|
18477
18818
|
import { createHash as createHash7 } from "node:crypto";
|
|
18478
18819
|
import { z as z5 } from "zod";
|
|
18479
18820
|
function computeLocalFingerprint(localPaths, projectRoot) {
|
|
18480
18821
|
const tuples = [];
|
|
18481
18822
|
for (const p19 of localPaths) {
|
|
18482
|
-
const abs = isAbsolute(p19) ? p19 :
|
|
18823
|
+
const abs = isAbsolute(p19) ? p19 : resolve21(projectRoot, p19);
|
|
18483
18824
|
let contentTag;
|
|
18484
18825
|
try {
|
|
18485
18826
|
const lst = lstatSync5(abs);
|
|
@@ -18488,7 +18829,7 @@ function computeLocalFingerprint(localPaths, projectRoot) {
|
|
|
18488
18829
|
} else if (!lst.isFile()) {
|
|
18489
18830
|
contentTag = "<not-a-file>";
|
|
18490
18831
|
} else {
|
|
18491
|
-
contentTag = createHash7("sha256").update(
|
|
18832
|
+
contentTag = createHash7("sha256").update(readFileSync22(abs)).digest("hex");
|
|
18492
18833
|
}
|
|
18493
18834
|
} catch {
|
|
18494
18835
|
contentTag = "<missing>";
|
|
@@ -18500,10 +18841,10 @@ function computeLocalFingerprint(localPaths, projectRoot) {
|
|
|
18500
18841
|
return createHash7("sha256").update(canonical).digest("hex");
|
|
18501
18842
|
}
|
|
18502
18843
|
function readFingerprintSentinel(path = FINGERPRINT_PATH) {
|
|
18503
|
-
if (!
|
|
18844
|
+
if (!existsSync25(path)) return null;
|
|
18504
18845
|
let raw;
|
|
18505
18846
|
try {
|
|
18506
|
-
raw = JSON.parse(
|
|
18847
|
+
raw = JSON.parse(readFileSync22(path, "utf-8"));
|
|
18507
18848
|
} catch {
|
|
18508
18849
|
return null;
|
|
18509
18850
|
}
|
|
@@ -18551,7 +18892,7 @@ var init_local_fingerprint = __esm({
|
|
|
18551
18892
|
"use strict";
|
|
18552
18893
|
init_atomic_write();
|
|
18553
18894
|
init_manifest_schema();
|
|
18554
|
-
FINGERPRINT_PATH =
|
|
18895
|
+
FINGERPRINT_PATH = resolve21(homedir7(), ".massu", "adapters-local-fingerprint.json");
|
|
18555
18896
|
FingerprintSentinelSchema = z5.object({
|
|
18556
18897
|
fingerprint: z5.string().regex(/^[0-9a-f]{64}$/),
|
|
18557
18898
|
source: z5.enum(["cli", "cli-resync"]),
|
|
@@ -18567,15 +18908,15 @@ var init_local_fingerprint = __esm({
|
|
|
18567
18908
|
});
|
|
18568
18909
|
|
|
18569
18910
|
// src/security/install-tracking.ts
|
|
18570
|
-
import { readFileSync as
|
|
18911
|
+
import { readFileSync as readFileSync23, readdirSync as readdirSync13, lstatSync as lstatSync6, existsSync as existsSync26 } from "node:fs";
|
|
18571
18912
|
import { join as join12, relative as relative5, sep } from "node:path";
|
|
18572
|
-
import { homedir as
|
|
18573
|
-
import { resolve as
|
|
18913
|
+
import { homedir as homedir8 } from "node:os";
|
|
18914
|
+
import { resolve as resolve22 } from "node:path";
|
|
18574
18915
|
import { createHash as createHash8 } from "node:crypto";
|
|
18575
18916
|
import { z as z6 } from "zod";
|
|
18576
18917
|
function containsHiddenDirs(packageDir) {
|
|
18577
18918
|
for (const hidden of EXCLUDED_DIR_NAMES) {
|
|
18578
|
-
if (
|
|
18919
|
+
if (existsSync26(`${packageDir}/${hidden}`)) {
|
|
18579
18920
|
return hidden;
|
|
18580
18921
|
}
|
|
18581
18922
|
}
|
|
@@ -18621,7 +18962,7 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
18621
18962
|
files.sort((a2, b2) => a2.relativePath < b2.relativePath ? -1 : a2.relativePath > b2.relativePath ? 1 : 0);
|
|
18622
18963
|
const top = createHash8("sha256");
|
|
18623
18964
|
for (const f2 of files) {
|
|
18624
|
-
const fileHash = createHash8("sha256").update(
|
|
18965
|
+
const fileHash = createHash8("sha256").update(readFileSync23(f2.absPath)).digest("hex");
|
|
18625
18966
|
top.update(f2.relativePath, "utf-8");
|
|
18626
18967
|
top.update("\0", "utf-8");
|
|
18627
18968
|
top.update(fileHash, "utf-8");
|
|
@@ -18630,10 +18971,10 @@ function sha256OfDir(dir, opts = {}) {
|
|
|
18630
18971
|
return top.digest("hex");
|
|
18631
18972
|
}
|
|
18632
18973
|
function readInstalledManifest(path = INSTALLED_MANIFEST_PATH) {
|
|
18633
|
-
if (!
|
|
18974
|
+
if (!existsSync26(path)) return {};
|
|
18634
18975
|
let raw;
|
|
18635
18976
|
try {
|
|
18636
|
-
raw = JSON.parse(
|
|
18977
|
+
raw = JSON.parse(readFileSync23(path, "utf-8"));
|
|
18637
18978
|
} catch {
|
|
18638
18979
|
return {};
|
|
18639
18980
|
}
|
|
@@ -18697,7 +19038,7 @@ var init_install_tracking = __esm({
|
|
|
18697
19038
|
"src/security/install-tracking.ts"() {
|
|
18698
19039
|
"use strict";
|
|
18699
19040
|
init_atomic_write();
|
|
18700
|
-
INSTALLED_MANIFEST_PATH =
|
|
19041
|
+
INSTALLED_MANIFEST_PATH = resolve22(homedir8(), ".massu", "adapter-manifest-installed.json");
|
|
18701
19042
|
DEFAULT_MAX_FILE_BYTES = 64 * 1024 * 1024;
|
|
18702
19043
|
EXCLUDED_DIR_NAMES = /* @__PURE__ */ new Set([".git", "node_modules", ".cache", ".tmp"]);
|
|
18703
19044
|
InstallEntrySchema = z6.object({
|
|
@@ -18720,12 +19061,12 @@ var init_install_tracking = __esm({
|
|
|
18720
19061
|
});
|
|
18721
19062
|
|
|
18722
19063
|
// src/detect/adapters/discover.ts
|
|
18723
|
-
import { existsSync as
|
|
18724
|
-
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";
|
|
18725
19066
|
import { z as z7 } from "zod";
|
|
18726
19067
|
function walkNodeModules(projectRoot, warnings) {
|
|
18727
|
-
const nodeModulesDir =
|
|
18728
|
-
if (!
|
|
19068
|
+
const nodeModulesDir = resolve23(projectRoot, "node_modules");
|
|
19069
|
+
if (!existsSync27(nodeModulesDir)) {
|
|
18729
19070
|
return [];
|
|
18730
19071
|
}
|
|
18731
19072
|
const candidates = [];
|
|
@@ -18738,7 +19079,7 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
18738
19079
|
}
|
|
18739
19080
|
for (const entry of topLevelEntries) {
|
|
18740
19081
|
if (entry.startsWith(".")) continue;
|
|
18741
|
-
const entryPath =
|
|
19082
|
+
const entryPath = resolve23(nodeModulesDir, entry);
|
|
18742
19083
|
let entryStat;
|
|
18743
19084
|
try {
|
|
18744
19085
|
entryStat = lstatSync7(entryPath);
|
|
@@ -18760,7 +19101,7 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
18760
19101
|
continue;
|
|
18761
19102
|
}
|
|
18762
19103
|
for (const sub of scopedEntries) {
|
|
18763
|
-
const subPath =
|
|
19104
|
+
const subPath = resolve23(entryPath, sub);
|
|
18764
19105
|
let subStat;
|
|
18765
19106
|
try {
|
|
18766
19107
|
subStat = lstatSync7(subPath);
|
|
@@ -18779,11 +19120,11 @@ function walkNodeModules(projectRoot, warnings) {
|
|
|
18779
19120
|
return candidates;
|
|
18780
19121
|
}
|
|
18781
19122
|
function tryReadAdapterPackage(packageDir, warnings) {
|
|
18782
|
-
const pkgJsonPath =
|
|
18783
|
-
if (!
|
|
19123
|
+
const pkgJsonPath = resolve23(packageDir, "package.json");
|
|
19124
|
+
if (!existsSync27(pkgJsonPath)) return null;
|
|
18784
19125
|
let raw;
|
|
18785
19126
|
try {
|
|
18786
|
-
raw = JSON.parse(
|
|
19127
|
+
raw = JSON.parse(readFileSync24(pkgJsonPath, "utf-8"));
|
|
18787
19128
|
} catch (err) {
|
|
18788
19129
|
warnings.push(
|
|
18789
19130
|
`skipping ${packageDir}: package.json parse failed (${err instanceof Error ? err.message : String(err)})`
|
|
@@ -18917,8 +19258,8 @@ function discoverAdapters(opts) {
|
|
|
18917
19258
|
const localSet = new Set(opts.configLocalPaths);
|
|
18918
19259
|
for (const localPath of opts.configLocalPaths) {
|
|
18919
19260
|
if (seenIds.has(localPath)) continue;
|
|
18920
|
-
const absPath = isAbsolute2(localPath) ? localPath :
|
|
18921
|
-
if (!
|
|
19261
|
+
const absPath = isAbsolute2(localPath) ? localPath : resolve23(opts.projectRoot, localPath);
|
|
19262
|
+
if (!existsSync27(absPath)) {
|
|
18922
19263
|
warnings.push(
|
|
18923
19264
|
`local adapter file not found: ${localPath} (resolved to ${absPath}). Remove via: massu adapters remove-local ${localPath}`
|
|
18924
19265
|
);
|
|
@@ -19000,8 +19341,8 @@ __export(adapters_exports, {
|
|
|
19000
19341
|
runAdaptersResyncLocalFingerprint: () => runAdaptersResyncLocalFingerprint,
|
|
19001
19342
|
runAdaptersSearch: () => runAdaptersSearch
|
|
19002
19343
|
});
|
|
19003
|
-
import { existsSync as
|
|
19004
|
-
import { resolve as
|
|
19344
|
+
import { existsSync as existsSync28, readFileSync as readFileSync25 } from "node:fs";
|
|
19345
|
+
import { resolve as resolve24 } from "node:path";
|
|
19005
19346
|
import { parseDocument } from "yaml";
|
|
19006
19347
|
async function handleAdaptersSubcommand(args2) {
|
|
19007
19348
|
const sub = args2[0];
|
|
@@ -19268,8 +19609,8 @@ function mutateLocalArray(mutator, command) {
|
|
|
19268
19609
|
);
|
|
19269
19610
|
return { exitCode: 2 };
|
|
19270
19611
|
}
|
|
19271
|
-
const yamlPath =
|
|
19272
|
-
if (!
|
|
19612
|
+
const yamlPath = resolve24(projectRoot, "massu.config.yaml");
|
|
19613
|
+
if (!existsSync28(yamlPath)) {
|
|
19273
19614
|
process.stderr.write(
|
|
19274
19615
|
`${command}: massu.config.yaml not found at ${yamlPath}. Run \`massu init\` first.
|
|
19275
19616
|
`
|
|
@@ -19278,7 +19619,7 @@ function mutateLocalArray(mutator, command) {
|
|
|
19278
19619
|
}
|
|
19279
19620
|
let yamlText;
|
|
19280
19621
|
try {
|
|
19281
|
-
yamlText =
|
|
19622
|
+
yamlText = readFileSync25(yamlPath, "utf-8");
|
|
19282
19623
|
} catch (err) {
|
|
19283
19624
|
process.stderr.write(`${command}: failed to read ${yamlPath}: ${err instanceof Error ? err.message : String(err)}
|
|
19284
19625
|
`);
|
|
@@ -19299,7 +19640,7 @@ function mutateLocalArray(mutator, command) {
|
|
|
19299
19640
|
if (next === null) {
|
|
19300
19641
|
return { exitCode: 0 };
|
|
19301
19642
|
}
|
|
19302
|
-
const lockPath =
|
|
19643
|
+
const lockPath = resolve24(projectRoot, ".massu", "adapters-local-mutate.lock");
|
|
19303
19644
|
return withFileLockSync(lockPath, () => {
|
|
19304
19645
|
doc.setIn(["adapters", "local"], next);
|
|
19305
19646
|
const newYaml = doc.toString();
|
|
@@ -19368,23 +19709,23 @@ async function runAdaptersInstall(args2) {
|
|
|
19368
19709
|
`);
|
|
19369
19710
|
return { exitCode: 1 };
|
|
19370
19711
|
}
|
|
19371
|
-
const packageDir =
|
|
19372
|
-
if (!
|
|
19712
|
+
const packageDir = resolve24(projectRoot, "node_modules", ...packageName.split("/"));
|
|
19713
|
+
if (!existsSync28(packageDir)) {
|
|
19373
19714
|
process.stderr.write(
|
|
19374
19715
|
`install: ${packageName} is not installed in node_modules. Run \`npm install ${packageName}\` first.
|
|
19375
19716
|
`
|
|
19376
19717
|
);
|
|
19377
19718
|
return { exitCode: 1 };
|
|
19378
19719
|
}
|
|
19379
|
-
const pkgJsonPath =
|
|
19380
|
-
if (!
|
|
19720
|
+
const pkgJsonPath = resolve24(packageDir, "package.json");
|
|
19721
|
+
if (!existsSync28(pkgJsonPath)) {
|
|
19381
19722
|
process.stderr.write(`install: ${packageName} has no package.json at ${pkgJsonPath}
|
|
19382
19723
|
`);
|
|
19383
19724
|
return { exitCode: 1 };
|
|
19384
19725
|
}
|
|
19385
19726
|
let pkgJson;
|
|
19386
19727
|
try {
|
|
19387
|
-
pkgJson = JSON.parse(
|
|
19728
|
+
pkgJson = JSON.parse(readFileSync25(pkgJsonPath, "utf-8"));
|
|
19388
19729
|
} catch (err) {
|
|
19389
19730
|
process.stderr.write(`install: ${packageName} has malformed package.json: ${err instanceof Error ? err.message : String(err)}
|
|
19390
19731
|
`);
|
|
@@ -19503,8 +19844,8 @@ async function runAdaptersResign(_args) {
|
|
|
19503
19844
|
removeInstalledManifestEntry(name);
|
|
19504
19845
|
continue;
|
|
19505
19846
|
}
|
|
19506
|
-
const packageDir =
|
|
19507
|
-
if (!
|
|
19847
|
+
const packageDir = resolve24(projectRoot, "node_modules", ...name.split("/"));
|
|
19848
|
+
if (!existsSync28(packageDir)) {
|
|
19508
19849
|
removed++;
|
|
19509
19850
|
warnings.push(`${name}@${entry.version}: not present in node_modules \u2014 REMOVED from sidecar`);
|
|
19510
19851
|
removeInstalledManifestEntry(name);
|
|
@@ -19603,10 +19944,10 @@ var init_sql_table_names = __esm({
|
|
|
19603
19944
|
// src/db.ts
|
|
19604
19945
|
import Database2 from "better-sqlite3";
|
|
19605
19946
|
import { dirname as dirname14, join as join13 } from "path";
|
|
19606
|
-
import { existsSync as
|
|
19947
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync12, readdirSync as readdirSync15, statSync as statSync11 } from "fs";
|
|
19607
19948
|
function getCodeGraphDb() {
|
|
19608
19949
|
const dbPath = getResolvedPaths().codegraphDbPath;
|
|
19609
|
-
if (!
|
|
19950
|
+
if (!existsSync29(dbPath)) {
|
|
19610
19951
|
throw new CodegraphDbNotInitializedError(dbPath);
|
|
19611
19952
|
}
|
|
19612
19953
|
const db = new Database2(dbPath, { readonly: true });
|
|
@@ -19616,8 +19957,8 @@ function getCodeGraphDb() {
|
|
|
19616
19957
|
function getDataDb() {
|
|
19617
19958
|
const dbPath = getResolvedPaths().dataDbPath;
|
|
19618
19959
|
const dir = dirname14(dbPath);
|
|
19619
|
-
if (!
|
|
19620
|
-
|
|
19960
|
+
if (!existsSync29(dir)) {
|
|
19961
|
+
mkdirSync12(dir, { recursive: true });
|
|
19621
19962
|
}
|
|
19622
19963
|
const db = new Database2(dbPath);
|
|
19623
19964
|
db.pragma("journal_mode = WAL");
|
|
@@ -19926,12 +20267,12 @@ var init_db = __esm({
|
|
|
19926
20267
|
// src/knowledge-db.ts
|
|
19927
20268
|
import Database3 from "better-sqlite3";
|
|
19928
20269
|
import { dirname as dirname15 } from "path";
|
|
19929
|
-
import { existsSync as
|
|
20270
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync13 } from "fs";
|
|
19930
20271
|
function getKnowledgeDb() {
|
|
19931
20272
|
const dbPath = getResolvedPaths().knowledgeDbPath;
|
|
19932
20273
|
const dir = dirname15(dbPath);
|
|
19933
|
-
if (!
|
|
19934
|
-
|
|
20274
|
+
if (!existsSync30(dir)) {
|
|
20275
|
+
mkdirSync13(dir, { recursive: true });
|
|
19935
20276
|
}
|
|
19936
20277
|
const db = new Database3(dbPath);
|
|
19937
20278
|
db.pragma("journal_mode = WAL");
|
|
@@ -20102,10 +20443,10 @@ var init_knowledge_db = __esm({
|
|
|
20102
20443
|
});
|
|
20103
20444
|
|
|
20104
20445
|
// src/security-utils.ts
|
|
20105
|
-
import { resolve as
|
|
20446
|
+
import { resolve as resolve25, normalize } from "path";
|
|
20106
20447
|
function ensureWithinRoot(filePath, projectRoot) {
|
|
20107
|
-
const resolvedRoot =
|
|
20108
|
-
const resolvedPath =
|
|
20448
|
+
const resolvedRoot = resolve25(projectRoot);
|
|
20449
|
+
const resolvedPath = resolve25(resolvedRoot, filePath);
|
|
20109
20450
|
const normalizedPath = normalize(resolvedPath);
|
|
20110
20451
|
const normalizedRoot = normalize(resolvedRoot);
|
|
20111
20452
|
if (!normalizedPath.startsWith(normalizedRoot + "/") && normalizedPath !== normalizedRoot) {
|
|
@@ -20178,8 +20519,8 @@ var init_rules = __esm({
|
|
|
20178
20519
|
});
|
|
20179
20520
|
|
|
20180
20521
|
// src/import-resolver.ts
|
|
20181
|
-
import { readFileSync as
|
|
20182
|
-
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";
|
|
20183
20524
|
function parseImports(source) {
|
|
20184
20525
|
const imports = [];
|
|
20185
20526
|
const lines = source.split("\n");
|
|
@@ -20235,23 +20576,23 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
20235
20576
|
let basePath;
|
|
20236
20577
|
if (specifier.startsWith("@/")) {
|
|
20237
20578
|
const paths = getResolvedPaths();
|
|
20238
|
-
basePath =
|
|
20579
|
+
basePath = resolve26(paths.pathAlias["@"] ?? paths.srcDir, specifier.slice(2));
|
|
20239
20580
|
} else {
|
|
20240
|
-
basePath =
|
|
20581
|
+
basePath = resolve26(dirname16(fromFile), specifier);
|
|
20241
20582
|
}
|
|
20242
|
-
if (
|
|
20583
|
+
if (existsSync31(basePath) && !isDirectory(basePath)) {
|
|
20243
20584
|
return toRelative(basePath);
|
|
20244
20585
|
}
|
|
20245
20586
|
const resolvedPaths = getResolvedPaths();
|
|
20246
20587
|
for (const ext of resolvedPaths.extensions) {
|
|
20247
20588
|
const withExt = basePath + ext;
|
|
20248
|
-
if (
|
|
20589
|
+
if (existsSync31(withExt)) {
|
|
20249
20590
|
return toRelative(withExt);
|
|
20250
20591
|
}
|
|
20251
20592
|
}
|
|
20252
20593
|
for (const indexFile of resolvedPaths.indexFiles) {
|
|
20253
20594
|
const indexPath = join14(basePath, indexFile);
|
|
20254
|
-
if (
|
|
20595
|
+
if (existsSync31(indexPath)) {
|
|
20255
20596
|
return toRelative(indexPath);
|
|
20256
20597
|
}
|
|
20257
20598
|
}
|
|
@@ -20287,11 +20628,11 @@ function buildImportIndex(dataDb, codegraphDb) {
|
|
|
20287
20628
|
const batchSize = 500;
|
|
20288
20629
|
let batch = [];
|
|
20289
20630
|
for (const file of files) {
|
|
20290
|
-
const absPath = ensureWithinRoot(
|
|
20291
|
-
if (!
|
|
20631
|
+
const absPath = ensureWithinRoot(resolve26(projectRoot, file.path), projectRoot);
|
|
20632
|
+
if (!existsSync31(absPath)) continue;
|
|
20292
20633
|
let source;
|
|
20293
20634
|
try {
|
|
20294
|
-
source =
|
|
20635
|
+
source = readFileSync26(absPath, "utf-8");
|
|
20295
20636
|
} catch {
|
|
20296
20637
|
continue;
|
|
20297
20638
|
}
|
|
@@ -20328,15 +20669,15 @@ var init_import_resolver = __esm({
|
|
|
20328
20669
|
});
|
|
20329
20670
|
|
|
20330
20671
|
// src/trpc-index.ts
|
|
20331
|
-
import { readFileSync as
|
|
20332
|
-
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";
|
|
20333
20674
|
function parseRootRouter() {
|
|
20334
20675
|
const paths = getResolvedPaths();
|
|
20335
20676
|
const rootPath = paths.rootRouterPath;
|
|
20336
|
-
if (!
|
|
20677
|
+
if (!existsSync32(rootPath)) {
|
|
20337
20678
|
throw new Error(`Root router not found at ${rootPath}`);
|
|
20338
20679
|
}
|
|
20339
|
-
const source =
|
|
20680
|
+
const source = readFileSync27(rootPath, "utf-8");
|
|
20340
20681
|
const mappings = [];
|
|
20341
20682
|
const importMap = /* @__PURE__ */ new Map();
|
|
20342
20683
|
const importRegex = /import\s+\{[^}]*?(\w+Router)[^}]*\}\s+from\s+['"]\.\/routers\/([^'"]+)['"]/g;
|
|
@@ -20344,16 +20685,16 @@ function parseRootRouter() {
|
|
|
20344
20685
|
while ((match = importRegex.exec(source)) !== null) {
|
|
20345
20686
|
const variable = match[1];
|
|
20346
20687
|
let filePath = match[2];
|
|
20347
|
-
const fullPath =
|
|
20688
|
+
const fullPath = resolve27(paths.routersDir, filePath);
|
|
20348
20689
|
for (const ext of [".ts", ".tsx", ""]) {
|
|
20349
20690
|
const candidate = fullPath + ext;
|
|
20350
20691
|
const routersRelPath = getConfig().paths.routers ?? "src/server/api/routers";
|
|
20351
|
-
if (
|
|
20692
|
+
if (existsSync32(candidate)) {
|
|
20352
20693
|
filePath = routersRelPath + "/" + filePath + ext;
|
|
20353
20694
|
break;
|
|
20354
20695
|
}
|
|
20355
20696
|
const indexCandidate = join15(fullPath, "index.ts");
|
|
20356
|
-
if (
|
|
20697
|
+
if (existsSync32(indexCandidate)) {
|
|
20357
20698
|
filePath = routersRelPath + "/" + filePath + "/index.ts";
|
|
20358
20699
|
break;
|
|
20359
20700
|
}
|
|
@@ -20372,9 +20713,9 @@ function parseRootRouter() {
|
|
|
20372
20713
|
return mappings;
|
|
20373
20714
|
}
|
|
20374
20715
|
function extractProcedures(routerFilePath) {
|
|
20375
|
-
const absPath =
|
|
20376
|
-
if (!
|
|
20377
|
-
const source =
|
|
20716
|
+
const absPath = resolve27(getProjectRoot(), routerFilePath);
|
|
20717
|
+
if (!existsSync32(absPath)) return [];
|
|
20718
|
+
const source = readFileSync27(absPath, "utf-8");
|
|
20378
20719
|
const procedures = [];
|
|
20379
20720
|
const seen = /* @__PURE__ */ new Set();
|
|
20380
20721
|
const procRegex = /(\w+)\s*:\s*(protected|public)Procedure/g;
|
|
@@ -20397,13 +20738,13 @@ function findUICallSites(routerKey, procedureName) {
|
|
|
20397
20738
|
const root = getProjectRoot();
|
|
20398
20739
|
const src = config.paths.source;
|
|
20399
20740
|
const searchDirs = [
|
|
20400
|
-
|
|
20401
|
-
|
|
20402
|
-
|
|
20741
|
+
resolve27(root, config.paths.pages ?? src + "/app"),
|
|
20742
|
+
resolve27(root, config.paths.components ?? src + "/components"),
|
|
20743
|
+
resolve27(root, config.paths.hooks ?? src + "/hooks")
|
|
20403
20744
|
];
|
|
20404
20745
|
const searchPattern = `api.${routerKey}.${procedureName}`;
|
|
20405
20746
|
for (const dir of searchDirs) {
|
|
20406
|
-
if (!
|
|
20747
|
+
if (!existsSync32(dir)) continue;
|
|
20407
20748
|
searchDirectory(dir, searchPattern, callSites);
|
|
20408
20749
|
}
|
|
20409
20750
|
return callSites;
|
|
@@ -20417,7 +20758,7 @@ function searchDirectory(dir, pattern, results) {
|
|
|
20417
20758
|
searchDirectory(fullPath, pattern, results);
|
|
20418
20759
|
} else if (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) {
|
|
20419
20760
|
try {
|
|
20420
|
-
const source =
|
|
20761
|
+
const source = readFileSync27(fullPath, "utf-8");
|
|
20421
20762
|
const lines = source.split("\n");
|
|
20422
20763
|
for (let i = 0; i < lines.length; i++) {
|
|
20423
20764
|
if (lines[i].includes(pattern)) {
|
|
@@ -20481,8 +20822,8 @@ var init_trpc_index = __esm({
|
|
|
20481
20822
|
});
|
|
20482
20823
|
|
|
20483
20824
|
// src/page-deps.ts
|
|
20484
|
-
import { readFileSync as
|
|
20485
|
-
import { resolve as
|
|
20825
|
+
import { readFileSync as readFileSync28, existsSync as existsSync33 } from "fs";
|
|
20826
|
+
import { resolve as resolve28 } from "path";
|
|
20486
20827
|
function deriveRoute(pageFile) {
|
|
20487
20828
|
let route = pageFile.replace(/^src\/app/, "").replace(/\/page\.tsx?$/, "").replace(/\/page\.jsx?$/, "");
|
|
20488
20829
|
return route || "/";
|
|
@@ -20520,10 +20861,10 @@ function findRouterCalls(files) {
|
|
|
20520
20861
|
const routers = /* @__PURE__ */ new Set();
|
|
20521
20862
|
const projectRoot = getProjectRoot();
|
|
20522
20863
|
for (const file of files) {
|
|
20523
|
-
const absPath = ensureWithinRoot(
|
|
20524
|
-
if (!
|
|
20864
|
+
const absPath = ensureWithinRoot(resolve28(projectRoot, file), projectRoot);
|
|
20865
|
+
if (!existsSync33(absPath)) continue;
|
|
20525
20866
|
try {
|
|
20526
|
-
const source =
|
|
20867
|
+
const source = readFileSync28(absPath, "utf-8");
|
|
20527
20868
|
const apiCallRegex = /api\.(\w+)\.\w+/g;
|
|
20528
20869
|
let match;
|
|
20529
20870
|
while ((match = apiCallRegex.exec(source)) !== null) {
|
|
@@ -20541,10 +20882,10 @@ function findTablesFromRouters(routerNames, dataDb) {
|
|
|
20541
20882
|
`SELECT DISTINCT router_file FROM ${t("trpc_procedures")} WHERE router_name = ? LIMIT 10000`
|
|
20542
20883
|
).all(routerName);
|
|
20543
20884
|
for (const proc of procs) {
|
|
20544
|
-
const absPath = ensureWithinRoot(
|
|
20545
|
-
if (!
|
|
20885
|
+
const absPath = ensureWithinRoot(resolve28(getProjectRoot(), proc.router_file), getProjectRoot());
|
|
20886
|
+
if (!existsSync33(absPath)) continue;
|
|
20546
20887
|
try {
|
|
20547
|
-
const source =
|
|
20888
|
+
const source = readFileSync28(absPath, "utf-8");
|
|
20548
20889
|
const dbPattern = getConfig().dbAccessPattern ?? "ctx.db.{table}";
|
|
20549
20890
|
const regexStr = dbPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{table\\}", "(\\w+)");
|
|
20550
20891
|
const tableRegex = new RegExp(regexStr + "\\.", "g");
|
|
@@ -20816,14 +21157,14 @@ var init_domains = __esm({
|
|
|
20816
21157
|
});
|
|
20817
21158
|
|
|
20818
21159
|
// src/schema-mapper.ts
|
|
20819
|
-
import { readFileSync as
|
|
21160
|
+
import { readFileSync as readFileSync29, existsSync as existsSync34, readdirSync as readdirSync17 } from "fs";
|
|
20820
21161
|
import { join as join16 } from "path";
|
|
20821
21162
|
function parsePrismaSchema() {
|
|
20822
21163
|
const schemaPath = getResolvedPaths().prismaSchemaPath;
|
|
20823
|
-
if (!
|
|
21164
|
+
if (!existsSync34(schemaPath)) {
|
|
20824
21165
|
throw new Error(`Prisma schema not found at ${schemaPath}`);
|
|
20825
21166
|
}
|
|
20826
|
-
const source =
|
|
21167
|
+
const source = readFileSync29(schemaPath, "utf-8");
|
|
20827
21168
|
const models = [];
|
|
20828
21169
|
const sourceLines = source.split("\n");
|
|
20829
21170
|
let i = 0;
|
|
@@ -20881,7 +21222,7 @@ function toSnakeCase(str) {
|
|
|
20881
21222
|
function findColumnUsageInRouters(tableName) {
|
|
20882
21223
|
const usage = /* @__PURE__ */ new Map();
|
|
20883
21224
|
const routersDir = getResolvedPaths().routersDir;
|
|
20884
|
-
if (!
|
|
21225
|
+
if (!existsSync34(routersDir)) return usage;
|
|
20885
21226
|
scanDirectory(routersDir, tableName, usage);
|
|
20886
21227
|
return usage;
|
|
20887
21228
|
}
|
|
@@ -20898,7 +21239,7 @@ function scanDirectory(dir, tableName, usage) {
|
|
|
20898
21239
|
}
|
|
20899
21240
|
function scanFile(absPath, tableName, usage) {
|
|
20900
21241
|
try {
|
|
20901
|
-
const source =
|
|
21242
|
+
const source = readFileSync29(absPath, "utf-8");
|
|
20902
21243
|
if (!source.includes(tableName)) return;
|
|
20903
21244
|
const relPath = absPath.slice(getProjectRoot().length + 1);
|
|
20904
21245
|
const lines = source.split("\n");
|
|
@@ -20943,7 +21284,7 @@ function detectMismatches(models) {
|
|
|
20943
21284
|
}
|
|
20944
21285
|
function findFilesUsingColumn(dir, column, tableName) {
|
|
20945
21286
|
const result = [];
|
|
20946
|
-
if (!
|
|
21287
|
+
if (!existsSync34(dir)) return result;
|
|
20947
21288
|
const entries = readdirSync17(dir, { withFileTypes: true });
|
|
20948
21289
|
for (const entry of entries) {
|
|
20949
21290
|
const fullPath = join16(dir, entry.name);
|
|
@@ -20951,7 +21292,7 @@ function findFilesUsingColumn(dir, column, tableName) {
|
|
|
20951
21292
|
result.push(...findFilesUsingColumn(fullPath, column, tableName));
|
|
20952
21293
|
} else if (entry.name.endsWith(".ts")) {
|
|
20953
21294
|
try {
|
|
20954
|
-
const source =
|
|
21295
|
+
const source = readFileSync29(fullPath, "utf-8");
|
|
20955
21296
|
if (source.includes(tableName) && source.includes(column)) {
|
|
20956
21297
|
result.push(fullPath.slice(getProjectRoot().length + 1));
|
|
20957
21298
|
}
|
|
@@ -21096,12 +21437,12 @@ var init_import_parser = __esm({
|
|
|
21096
21437
|
});
|
|
21097
21438
|
|
|
21098
21439
|
// src/python/import-resolver.ts
|
|
21099
|
-
import { readFileSync as
|
|
21100
|
-
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";
|
|
21101
21442
|
function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
21102
21443
|
const projectRoot = getProjectRoot();
|
|
21103
21444
|
if (level > 0) {
|
|
21104
|
-
let baseDir = dirname17(
|
|
21445
|
+
let baseDir = dirname17(resolve30(projectRoot, fromFile));
|
|
21105
21446
|
for (let i = 1; i < level; i++) {
|
|
21106
21447
|
baseDir = dirname17(baseDir);
|
|
21107
21448
|
}
|
|
@@ -21113,17 +21454,17 @@ function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
|
21113
21454
|
return tryResolvePythonPath(baseDir, projectRoot);
|
|
21114
21455
|
}
|
|
21115
21456
|
const parts = module.split(".");
|
|
21116
|
-
const candidate = join17(
|
|
21457
|
+
const candidate = join17(resolve30(projectRoot, pythonRoot), ...parts);
|
|
21117
21458
|
return tryResolvePythonPath(candidate, projectRoot);
|
|
21118
21459
|
}
|
|
21119
21460
|
function tryResolvePythonPath(basePath, projectRoot) {
|
|
21120
|
-
if (
|
|
21461
|
+
if (existsSync35(basePath + ".py")) {
|
|
21121
21462
|
return relative6(projectRoot, basePath + ".py");
|
|
21122
21463
|
}
|
|
21123
|
-
if (
|
|
21464
|
+
if (existsSync35(join17(basePath, "__init__.py"))) {
|
|
21124
21465
|
return relative6(projectRoot, join17(basePath, "__init__.py"));
|
|
21125
21466
|
}
|
|
21126
|
-
if (basePath.endsWith(".py") &&
|
|
21467
|
+
if (basePath.endsWith(".py") && existsSync35(basePath)) {
|
|
21127
21468
|
return relative6(projectRoot, basePath);
|
|
21128
21469
|
}
|
|
21129
21470
|
return null;
|
|
@@ -21146,7 +21487,7 @@ function walkPythonFiles(dir, excludeDirs) {
|
|
|
21146
21487
|
}
|
|
21147
21488
|
function buildPythonImportIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
21148
21489
|
const projectRoot = getProjectRoot();
|
|
21149
|
-
const absRoot =
|
|
21490
|
+
const absRoot = resolve30(projectRoot, pythonRoot);
|
|
21150
21491
|
dataDb.exec(`DELETE FROM ${t("py_imports")}`);
|
|
21151
21492
|
const insertStmt = dataDb.prepare(
|
|
21152
21493
|
`INSERT INTO ${t("py_imports")} (source_file, target_file, import_type, imported_names, line) VALUES (?, ?, ?, ?, ?)`
|
|
@@ -21163,7 +21504,7 @@ function buildPythonImportIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__"
|
|
|
21163
21504
|
const relFile = relative6(projectRoot, absFile);
|
|
21164
21505
|
let source;
|
|
21165
21506
|
try {
|
|
21166
|
-
source =
|
|
21507
|
+
source = readFileSync30(absFile, "utf-8");
|
|
21167
21508
|
} catch {
|
|
21168
21509
|
continue;
|
|
21169
21510
|
}
|
|
@@ -21430,7 +21771,7 @@ var init_route_parser = __esm({
|
|
|
21430
21771
|
});
|
|
21431
21772
|
|
|
21432
21773
|
// src/python/route-indexer.ts
|
|
21433
|
-
import { readFileSync as
|
|
21774
|
+
import { readFileSync as readFileSync31, readdirSync as readdirSync19 } from "fs";
|
|
21434
21775
|
import { join as join18, relative as relative7 } from "path";
|
|
21435
21776
|
function walkPyFiles(dir, excludeDirs) {
|
|
21436
21777
|
const files = [];
|
|
@@ -21463,7 +21804,7 @@ function buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__",
|
|
|
21463
21804
|
const relFile = relative7(projectRoot, absFile);
|
|
21464
21805
|
let source;
|
|
21465
21806
|
try {
|
|
21466
|
-
source =
|
|
21807
|
+
source = readFileSync31(absFile, "utf-8");
|
|
21467
21808
|
} catch {
|
|
21468
21809
|
continue;
|
|
21469
21810
|
}
|
|
@@ -21675,7 +22016,7 @@ var init_model_parser = __esm({
|
|
|
21675
22016
|
});
|
|
21676
22017
|
|
|
21677
22018
|
// src/python/model-indexer.ts
|
|
21678
|
-
import { readFileSync as
|
|
22019
|
+
import { readFileSync as readFileSync32, readdirSync as readdirSync20 } from "fs";
|
|
21679
22020
|
import { join as join19, relative as relative8 } from "path";
|
|
21680
22021
|
function walkPyFiles2(dir, excludeDirs) {
|
|
21681
22022
|
const files = [];
|
|
@@ -21711,7 +22052,7 @@ function buildPythonModelIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__",
|
|
|
21711
22052
|
const relFile = relative8(projectRoot, absFile);
|
|
21712
22053
|
let source;
|
|
21713
22054
|
try {
|
|
21714
|
-
source =
|
|
22055
|
+
source = readFileSync32(absFile, "utf-8");
|
|
21715
22056
|
} catch {
|
|
21716
22057
|
continue;
|
|
21717
22058
|
}
|
|
@@ -21972,7 +22313,7 @@ var init_migration_parser = __esm({
|
|
|
21972
22313
|
});
|
|
21973
22314
|
|
|
21974
22315
|
// src/python/migration-indexer.ts
|
|
21975
|
-
import { readFileSync as
|
|
22316
|
+
import { readFileSync as readFileSync33, readdirSync as readdirSync21 } from "fs";
|
|
21976
22317
|
import { join as join20, relative as relative9 } from "path";
|
|
21977
22318
|
function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
21978
22319
|
const projectRoot = getProjectRoot();
|
|
@@ -21998,7 +22339,7 @@ function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
|
21998
22339
|
for (const absFile of files) {
|
|
21999
22340
|
let source;
|
|
22000
22341
|
try {
|
|
22001
|
-
source =
|
|
22342
|
+
source = readFileSync33(absFile, "utf-8");
|
|
22002
22343
|
} catch {
|
|
22003
22344
|
continue;
|
|
22004
22345
|
}
|
|
@@ -22033,7 +22374,7 @@ var init_migration_indexer = __esm({
|
|
|
22033
22374
|
});
|
|
22034
22375
|
|
|
22035
22376
|
// src/python/coupling-detector.ts
|
|
22036
|
-
import { readFileSync as
|
|
22377
|
+
import { readFileSync as readFileSync34, readdirSync as readdirSync22 } from "fs";
|
|
22037
22378
|
import { join as join21, relative as relative10 } from "path";
|
|
22038
22379
|
function buildPythonCouplingIndex(dataDb) {
|
|
22039
22380
|
const projectRoot = getProjectRoot();
|
|
@@ -22070,7 +22411,7 @@ function buildPythonCouplingIndex(dataDb) {
|
|
|
22070
22411
|
const relFile = relative10(projectRoot, absFile);
|
|
22071
22412
|
let source;
|
|
22072
22413
|
try {
|
|
22073
|
-
source =
|
|
22414
|
+
source = readFileSync34(absFile, "utf-8");
|
|
22074
22415
|
} catch {
|
|
22075
22416
|
continue;
|
|
22076
22417
|
}
|
|
@@ -22476,8 +22817,8 @@ var init_memory_tools = __esm({
|
|
|
22476
22817
|
});
|
|
22477
22818
|
|
|
22478
22819
|
// src/docs-tools.ts
|
|
22479
|
-
import { readFileSync as
|
|
22480
|
-
import { resolve as
|
|
22820
|
+
import { readFileSync as readFileSync35, existsSync as existsSync36 } from "fs";
|
|
22821
|
+
import { resolve as resolve31, basename as basename6 } from "path";
|
|
22481
22822
|
function p3(baseName) {
|
|
22482
22823
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
22483
22824
|
}
|
|
@@ -22532,10 +22873,10 @@ function handleDocsToolCall(name, args2) {
|
|
|
22532
22873
|
}
|
|
22533
22874
|
function loadDocsMap() {
|
|
22534
22875
|
const mapPath = getResolvedPaths().docsMapPath;
|
|
22535
|
-
if (!
|
|
22876
|
+
if (!existsSync36(mapPath)) {
|
|
22536
22877
|
throw new Error(`docs-map.json not found at ${mapPath}`);
|
|
22537
22878
|
}
|
|
22538
|
-
return JSON.parse(
|
|
22879
|
+
return JSON.parse(readFileSync35(mapPath, "utf-8"));
|
|
22539
22880
|
}
|
|
22540
22881
|
function matchesPattern(filePath, pattern) {
|
|
22541
22882
|
const regexStr = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\{\{GLOBSTAR\}\}/g, ".*");
|
|
@@ -22605,13 +22946,13 @@ function extractFrontmatter(content) {
|
|
|
22605
22946
|
}
|
|
22606
22947
|
function extractProcedureNames(routerPath) {
|
|
22607
22948
|
const root = getProjectRoot();
|
|
22608
|
-
const absPath = ensureWithinRoot(
|
|
22609
|
-
if (!
|
|
22610
|
-
const altPath = ensureWithinRoot(
|
|
22611
|
-
if (!
|
|
22612
|
-
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"));
|
|
22613
22954
|
}
|
|
22614
|
-
return extractProcedureNamesFromContent(
|
|
22955
|
+
return extractProcedureNamesFromContent(readFileSync35(absPath, "utf-8"));
|
|
22615
22956
|
}
|
|
22616
22957
|
function extractProcedureNamesFromContent(content) {
|
|
22617
22958
|
const procRegex = /\.(?:query|mutation)\s*\(/g;
|
|
@@ -22651,8 +22992,8 @@ function handleDocsAudit(args2) {
|
|
|
22651
22992
|
for (const [mappingId, triggeringFiles] of affectedMappings) {
|
|
22652
22993
|
const mapping = docsMap.mappings.find((m3) => m3.id === mappingId);
|
|
22653
22994
|
if (!mapping) continue;
|
|
22654
|
-
const helpPagePath = ensureWithinRoot(
|
|
22655
|
-
if (!
|
|
22995
|
+
const helpPagePath = ensureWithinRoot(resolve31(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
22996
|
+
if (!existsSync36(helpPagePath)) {
|
|
22656
22997
|
results.push({
|
|
22657
22998
|
helpPage: mapping.helpPage,
|
|
22658
22999
|
mappingId,
|
|
@@ -22664,7 +23005,7 @@ function handleDocsAudit(args2) {
|
|
|
22664
23005
|
});
|
|
22665
23006
|
continue;
|
|
22666
23007
|
}
|
|
22667
|
-
const content =
|
|
23008
|
+
const content = readFileSync35(helpPagePath, "utf-8");
|
|
22668
23009
|
const sections = extractSections(content);
|
|
22669
23010
|
const frontmatter = extractFrontmatter(content);
|
|
22670
23011
|
const staleReasons = [];
|
|
@@ -22704,9 +23045,9 @@ function handleDocsAudit(args2) {
|
|
|
22704
23045
|
});
|
|
22705
23046
|
for (const [guideName, parentId] of Object.entries(docsMap.userGuideInheritance.examples)) {
|
|
22706
23047
|
if (parentId === mappingId) {
|
|
22707
|
-
const guidePath = ensureWithinRoot(
|
|
22708
|
-
if (
|
|
22709
|
-
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");
|
|
22710
23051
|
const guideFrontmatter = extractFrontmatter(guideContent);
|
|
22711
23052
|
if (!guideFrontmatter?.lastVerified || status === "STALE") {
|
|
22712
23053
|
results.push({
|
|
@@ -22739,14 +23080,14 @@ function handleDocsCoverage(args2) {
|
|
|
22739
23080
|
const gaps = [];
|
|
22740
23081
|
const mappings = filterDomain ? docsMap.mappings.filter((m3) => m3.id === filterDomain) : docsMap.mappings;
|
|
22741
23082
|
for (const mapping of mappings) {
|
|
22742
|
-
const helpPagePath = ensureWithinRoot(
|
|
22743
|
-
const exists =
|
|
23083
|
+
const helpPagePath = ensureWithinRoot(resolve31(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
23084
|
+
const exists = existsSync36(helpPagePath);
|
|
22744
23085
|
let hasContent = false;
|
|
22745
23086
|
let lineCount = 0;
|
|
22746
23087
|
let lastVerified = null;
|
|
22747
23088
|
let status = null;
|
|
22748
23089
|
if (exists) {
|
|
22749
|
-
const content =
|
|
23090
|
+
const content = readFileSync35(helpPagePath, "utf-8");
|
|
22750
23091
|
lineCount = content.split("\n").length;
|
|
22751
23092
|
hasContent = lineCount > 10;
|
|
22752
23093
|
const frontmatter = extractFrontmatter(content);
|
|
@@ -23087,8 +23428,8 @@ var init_observability_tools = __esm({
|
|
|
23087
23428
|
});
|
|
23088
23429
|
|
|
23089
23430
|
// src/sentinel-db.ts
|
|
23090
|
-
import { existsSync as
|
|
23091
|
-
import { resolve as
|
|
23431
|
+
import { existsSync as existsSync37 } from "fs";
|
|
23432
|
+
import { resolve as resolve32 } from "path";
|
|
23092
23433
|
function parsePortalScope(raw) {
|
|
23093
23434
|
if (!raw) return [];
|
|
23094
23435
|
try {
|
|
@@ -23324,23 +23665,23 @@ function validateFeatures(db, domainFilter) {
|
|
|
23324
23665
|
const missingProcedures = [];
|
|
23325
23666
|
const missingPages = [];
|
|
23326
23667
|
for (const comp of components) {
|
|
23327
|
-
const absPath =
|
|
23328
|
-
if (!
|
|
23668
|
+
const absPath = resolve32(PROJECT_ROOT, comp.component_file);
|
|
23669
|
+
if (!existsSync37(absPath)) {
|
|
23329
23670
|
missingComponents.push(comp.component_file);
|
|
23330
23671
|
}
|
|
23331
23672
|
}
|
|
23332
23673
|
for (const proc of procedures) {
|
|
23333
|
-
const routerPath =
|
|
23334
|
-
if (!
|
|
23674
|
+
const routerPath = resolve32(PROJECT_ROOT, `src/server/api/routers/${proc.router_name}.ts`);
|
|
23675
|
+
if (!existsSync37(routerPath)) {
|
|
23335
23676
|
missingProcedures.push({ router: proc.router_name, procedure: proc.procedure_name });
|
|
23336
23677
|
}
|
|
23337
23678
|
}
|
|
23338
23679
|
for (const page of pages) {
|
|
23339
23680
|
const routeToPath = page.page_route.replace(/^\/(portal-[^/]+\/)?/, "src/app/").replace(/\/$/, "") + "/page.tsx";
|
|
23340
|
-
const absPath =
|
|
23341
|
-
if (page.page_route.startsWith("/") && !
|
|
23342
|
-
const altPath =
|
|
23343
|
-
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)) {
|
|
23344
23685
|
missingPages.push(page.page_route);
|
|
23345
23686
|
}
|
|
23346
23687
|
}
|
|
@@ -23866,8 +24207,8 @@ var init_sentinel_tools = __esm({
|
|
|
23866
24207
|
});
|
|
23867
24208
|
|
|
23868
24209
|
// src/sentinel-scanner.ts
|
|
23869
|
-
import { readFileSync as
|
|
23870
|
-
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";
|
|
23871
24212
|
function inferDomain(filePath) {
|
|
23872
24213
|
const domains = getConfig().domains;
|
|
23873
24214
|
const path = filePath.toLowerCase();
|
|
@@ -23998,8 +24339,8 @@ function scanComponentExports(dataDb) {
|
|
|
23998
24339
|
const projectRoot = getProjectRoot();
|
|
23999
24340
|
const componentsBase = config.paths.components ?? config.paths.source + "/components";
|
|
24000
24341
|
const componentDirs = [];
|
|
24001
|
-
const basePath =
|
|
24002
|
-
if (
|
|
24342
|
+
const basePath = resolve33(projectRoot, componentsBase);
|
|
24343
|
+
if (existsSync38(basePath)) {
|
|
24003
24344
|
try {
|
|
24004
24345
|
const entries = readdirSync23(basePath, { withFileTypes: true });
|
|
24005
24346
|
for (const entry of entries) {
|
|
@@ -24011,12 +24352,12 @@ function scanComponentExports(dataDb) {
|
|
|
24011
24352
|
}
|
|
24012
24353
|
}
|
|
24013
24354
|
for (const dir of componentDirs) {
|
|
24014
|
-
const absDir =
|
|
24015
|
-
if (!
|
|
24355
|
+
const absDir = resolve33(projectRoot, dir);
|
|
24356
|
+
if (!existsSync38(absDir)) continue;
|
|
24016
24357
|
const files = walkDir2(absDir).filter((f2) => f2.endsWith(".tsx") || f2.endsWith(".ts"));
|
|
24017
24358
|
for (const file of files) {
|
|
24018
24359
|
const relPath = relative11(projectRoot, file);
|
|
24019
|
-
const source =
|
|
24360
|
+
const source = readFileSync36(file, "utf-8");
|
|
24020
24361
|
const annotations = parseFeatureAnnotations(source);
|
|
24021
24362
|
if (annotations.length > 0) {
|
|
24022
24363
|
for (const ann of annotations) {
|
|
@@ -25059,7 +25400,7 @@ var init_audit_trail = __esm({
|
|
|
25059
25400
|
});
|
|
25060
25401
|
|
|
25061
25402
|
// src/validation-engine.ts
|
|
25062
|
-
import { existsSync as
|
|
25403
|
+
import { existsSync as existsSync39, readFileSync as readFileSync37 } from "fs";
|
|
25063
25404
|
function p10(baseName) {
|
|
25064
25405
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
25065
25406
|
}
|
|
@@ -25090,7 +25431,7 @@ function validateFile(filePath, projectRoot) {
|
|
|
25090
25431
|
});
|
|
25091
25432
|
return checks;
|
|
25092
25433
|
}
|
|
25093
|
-
if (!
|
|
25434
|
+
if (!existsSync39(absPath)) {
|
|
25094
25435
|
checks.push({
|
|
25095
25436
|
name: "file_exists",
|
|
25096
25437
|
severity: "error",
|
|
@@ -25099,7 +25440,7 @@ function validateFile(filePath, projectRoot) {
|
|
|
25099
25440
|
});
|
|
25100
25441
|
return checks;
|
|
25101
25442
|
}
|
|
25102
|
-
const source =
|
|
25443
|
+
const source = readFileSync37(absPath, "utf-8");
|
|
25103
25444
|
const lines = source.split("\n");
|
|
25104
25445
|
if (activeChecks.rule_compliance !== false) {
|
|
25105
25446
|
for (const ruleSet of config.rules) {
|
|
@@ -25545,7 +25886,7 @@ var init_adr_generator = __esm({
|
|
|
25545
25886
|
});
|
|
25546
25887
|
|
|
25547
25888
|
// src/security-scorer.ts
|
|
25548
|
-
import { existsSync as
|
|
25889
|
+
import { existsSync as existsSync40, readFileSync as readFileSync38 } from "fs";
|
|
25549
25890
|
function p12(baseName) {
|
|
25550
25891
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
25551
25892
|
}
|
|
@@ -25569,12 +25910,12 @@ function scoreFileSecurity(filePath, projectRoot) {
|
|
|
25569
25910
|
}]
|
|
25570
25911
|
};
|
|
25571
25912
|
}
|
|
25572
|
-
if (!
|
|
25913
|
+
if (!existsSync40(absPath)) {
|
|
25573
25914
|
return { riskScore: 0, findings: [] };
|
|
25574
25915
|
}
|
|
25575
25916
|
let source;
|
|
25576
25917
|
try {
|
|
25577
|
-
source =
|
|
25918
|
+
source = readFileSync38(absPath, "utf-8");
|
|
25578
25919
|
} catch {
|
|
25579
25920
|
return { riskScore: 0, findings: [] };
|
|
25580
25921
|
}
|
|
@@ -25864,8 +26205,8 @@ var init_security_scorer = __esm({
|
|
|
25864
26205
|
});
|
|
25865
26206
|
|
|
25866
26207
|
// src/dependency-scorer.ts
|
|
25867
|
-
import { existsSync as
|
|
25868
|
-
import { resolve as
|
|
26208
|
+
import { existsSync as existsSync41, readFileSync as readFileSync39 } from "fs";
|
|
26209
|
+
import { resolve as resolve34 } from "path";
|
|
25869
26210
|
function p13(baseName) {
|
|
25870
26211
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
25871
26212
|
}
|
|
@@ -25897,10 +26238,10 @@ function calculateDepRisk(factors) {
|
|
|
25897
26238
|
return Math.min(100, risk);
|
|
25898
26239
|
}
|
|
25899
26240
|
function getInstalledPackages(projectRoot) {
|
|
25900
|
-
const pkgPath =
|
|
25901
|
-
if (!
|
|
26241
|
+
const pkgPath = resolve34(projectRoot, "package.json");
|
|
26242
|
+
if (!existsSync41(pkgPath)) return /* @__PURE__ */ new Map();
|
|
25902
26243
|
try {
|
|
25903
|
-
const pkg = JSON.parse(
|
|
26244
|
+
const pkg = JSON.parse(readFileSync39(pkgPath, "utf-8"));
|
|
25904
26245
|
const packages = /* @__PURE__ */ new Map();
|
|
25905
26246
|
for (const [name, version] of Object.entries(pkg.dependencies ?? {})) {
|
|
25906
26247
|
packages.set(name, version);
|
|
@@ -26506,8 +26847,8 @@ var init_regression_detector = __esm({
|
|
|
26506
26847
|
|
|
26507
26848
|
// src/knowledge-indexer.ts
|
|
26508
26849
|
import { createHash as createHash9 } from "crypto";
|
|
26509
|
-
import { readFileSync as
|
|
26510
|
-
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";
|
|
26511
26852
|
function getKnowledgePaths() {
|
|
26512
26853
|
const resolved = getResolvedPaths();
|
|
26513
26854
|
const config = getConfig();
|
|
@@ -26535,7 +26876,7 @@ function discoverMarkdownFiles(baseDir) {
|
|
|
26535
26876
|
try {
|
|
26536
26877
|
const entries = readdirSync24(dir, { withFileTypes: true });
|
|
26537
26878
|
for (const entry of entries) {
|
|
26538
|
-
const fullPath =
|
|
26879
|
+
const fullPath = resolve35(dir, entry.name);
|
|
26539
26880
|
if (entry.isDirectory()) {
|
|
26540
26881
|
if (entry.name === "archive" && dir.includes("session-state")) continue;
|
|
26541
26882
|
if (entry.name === "archive" && dir.includes("status")) continue;
|
|
@@ -26814,11 +27155,11 @@ function indexAllKnowledge(db) {
|
|
|
26814
27155
|
files.push(...memFiles);
|
|
26815
27156
|
} catch {
|
|
26816
27157
|
}
|
|
26817
|
-
if (
|
|
27158
|
+
if (existsSync42(paths.plansDir)) {
|
|
26818
27159
|
const planFiles = discoverMarkdownFiles(paths.plansDir);
|
|
26819
27160
|
files.push(...planFiles);
|
|
26820
27161
|
}
|
|
26821
|
-
if (
|
|
27162
|
+
if (existsSync42(paths.docsDir)) {
|
|
26822
27163
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
26823
27164
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
26824
27165
|
files.push(...docsFiles);
|
|
@@ -26861,8 +27202,8 @@ function indexAllKnowledge(db) {
|
|
|
26861
27202
|
} catch {
|
|
26862
27203
|
}
|
|
26863
27204
|
for (const filePath of files) {
|
|
26864
|
-
if (!
|
|
26865
|
-
const content =
|
|
27205
|
+
if (!existsSync42(filePath)) continue;
|
|
27206
|
+
const content = readFileSync40(filePath, "utf-8");
|
|
26866
27207
|
const hash = hashContent2(content);
|
|
26867
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);
|
|
26868
27209
|
const category = categorizeFile(filePath);
|
|
@@ -26997,10 +27338,10 @@ function isKnowledgeStale(db) {
|
|
|
26997
27338
|
files.push(...discoverMarkdownFiles(paths.memoryDir));
|
|
26998
27339
|
} catch {
|
|
26999
27340
|
}
|
|
27000
|
-
if (
|
|
27341
|
+
if (existsSync42(paths.plansDir)) {
|
|
27001
27342
|
files.push(...discoverMarkdownFiles(paths.plansDir));
|
|
27002
27343
|
}
|
|
27003
|
-
if (
|
|
27344
|
+
if (existsSync42(paths.docsDir)) {
|
|
27004
27345
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
27005
27346
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
27006
27347
|
files.push(...docsFiles);
|
|
@@ -27029,8 +27370,8 @@ var init_knowledge_indexer = __esm({
|
|
|
27029
27370
|
});
|
|
27030
27371
|
|
|
27031
27372
|
// src/knowledge-tools.ts
|
|
27032
|
-
import { readFileSync as
|
|
27033
|
-
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";
|
|
27034
27375
|
function p16(baseName) {
|
|
27035
27376
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
27036
27377
|
}
|
|
@@ -27769,7 +28110,7 @@ function handleCorrect(db, args2) {
|
|
|
27769
28110
|
if (!wrong || !correction || !rule) {
|
|
27770
28111
|
return text15("Error: wrong, correction, and rule are all required.");
|
|
27771
28112
|
}
|
|
27772
|
-
const correctionsPath =
|
|
28113
|
+
const correctionsPath = resolve36(getResolvedPaths().memoryDir, "corrections.md");
|
|
27773
28114
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
27774
28115
|
const title = rule.slice(0, 60);
|
|
27775
28116
|
const entry = `
|
|
@@ -27782,14 +28123,14 @@ ${crRule ? `- **CR**: ${crRule}
|
|
|
27782
28123
|
`;
|
|
27783
28124
|
let existing = "";
|
|
27784
28125
|
try {
|
|
27785
|
-
existing =
|
|
28126
|
+
existing = readFileSync41(correctionsPath, "utf-8");
|
|
27786
28127
|
} catch {
|
|
27787
28128
|
}
|
|
27788
28129
|
const archiveIdx = existing.indexOf("## Archived");
|
|
27789
28130
|
if (archiveIdx > 0) {
|
|
27790
28131
|
const before = existing.slice(0, archiveIdx);
|
|
27791
28132
|
const after = existing.slice(archiveIdx);
|
|
27792
|
-
|
|
28133
|
+
writeFileSync7(correctionsPath, before + entry + after);
|
|
27793
28134
|
} else {
|
|
27794
28135
|
appendFileSync2(correctionsPath, entry);
|
|
27795
28136
|
}
|
|
@@ -28737,8 +29078,8 @@ var init_framework_supports = __esm({
|
|
|
28737
29078
|
});
|
|
28738
29079
|
|
|
28739
29080
|
// src/tools.ts
|
|
28740
|
-
import { readFileSync as
|
|
28741
|
-
import { resolve as
|
|
29081
|
+
import { readFileSync as readFileSync42, existsSync as existsSync44 } from "fs";
|
|
29082
|
+
import { resolve as resolve37, basename as basename10 } from "path";
|
|
28742
29083
|
function prefix2() {
|
|
28743
29084
|
return getConfig().toolPrefix;
|
|
28744
29085
|
}
|
|
@@ -28773,7 +29114,7 @@ function ensureIndexes(dataDb, codegraphDb, force = false) {
|
|
|
28773
29114
|
if (config.python?.root) {
|
|
28774
29115
|
const pythonRoot = config.python.root;
|
|
28775
29116
|
const excludeDirs = config.python.exclude_dirs || ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"];
|
|
28776
|
-
if (force || isPythonDataStale(dataDb,
|
|
29117
|
+
if (force || isPythonDataStale(dataDb, resolve37(getProjectRoot(), pythonRoot))) {
|
|
28777
29118
|
const pyImports = buildPythonImportIndex(dataDb, pythonRoot, excludeDirs);
|
|
28778
29119
|
results.push(`Python imports: ${pyImports}`);
|
|
28779
29120
|
const pyRoutes = buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs);
|
|
@@ -29156,9 +29497,9 @@ function handleContext(file, dataDb, codegraphDb) {
|
|
|
29156
29497
|
try {
|
|
29157
29498
|
const resolvedPaths = getResolvedPaths();
|
|
29158
29499
|
const root = getProjectRoot();
|
|
29159
|
-
const absFilePath = ensureWithinRoot(
|
|
29160
|
-
if (
|
|
29161
|
-
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);
|
|
29162
29503
|
const keywords = [];
|
|
29163
29504
|
if (fileContent.includes("ctx.db")) keywords.push("database", "schema");
|
|
29164
29505
|
if (fileContent.includes("BigInt") || fileContent.includes("Decimal")) keywords.push("BigInt", "serialization");
|
|
@@ -29595,11 +29936,11 @@ function handleSchema(args2) {
|
|
|
29595
29936
|
lines.push("Checking all column references against Prisma schema...");
|
|
29596
29937
|
lines.push("");
|
|
29597
29938
|
const projectRoot = getProjectRoot();
|
|
29598
|
-
const absPath = ensureWithinRoot(
|
|
29599
|
-
if (!
|
|
29939
|
+
const absPath = ensureWithinRoot(resolve37(projectRoot, file), projectRoot);
|
|
29940
|
+
if (!existsSync44(absPath)) {
|
|
29600
29941
|
return text17(`File not found: ${file}`);
|
|
29601
29942
|
}
|
|
29602
|
-
const source =
|
|
29943
|
+
const source = readFileSync42(absPath, "utf-8");
|
|
29603
29944
|
const config = getConfig();
|
|
29604
29945
|
const dbPattern = config.dbAccessPattern ?? "ctx.db.{table}";
|
|
29605
29946
|
const regexStr = dbPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{table\\}", "(\\w+)");
|
|
@@ -30004,8 +30345,8 @@ var init_server_dispatch = __esm({
|
|
|
30004
30345
|
|
|
30005
30346
|
// src/server.ts
|
|
30006
30347
|
var server_exports = {};
|
|
30007
|
-
import { readFileSync as
|
|
30008
|
-
import { resolve as
|
|
30348
|
+
import { readFileSync as readFileSync43 } from "fs";
|
|
30349
|
+
import { resolve as resolve38, dirname as dirname19 } from "path";
|
|
30009
30350
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
30010
30351
|
function pruneMemoryOnStartup() {
|
|
30011
30352
|
try {
|
|
@@ -30040,7 +30381,7 @@ var init_server = __esm({
|
|
|
30040
30381
|
__dirname5 = dirname19(fileURLToPath5(import.meta.url));
|
|
30041
30382
|
PKG_VERSION = (() => {
|
|
30042
30383
|
try {
|
|
30043
|
-
const pkg = JSON.parse(
|
|
30384
|
+
const pkg = JSON.parse(readFileSync43(resolve38(__dirname5, "..", "package.json"), "utf-8"));
|
|
30044
30385
|
return pkg.version ?? "0.0.0";
|
|
30045
30386
|
} catch {
|
|
30046
30387
|
return "0.0.0";
|
|
@@ -30326,19 +30667,19 @@ var config_upgrade_exports = {};
|
|
|
30326
30667
|
__export(config_upgrade_exports, {
|
|
30327
30668
|
runConfigUpgrade: () => runConfigUpgrade
|
|
30328
30669
|
});
|
|
30329
|
-
import { existsSync as
|
|
30330
|
-
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";
|
|
30331
30672
|
import { parse as parseYaml6 } from "yaml";
|
|
30332
30673
|
async function runConfigUpgrade(opts = {}) {
|
|
30333
30674
|
const cwd = opts.cwd ?? process.cwd();
|
|
30334
|
-
const configPath =
|
|
30675
|
+
const configPath = resolve39(cwd, "massu.config.yaml");
|
|
30335
30676
|
const bakPath = `${configPath}.bak`;
|
|
30336
30677
|
const log = opts.silent ? () => {
|
|
30337
30678
|
} : (s) => process.stdout.write(s);
|
|
30338
30679
|
const err = opts.silent ? () => {
|
|
30339
30680
|
} : (s) => process.stderr.write(s);
|
|
30340
30681
|
if (opts.rollback) {
|
|
30341
|
-
if (!
|
|
30682
|
+
if (!existsSync45(bakPath)) {
|
|
30342
30683
|
const message = `No backup found at ${bakPath}`;
|
|
30343
30684
|
err(message + "\n");
|
|
30344
30685
|
return { exitCode: 1, action: "none", message };
|
|
@@ -30354,14 +30695,14 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
30354
30695
|
return { exitCode: 2, action: "none", message };
|
|
30355
30696
|
}
|
|
30356
30697
|
}
|
|
30357
|
-
if (!
|
|
30698
|
+
if (!existsSync45(configPath)) {
|
|
30358
30699
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
30359
30700
|
err(message + "\n");
|
|
30360
30701
|
return { exitCode: 1, action: "none", message };
|
|
30361
30702
|
}
|
|
30362
30703
|
let existing;
|
|
30363
30704
|
try {
|
|
30364
|
-
const content =
|
|
30705
|
+
const content = readFileSync44(configPath, "utf-8");
|
|
30365
30706
|
const parsed = parseYaml6(content);
|
|
30366
30707
|
if (!parsed || typeof parsed !== "object") {
|
|
30367
30708
|
throw new Error("config is not a YAML object");
|
|
@@ -30384,8 +30725,8 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
30384
30725
|
fingerprint: computeFingerprint(detection)
|
|
30385
30726
|
};
|
|
30386
30727
|
try {
|
|
30387
|
-
const original =
|
|
30388
|
-
|
|
30728
|
+
const original = readFileSync44(configPath, "utf-8");
|
|
30729
|
+
writeFileSync8(bakPath, original, "utf-8");
|
|
30389
30730
|
} catch (e2) {
|
|
30390
30731
|
const message = `Failed to write backup: ${e2 instanceof Error ? e2.message : String(e2)}`;
|
|
30391
30732
|
err(message + "\n");
|
|
@@ -30418,8 +30759,8 @@ var config_check_drift_exports = {};
|
|
|
30418
30759
|
__export(config_check_drift_exports, {
|
|
30419
30760
|
runConfigCheckDrift: () => runConfigCheckDrift
|
|
30420
30761
|
});
|
|
30421
|
-
import { existsSync as
|
|
30422
|
-
import { resolve as
|
|
30762
|
+
import { existsSync as existsSync46, readFileSync as readFileSync45 } from "fs";
|
|
30763
|
+
import { resolve as resolve40 } from "path";
|
|
30423
30764
|
import { parse as parseYaml7 } from "yaml";
|
|
30424
30765
|
function renderChanges(changes) {
|
|
30425
30766
|
if (changes.length === 0) return "(none)\n";
|
|
@@ -30427,12 +30768,12 @@ function renderChanges(changes) {
|
|
|
30427
30768
|
}
|
|
30428
30769
|
async function runConfigCheckDrift(opts = {}) {
|
|
30429
30770
|
const cwd = opts.cwd ?? process.cwd();
|
|
30430
|
-
const configPath =
|
|
30771
|
+
const configPath = resolve40(cwd, "massu.config.yaml");
|
|
30431
30772
|
const log = opts.silent ? () => {
|
|
30432
30773
|
} : (s) => process.stdout.write(s);
|
|
30433
30774
|
const err = opts.silent ? () => {
|
|
30434
30775
|
} : (s) => process.stderr.write(s);
|
|
30435
|
-
if (!
|
|
30776
|
+
if (!existsSync46(configPath)) {
|
|
30436
30777
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
30437
30778
|
err(message + "\n");
|
|
30438
30779
|
return {
|
|
@@ -30446,7 +30787,7 @@ async function runConfigCheckDrift(opts = {}) {
|
|
|
30446
30787
|
}
|
|
30447
30788
|
let config;
|
|
30448
30789
|
try {
|
|
30449
|
-
const content =
|
|
30790
|
+
const content = readFileSync45(configPath, "utf-8");
|
|
30450
30791
|
const parsed = parseYaml7(content);
|
|
30451
30792
|
if (!parsed || typeof parsed !== "object") {
|
|
30452
30793
|
throw new Error("config is not a YAML object");
|
|
@@ -30513,8 +30854,8 @@ var init_config_check_drift = __esm({
|
|
|
30513
30854
|
});
|
|
30514
30855
|
|
|
30515
30856
|
// src/cli.ts
|
|
30516
|
-
import { readFileSync as
|
|
30517
|
-
import { resolve as
|
|
30857
|
+
import { readFileSync as readFileSync46 } from "fs";
|
|
30858
|
+
import { resolve as resolve41, dirname as dirname20 } from "path";
|
|
30518
30859
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
30519
30860
|
var __filename5 = fileURLToPath6(import.meta.url);
|
|
30520
30861
|
var __dirname6 = dirname20(__filename5);
|
|
@@ -30532,6 +30873,16 @@ async function main() {
|
|
|
30532
30873
|
await runDoctor2();
|
|
30533
30874
|
break;
|
|
30534
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
|
+
}
|
|
30535
30886
|
case "install-hooks": {
|
|
30536
30887
|
const { runInstallHooks: runInstallHooks2 } = await Promise.resolve().then(() => (init_install_hooks(), install_hooks_exports));
|
|
30537
30888
|
await runInstallHooks2();
|
|
@@ -30555,7 +30906,7 @@ async function main() {
|
|
|
30555
30906
|
return;
|
|
30556
30907
|
}
|
|
30557
30908
|
case "license": {
|
|
30558
|
-
const { handleLicenseSubcommand: handleLicenseSubcommand2 } = await Promise.resolve().then(() => (init_license2(),
|
|
30909
|
+
const { handleLicenseSubcommand: handleLicenseSubcommand2 } = await Promise.resolve().then(() => (init_license2(), license_exports2));
|
|
30559
30910
|
const result = await handleLicenseSubcommand2(args.slice(1));
|
|
30560
30911
|
process.exit(result.exitCode);
|
|
30561
30912
|
return;
|
|
@@ -30692,6 +31043,10 @@ Usage:
|
|
|
30692
31043
|
Commands:
|
|
30693
31044
|
init Set up Massu AI in your project (one command, full setup)
|
|
30694
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
|
|
30695
31050
|
install-hooks Install/update Claude Code hooks
|
|
30696
31051
|
install-commands Install/update slash commands (use --skip-permissions to opt out of MCP allowlist seeding)
|
|
30697
31052
|
show-template Print the resolved variant of a bundled template (e.g. for diffs)
|
|
@@ -30742,7 +31097,7 @@ Examples:
|
|
|
30742
31097
|
}
|
|
30743
31098
|
function printVersion() {
|
|
30744
31099
|
try {
|
|
30745
|
-
const pkg = JSON.parse(
|
|
31100
|
+
const pkg = JSON.parse(readFileSync46(resolve41(__dirname6, "../package.json"), "utf-8"));
|
|
30746
31101
|
console.log(`massu v${pkg.version}`);
|
|
30747
31102
|
} catch {
|
|
30748
31103
|
console.log("massu v0.1.0");
|