@massu/core 1.15.1 → 1.15.2

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