@massu/core 0.1.1 → 0.4.0

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.
Files changed (151) hide show
  1. package/commands/_shared-preamble.md +76 -0
  2. package/commands/massu-audit-deps.md +211 -0
  3. package/commands/massu-changelog.md +174 -0
  4. package/commands/massu-cleanup.md +315 -0
  5. package/commands/massu-commit.md +481 -0
  6. package/commands/massu-create-plan.md +752 -0
  7. package/commands/massu-dead-code.md +131 -0
  8. package/commands/massu-debug.md +484 -0
  9. package/commands/massu-deploy.md +91 -0
  10. package/commands/massu-deps.md +374 -0
  11. package/commands/massu-doc-gen.md +279 -0
  12. package/commands/massu-docs.md +364 -0
  13. package/commands/massu-estimate.md +313 -0
  14. package/commands/massu-golden-path.md +973 -0
  15. package/commands/massu-guide.md +167 -0
  16. package/commands/massu-hotfix.md +480 -0
  17. package/commands/massu-loop-playwright.md +837 -0
  18. package/commands/massu-loop.md +775 -0
  19. package/commands/massu-new-feature.md +511 -0
  20. package/commands/massu-parity.md +214 -0
  21. package/commands/massu-plan.md +456 -0
  22. package/commands/massu-push-light.md +207 -0
  23. package/commands/massu-push.md +434 -0
  24. package/commands/massu-refactor.md +410 -0
  25. package/commands/massu-release.md +363 -0
  26. package/commands/massu-review.md +238 -0
  27. package/commands/massu-simplify.md +281 -0
  28. package/commands/massu-status.md +278 -0
  29. package/commands/massu-tdd.md +201 -0
  30. package/commands/massu-test.md +516 -0
  31. package/commands/massu-verify-playwright.md +281 -0
  32. package/commands/massu-verify.md +667 -0
  33. package/dist/cli.js +7772 -3140
  34. package/dist/hooks/cost-tracker.js +103 -40
  35. package/dist/hooks/post-edit-context.js +74 -8
  36. package/dist/hooks/post-tool-use.js +268 -106
  37. package/dist/hooks/pre-compact.js +167 -43
  38. package/dist/hooks/pre-delete-check.js +159 -42
  39. package/dist/hooks/quality-event.js +103 -40
  40. package/dist/hooks/security-gate.js +29 -0
  41. package/dist/hooks/session-end.js +143 -84
  42. package/dist/hooks/session-start.js +186 -49
  43. package/dist/hooks/user-prompt.js +189 -43
  44. package/package.json +10 -15
  45. package/src/adr-generator.ts +9 -2
  46. package/src/analytics.ts +9 -3
  47. package/src/audit-trail.ts +10 -3
  48. package/src/backfill-sessions.ts +5 -4
  49. package/src/cli.ts +6 -0
  50. package/src/cloud-sync.ts +14 -18
  51. package/src/commands/doctor.ts +193 -6
  52. package/src/commands/init.ts +230 -5
  53. package/src/commands/install-commands.ts +137 -0
  54. package/src/config.ts +68 -2
  55. package/src/cost-tracker.ts +11 -6
  56. package/src/db.ts +115 -2
  57. package/src/dependency-scorer.ts +9 -2
  58. package/src/docs-tools.ts +21 -16
  59. package/src/hooks/post-edit-context.ts +4 -4
  60. package/src/hooks/post-tool-use.ts +130 -0
  61. package/src/hooks/pre-compact.ts +23 -1
  62. package/src/hooks/pre-delete-check.ts +92 -4
  63. package/src/hooks/security-gate.ts +32 -0
  64. package/src/hooks/session-end.ts +3 -3
  65. package/src/hooks/session-start.ts +99 -6
  66. package/src/hooks/user-prompt.ts +46 -1
  67. package/src/import-resolver.ts +2 -1
  68. package/src/knowledge-db.ts +169 -0
  69. package/src/knowledge-indexer.ts +704 -0
  70. package/src/knowledge-tools.ts +1413 -0
  71. package/src/license.ts +482 -0
  72. package/src/memory-db.ts +1364 -23
  73. package/src/memory-tools.ts +14 -15
  74. package/src/observability-tools.ts +13 -2
  75. package/src/observation-extractor.ts +11 -4
  76. package/src/page-deps.ts +3 -2
  77. package/src/prompt-analyzer.ts +9 -2
  78. package/src/python/coupling-detector.ts +124 -0
  79. package/src/python/domain-enforcer.ts +83 -0
  80. package/src/python/impact-analyzer.ts +95 -0
  81. package/src/python/import-parser.ts +244 -0
  82. package/src/python/import-resolver.ts +135 -0
  83. package/src/python/migration-indexer.ts +115 -0
  84. package/src/python/migration-parser.ts +332 -0
  85. package/src/python/model-indexer.ts +70 -0
  86. package/src/python/model-parser.ts +279 -0
  87. package/src/python/route-indexer.ts +58 -0
  88. package/src/python/route-parser.ts +317 -0
  89. package/src/python-tools.ts +629 -0
  90. package/src/regression-detector.ts +9 -3
  91. package/src/security-scorer.ts +9 -2
  92. package/src/sentinel-db.ts +45 -89
  93. package/src/sentinel-tools.ts +8 -11
  94. package/src/server.ts +29 -7
  95. package/src/session-archiver.ts +4 -5
  96. package/src/team-knowledge.ts +9 -2
  97. package/src/tools.ts +1032 -44
  98. package/src/validate-features-runner.ts +0 -1
  99. package/src/validation-engine.ts +9 -2
  100. package/README.md +0 -40
  101. package/dist/server.js +0 -7008
  102. package/src/__tests__/adr-generator.test.ts +0 -260
  103. package/src/__tests__/analytics.test.ts +0 -282
  104. package/src/__tests__/audit-trail.test.ts +0 -382
  105. package/src/__tests__/backfill-sessions.test.ts +0 -690
  106. package/src/__tests__/cli.test.ts +0 -290
  107. package/src/__tests__/cloud-sync.test.ts +0 -261
  108. package/src/__tests__/config-sections.test.ts +0 -359
  109. package/src/__tests__/config.test.ts +0 -732
  110. package/src/__tests__/cost-tracker.test.ts +0 -348
  111. package/src/__tests__/db.test.ts +0 -177
  112. package/src/__tests__/dependency-scorer.test.ts +0 -325
  113. package/src/__tests__/docs-integration.test.ts +0 -178
  114. package/src/__tests__/docs-tools.test.ts +0 -199
  115. package/src/__tests__/domains.test.ts +0 -236
  116. package/src/__tests__/hooks.test.ts +0 -221
  117. package/src/__tests__/import-resolver.test.ts +0 -95
  118. package/src/__tests__/integration/path-traversal.test.ts +0 -134
  119. package/src/__tests__/integration/pricing-consistency.test.ts +0 -88
  120. package/src/__tests__/integration/tool-registration.test.ts +0 -146
  121. package/src/__tests__/memory-db.test.ts +0 -404
  122. package/src/__tests__/memory-enhancements.test.ts +0 -316
  123. package/src/__tests__/memory-tools.test.ts +0 -199
  124. package/src/__tests__/middleware-tree.test.ts +0 -177
  125. package/src/__tests__/observability-tools.test.ts +0 -595
  126. package/src/__tests__/observability.test.ts +0 -437
  127. package/src/__tests__/observation-extractor.test.ts +0 -167
  128. package/src/__tests__/page-deps.test.ts +0 -60
  129. package/src/__tests__/prompt-analyzer.test.ts +0 -298
  130. package/src/__tests__/regression-detector.test.ts +0 -295
  131. package/src/__tests__/rules.test.ts +0 -87
  132. package/src/__tests__/schema-mapper.test.ts +0 -29
  133. package/src/__tests__/security-scorer.test.ts +0 -238
  134. package/src/__tests__/security-utils.test.ts +0 -175
  135. package/src/__tests__/sentinel-db.test.ts +0 -491
  136. package/src/__tests__/sentinel-scanner.test.ts +0 -750
  137. package/src/__tests__/sentinel-tools.test.ts +0 -324
  138. package/src/__tests__/sentinel-types.test.ts +0 -750
  139. package/src/__tests__/server.test.ts +0 -452
  140. package/src/__tests__/session-archiver.test.ts +0 -524
  141. package/src/__tests__/session-state-generator.test.ts +0 -900
  142. package/src/__tests__/team-knowledge.test.ts +0 -327
  143. package/src/__tests__/tools.test.ts +0 -340
  144. package/src/__tests__/transcript-parser.test.ts +0 -195
  145. package/src/__tests__/trpc-index.test.ts +0 -25
  146. package/src/__tests__/validate-features-runner.test.ts +0 -517
  147. package/src/__tests__/validation-engine.test.ts +0 -300
  148. package/src/core-tools.ts +0 -685
  149. package/src/memory-queries.ts +0 -804
  150. package/src/memory-schema.ts +0 -546
  151. package/src/tool-helpers.ts +0 -41
@@ -3,12 +3,13 @@ import{createRequire as __cr}from"module";const require=__cr(import.meta.url);
3
3
 
4
4
  // src/memory-db.ts
5
5
  import Database from "better-sqlite3";
6
- import { dirname as dirname2 } from "path";
6
+ import { dirname as dirname2, basename } from "path";
7
7
  import { existsSync as existsSync2, mkdirSync } from "fs";
8
8
 
9
9
  // src/config.ts
10
10
  import { resolve, dirname } from "path";
11
11
  import { existsSync, readFileSync } from "fs";
12
+ import { homedir } from "os";
12
13
  import { parse as parseYaml } from "yaml";
13
14
  import { z } from "zod";
14
15
  var DomainConfigSchema = z.object({
@@ -140,6 +141,49 @@ var CloudConfigSchema = z.object({
140
141
  audit: z.boolean().default(true)
141
142
  }).default({ memory: true, analytics: true, audit: true })
142
143
  }).optional();
144
+ var ConventionsConfigSchema = z.object({
145
+ claudeDirName: z.string().default(".claude").refine(
146
+ (s) => !s.includes("..") && !s.startsWith("/"),
147
+ { message: 'claudeDirName must not contain ".." or start with "/"' }
148
+ ),
149
+ sessionStatePath: z.string().default(".claude/session-state/CURRENT.md").refine(
150
+ (s) => !s.includes("..") && !s.startsWith("/"),
151
+ { message: 'sessionStatePath must not contain ".." or start with "/"' }
152
+ ),
153
+ sessionArchivePath: z.string().default(".claude/session-state/archive").refine(
154
+ (s) => !s.includes("..") && !s.startsWith("/"),
155
+ { message: 'sessionArchivePath must not contain ".." or start with "/"' }
156
+ ),
157
+ knowledgeCategories: z.array(z.string()).default([
158
+ "patterns",
159
+ "commands",
160
+ "incidents",
161
+ "reference",
162
+ "protocols",
163
+ "checklists",
164
+ "playbooks",
165
+ "critical",
166
+ "scripts",
167
+ "status",
168
+ "templates",
169
+ "loop-state",
170
+ "session-state",
171
+ "agents"
172
+ ]),
173
+ knowledgeSourceFiles: z.array(z.string()).default(["CLAUDE.md", "MEMORY.md", "corrections.md"]),
174
+ excludePatterns: z.array(z.string()).default(["/ARCHIVE/", "/SESSION-HISTORY/"])
175
+ }).optional();
176
+ var PythonDomainConfigSchema = z.object({
177
+ name: z.string(),
178
+ packages: z.array(z.string()),
179
+ allowed_imports_from: z.array(z.string()).default([])
180
+ });
181
+ var PythonConfigSchema = z.object({
182
+ root: z.string(),
183
+ alembic_dir: z.string().optional(),
184
+ domains: z.array(PythonDomainConfigSchema).default([]),
185
+ exclude_dirs: z.array(z.string()).default(["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"])
186
+ }).optional();
143
187
  var PathsConfigSchema = z.object({
144
188
  source: z.string().default("src"),
145
189
  aliases: z.record(z.string(), z.string()).default({ "@": "src" }),
@@ -174,7 +218,9 @@ var RawConfigSchema = z.object({
174
218
  security: SecurityConfigSchema,
175
219
  team: TeamConfigSchema,
176
220
  regression: RegressionConfigSchema,
177
- cloud: CloudConfigSchema
221
+ cloud: CloudConfigSchema,
222
+ conventions: ConventionsConfigSchema,
223
+ python: PythonConfigSchema
178
224
  }).passthrough();
179
225
  var _config = null;
180
226
  var _projectRoot = null;
@@ -238,13 +284,24 @@ function getConfig() {
238
284
  security: parsed.security,
239
285
  team: parsed.team,
240
286
  regression: parsed.regression,
241
- cloud: parsed.cloud
287
+ cloud: parsed.cloud,
288
+ conventions: parsed.conventions,
289
+ python: parsed.python
242
290
  };
291
+ if (!_config.cloud?.apiKey && process.env.MASSU_API_KEY) {
292
+ _config.cloud = {
293
+ enabled: true,
294
+ sync: { memory: true, analytics: true, audit: true },
295
+ ..._config.cloud,
296
+ apiKey: process.env.MASSU_API_KEY
297
+ };
298
+ }
243
299
  return _config;
244
300
  }
245
301
  function getResolvedPaths() {
246
302
  const config = getConfig();
247
303
  const root = getProjectRoot();
304
+ const claudeDirName = config.conventions?.claudeDirName ?? ".claude";
248
305
  return {
249
306
  codegraphDbPath: resolve(root, ".codegraph/codegraph.db"),
250
307
  dataDbPath: resolve(root, ".massu/data.db"),
@@ -260,22 +317,43 @@ function getResolvedPaths() {
260
317
  ),
261
318
  extensions: [".ts", ".tsx", ".js", ".jsx"],
262
319
  indexFiles: ["index.ts", "index.tsx", "index.js", "index.jsx"],
263
- patternsDir: resolve(root, ".claude/patterns"),
264
- claudeMdPath: resolve(root, ".claude/CLAUDE.md"),
320
+ patternsDir: resolve(root, claudeDirName, "patterns"),
321
+ claudeMdPath: resolve(root, claudeDirName, "CLAUDE.md"),
265
322
  docsMapPath: resolve(root, ".massu/docs-map.json"),
266
323
  helpSitePath: resolve(root, "../" + config.project.name + "-help"),
267
- memoryDbPath: resolve(root, ".massu/memory.db")
324
+ memoryDbPath: resolve(root, ".massu/memory.db"),
325
+ knowledgeDbPath: resolve(root, ".massu/knowledge.db"),
326
+ plansDir: resolve(root, "docs/plans"),
327
+ docsDir: resolve(root, "docs"),
328
+ claudeDir: resolve(root, claudeDirName),
329
+ memoryDir: resolve(homedir(), claudeDirName, "projects", root.replace(/\//g, "-"), "memory"),
330
+ sessionStatePath: resolve(root, config.conventions?.sessionStatePath ?? `${claudeDirName}/session-state/CURRENT.md`),
331
+ sessionArchivePath: resolve(root, config.conventions?.sessionArchivePath ?? `${claudeDirName}/session-state/archive`),
332
+ mcpJsonPath: resolve(root, ".mcp.json"),
333
+ settingsLocalPath: resolve(root, claudeDirName, "settings.local.json")
268
334
  };
269
335
  }
270
336
 
271
- // src/memory-schema.ts
337
+ // src/memory-db.ts
338
+ function getMemoryDb() {
339
+ const dbPath = getResolvedPaths().memoryDbPath;
340
+ const dir = dirname2(dbPath);
341
+ if (!existsSync2(dir)) {
342
+ mkdirSync(dir, { recursive: true });
343
+ }
344
+ const db = new Database(dbPath);
345
+ db.pragma("journal_mode = WAL");
346
+ db.pragma("foreign_keys = ON");
347
+ initMemorySchema(db);
348
+ return db;
349
+ }
272
350
  function initMemorySchema(db) {
273
351
  db.exec(`
274
352
  -- Sessions table (linked to Claude Code session IDs)
275
353
  CREATE TABLE IF NOT EXISTS sessions (
276
354
  id INTEGER PRIMARY KEY AUTOINCREMENT,
277
355
  session_id TEXT UNIQUE NOT NULL,
278
- project TEXT NOT NULL DEFAULT 'unknown',
356
+ project TEXT NOT NULL DEFAULT 'my-project',
279
357
  git_branch TEXT,
280
358
  started_at TEXT NOT NULL,
281
359
  started_at_epoch INTEGER NOT NULL,
@@ -330,9 +408,7 @@ function initMemorySchema(db) {
330
408
  content_rowid='id'
331
409
  );
332
410
  `);
333
- } catch (e) {
334
- process.stderr.write(`FTS5 setup warning: ${e instanceof Error ? e.message : String(e)}
335
- `);
411
+ } catch (_e) {
336
412
  }
337
413
  db.exec(`
338
414
  CREATE TRIGGER IF NOT EXISTS observations_ai AFTER INSERT ON observations BEGIN
@@ -392,9 +468,7 @@ function initMemorySchema(db) {
392
468
  content_rowid='id'
393
469
  );
394
470
  `);
395
- } catch (e) {
396
- process.stderr.write(`FTS5 setup warning: ${e instanceof Error ? e.message : String(e)}
397
- `);
471
+ } catch (_e) {
398
472
  }
399
473
  db.exec(`
400
474
  CREATE TRIGGER IF NOT EXISTS prompts_ai AFTER INSERT ON user_prompts BEGIN
@@ -464,9 +538,7 @@ function initMemorySchema(db) {
464
538
  content_rowid=id
465
539
  );
466
540
  `);
467
- } catch (e) {
468
- process.stderr.write(`FTS5 setup warning: ${e instanceof Error ? e.message : String(e)}
469
- `);
541
+ } catch (_e) {
470
542
  }
471
543
  db.exec(`
472
544
  CREATE TRIGGER IF NOT EXISTS ct_fts_insert AFTER INSERT ON conversation_turns BEGIN
@@ -490,7 +562,7 @@ function initMemorySchema(db) {
490
562
  CREATE TABLE IF NOT EXISTS session_quality_scores (
491
563
  id INTEGER PRIMARY KEY AUTOINCREMENT,
492
564
  session_id TEXT NOT NULL UNIQUE,
493
- project TEXT NOT NULL DEFAULT 'unknown',
565
+ project TEXT NOT NULL DEFAULT 'my-project',
494
566
  score INTEGER NOT NULL DEFAULT 100,
495
567
  security_score INTEGER NOT NULL DEFAULT 100,
496
568
  architecture_score INTEGER NOT NULL DEFAULT 100,
@@ -513,7 +585,7 @@ function initMemorySchema(db) {
513
585
  CREATE TABLE IF NOT EXISTS session_costs (
514
586
  id INTEGER PRIMARY KEY AUTOINCREMENT,
515
587
  session_id TEXT NOT NULL UNIQUE,
516
- project TEXT NOT NULL DEFAULT 'unknown',
588
+ project TEXT NOT NULL DEFAULT 'my-project',
517
589
  input_tokens INTEGER NOT NULL DEFAULT 0,
518
590
  output_tokens INTEGER NOT NULL DEFAULT 0,
519
591
  cache_read_tokens INTEGER NOT NULL DEFAULT 0,
@@ -740,24 +812,15 @@ function initMemorySchema(db) {
740
812
  );
741
813
  CREATE INDEX IF NOT EXISTS idx_pending_sync_created ON pending_sync(created_at ASC);
742
814
  `);
743
- }
744
-
745
- // src/memory-db.ts
746
- var initializedPaths = /* @__PURE__ */ new Set();
747
- function getMemoryDb() {
748
- const dbPath = getResolvedPaths().memoryDbPath;
749
- const dir = dirname2(dbPath);
750
- if (!existsSync2(dir)) {
751
- mkdirSync(dir, { recursive: true });
752
- }
753
- const db = new Database(dbPath);
754
- db.pragma("journal_mode = WAL");
755
- db.pragma("foreign_keys = ON");
756
- if (!initializedPaths.has(dbPath)) {
757
- initMemorySchema(db);
758
- initializedPaths.add(dbPath);
759
- }
760
- return db;
815
+ db.exec(`
816
+ CREATE TABLE IF NOT EXISTS license_cache (
817
+ api_key_hash TEXT PRIMARY KEY,
818
+ tier TEXT NOT NULL,
819
+ valid_until TEXT NOT NULL,
820
+ last_validated TEXT NOT NULL,
821
+ features TEXT DEFAULT '[]'
822
+ );
823
+ `);
761
824
  }
762
825
 
763
826
  // src/hooks/cost-tracker.ts
@@ -787,14 +850,14 @@ async function main() {
787
850
  process.exit(0);
788
851
  }
789
852
  function readStdin() {
790
- return new Promise((resolve2) => {
853
+ return new Promise((resolve3) => {
791
854
  let data = "";
792
855
  process.stdin.setEncoding("utf-8");
793
856
  process.stdin.on("data", (chunk) => {
794
857
  data += chunk;
795
858
  });
796
- process.stdin.on("end", () => resolve2(data));
797
- setTimeout(() => resolve2(data), 3e3);
859
+ process.stdin.on("end", () => resolve3(data));
860
+ setTimeout(() => resolve3(data), 3e3);
798
861
  });
799
862
  }
800
863
  main();
@@ -7,6 +7,7 @@ import Database from "better-sqlite3";
7
7
  // src/config.ts
8
8
  import { resolve, dirname } from "path";
9
9
  import { existsSync, readFileSync } from "fs";
10
+ import { homedir } from "os";
10
11
  import { parse as parseYaml } from "yaml";
11
12
  import { z } from "zod";
12
13
  var DomainConfigSchema = z.object({
@@ -138,6 +139,49 @@ var CloudConfigSchema = z.object({
138
139
  audit: z.boolean().default(true)
139
140
  }).default({ memory: true, analytics: true, audit: true })
140
141
  }).optional();
142
+ var ConventionsConfigSchema = z.object({
143
+ claudeDirName: z.string().default(".claude").refine(
144
+ (s) => !s.includes("..") && !s.startsWith("/"),
145
+ { message: 'claudeDirName must not contain ".." or start with "/"' }
146
+ ),
147
+ sessionStatePath: z.string().default(".claude/session-state/CURRENT.md").refine(
148
+ (s) => !s.includes("..") && !s.startsWith("/"),
149
+ { message: 'sessionStatePath must not contain ".." or start with "/"' }
150
+ ),
151
+ sessionArchivePath: z.string().default(".claude/session-state/archive").refine(
152
+ (s) => !s.includes("..") && !s.startsWith("/"),
153
+ { message: 'sessionArchivePath must not contain ".." or start with "/"' }
154
+ ),
155
+ knowledgeCategories: z.array(z.string()).default([
156
+ "patterns",
157
+ "commands",
158
+ "incidents",
159
+ "reference",
160
+ "protocols",
161
+ "checklists",
162
+ "playbooks",
163
+ "critical",
164
+ "scripts",
165
+ "status",
166
+ "templates",
167
+ "loop-state",
168
+ "session-state",
169
+ "agents"
170
+ ]),
171
+ knowledgeSourceFiles: z.array(z.string()).default(["CLAUDE.md", "MEMORY.md", "corrections.md"]),
172
+ excludePatterns: z.array(z.string()).default(["/ARCHIVE/", "/SESSION-HISTORY/"])
173
+ }).optional();
174
+ var PythonDomainConfigSchema = z.object({
175
+ name: z.string(),
176
+ packages: z.array(z.string()),
177
+ allowed_imports_from: z.array(z.string()).default([])
178
+ });
179
+ var PythonConfigSchema = z.object({
180
+ root: z.string(),
181
+ alembic_dir: z.string().optional(),
182
+ domains: z.array(PythonDomainConfigSchema).default([]),
183
+ exclude_dirs: z.array(z.string()).default(["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"])
184
+ }).optional();
141
185
  var PathsConfigSchema = z.object({
142
186
  source: z.string().default("src"),
143
187
  aliases: z.record(z.string(), z.string()).default({ "@": "src" }),
@@ -172,7 +216,9 @@ var RawConfigSchema = z.object({
172
216
  security: SecurityConfigSchema,
173
217
  team: TeamConfigSchema,
174
218
  regression: RegressionConfigSchema,
175
- cloud: CloudConfigSchema
219
+ cloud: CloudConfigSchema,
220
+ conventions: ConventionsConfigSchema,
221
+ python: PythonConfigSchema
176
222
  }).passthrough();
177
223
  var _config = null;
178
224
  var _projectRoot = null;
@@ -236,13 +282,24 @@ function getConfig() {
236
282
  security: parsed.security,
237
283
  team: parsed.team,
238
284
  regression: parsed.regression,
239
- cloud: parsed.cloud
285
+ cloud: parsed.cloud,
286
+ conventions: parsed.conventions,
287
+ python: parsed.python
240
288
  };
289
+ if (!_config.cloud?.apiKey && process.env.MASSU_API_KEY) {
290
+ _config.cloud = {
291
+ enabled: true,
292
+ sync: { memory: true, analytics: true, audit: true },
293
+ ..._config.cloud,
294
+ apiKey: process.env.MASSU_API_KEY
295
+ };
296
+ }
241
297
  return _config;
242
298
  }
243
299
  function getResolvedPaths() {
244
300
  const config = getConfig();
245
301
  const root = getProjectRoot();
302
+ const claudeDirName = config.conventions?.claudeDirName ?? ".claude";
246
303
  return {
247
304
  codegraphDbPath: resolve(root, ".codegraph/codegraph.db"),
248
305
  dataDbPath: resolve(root, ".massu/data.db"),
@@ -258,11 +315,20 @@ function getResolvedPaths() {
258
315
  ),
259
316
  extensions: [".ts", ".tsx", ".js", ".jsx"],
260
317
  indexFiles: ["index.ts", "index.tsx", "index.js", "index.jsx"],
261
- patternsDir: resolve(root, ".claude/patterns"),
262
- claudeMdPath: resolve(root, ".claude/CLAUDE.md"),
318
+ patternsDir: resolve(root, claudeDirName, "patterns"),
319
+ claudeMdPath: resolve(root, claudeDirName, "CLAUDE.md"),
263
320
  docsMapPath: resolve(root, ".massu/docs-map.json"),
264
321
  helpSitePath: resolve(root, "../" + config.project.name + "-help"),
265
- memoryDbPath: resolve(root, ".massu/memory.db")
322
+ memoryDbPath: resolve(root, ".massu/memory.db"),
323
+ knowledgeDbPath: resolve(root, ".massu/knowledge.db"),
324
+ plansDir: resolve(root, "docs/plans"),
325
+ docsDir: resolve(root, "docs"),
326
+ claudeDir: resolve(root, claudeDirName),
327
+ memoryDir: resolve(homedir(), claudeDirName, "projects", root.replace(/\//g, "-"), "memory"),
328
+ sessionStatePath: resolve(root, config.conventions?.sessionStatePath ?? `${claudeDirName}/session-state/CURRENT.md`),
329
+ sessionArchivePath: resolve(root, config.conventions?.sessionArchivePath ?? `${claudeDirName}/session-state/archive`),
330
+ mcpJsonPath: resolve(root, ".mcp.json"),
331
+ settingsLocalPath: resolve(root, claudeDirName, "settings.local.json")
266
332
  };
267
333
  }
268
334
 
@@ -302,7 +368,7 @@ async function main() {
302
368
  }
303
369
  const root = getProjectRoot();
304
370
  const rel = filePath.startsWith(root + "/") ? filePath.slice(root.length + 1) : filePath;
305
- if (!rel.startsWith("src/")) {
371
+ if (!rel.startsWith("src/") && !rel.endsWith(".py")) {
306
372
  process.exit(0);
307
373
  return;
308
374
  }
@@ -319,7 +385,7 @@ async function main() {
319
385
  const dataDb = new Database(getResolvedPaths().dataDbPath, { readonly: true });
320
386
  try {
321
387
  if (isInMiddlewareTree(dataDb, rel)) {
322
- warnings.push("[CRITICAL] CR-16: This file is in the middleware import tree. No Node.js deps allowed.");
388
+ warnings.push("[CRITICAL] This file is in the middleware import tree. No Node.js deps allowed.");
323
389
  }
324
390
  } finally {
325
391
  dataDb.close();
@@ -327,7 +393,7 @@ async function main() {
327
393
  } catch (_e) {
328
394
  }
329
395
  if (warnings.length > 0) {
330
- console.log(`[CS CONTEXT] ${warnings.join(" | ")}`);
396
+ console.log(`[Massu] ${warnings.join(" | ")}`);
331
397
  }
332
398
  } catch (_e) {
333
399
  }