mythik-cli 0.1.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 (128) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +4 -0
  3. package/README.md +71 -0
  4. package/dist/api.d.ts +22 -0
  5. package/dist/api.d.ts.map +1 -0
  6. package/dist/api.js +17 -0
  7. package/dist/api.js.map +1 -0
  8. package/dist/cli.d.ts +3 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +519 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/commands/contract.d.ts +12 -0
  13. package/dist/commands/contract.d.ts.map +1 -0
  14. package/dist/commands/contract.js +133 -0
  15. package/dist/commands/contract.js.map +1 -0
  16. package/dist/commands/delete.d.ts +9 -0
  17. package/dist/commands/delete.d.ts.map +1 -0
  18. package/dist/commands/delete.js +46 -0
  19. package/dist/commands/delete.js.map +1 -0
  20. package/dist/commands/diff.d.ts +11 -0
  21. package/dist/commands/diff.d.ts.map +1 -0
  22. package/dist/commands/diff.js +49 -0
  23. package/dist/commands/diff.js.map +1 -0
  24. package/dist/commands/docs.d.ts +15 -0
  25. package/dist/commands/docs.d.ts.map +1 -0
  26. package/dist/commands/docs.js +117 -0
  27. package/dist/commands/docs.js.map +1 -0
  28. package/dist/commands/elements.d.ts +9 -0
  29. package/dist/commands/elements.d.ts.map +1 -0
  30. package/dist/commands/elements.js +48 -0
  31. package/dist/commands/elements.js.map +1 -0
  32. package/dist/commands/envs.d.ts +11 -0
  33. package/dist/commands/envs.d.ts.map +1 -0
  34. package/dist/commands/envs.js +54 -0
  35. package/dist/commands/envs.js.map +1 -0
  36. package/dist/commands/history.d.ts +10 -0
  37. package/dist/commands/history.d.ts.map +1 -0
  38. package/dist/commands/history.js +67 -0
  39. package/dist/commands/history.js.map +1 -0
  40. package/dist/commands/init.d.ts +9 -0
  41. package/dist/commands/init.d.ts.map +1 -0
  42. package/dist/commands/init.js +120 -0
  43. package/dist/commands/init.js.map +1 -0
  44. package/dist/commands/lint.d.ts +9 -0
  45. package/dist/commands/lint.d.ts.map +1 -0
  46. package/dist/commands/lint.js +15 -0
  47. package/dist/commands/lint.js.map +1 -0
  48. package/dist/commands/manifest.d.ts +11 -0
  49. package/dist/commands/manifest.d.ts.map +1 -0
  50. package/dist/commands/manifest.js +48 -0
  51. package/dist/commands/manifest.js.map +1 -0
  52. package/dist/commands/patch.d.ts +12 -0
  53. package/dist/commands/patch.d.ts.map +1 -0
  54. package/dist/commands/patch.js +103 -0
  55. package/dist/commands/patch.js.map +1 -0
  56. package/dist/commands/promote.d.ts +15 -0
  57. package/dist/commands/promote.d.ts.map +1 -0
  58. package/dist/commands/promote.js +83 -0
  59. package/dist/commands/promote.js.map +1 -0
  60. package/dist/commands/pull.d.ts +9 -0
  61. package/dist/commands/pull.d.ts.map +1 -0
  62. package/dist/commands/pull.js +36 -0
  63. package/dist/commands/pull.js.map +1 -0
  64. package/dist/commands/push-bulk.d.ts +11 -0
  65. package/dist/commands/push-bulk.d.ts.map +1 -0
  66. package/dist/commands/push-bulk.js +112 -0
  67. package/dist/commands/push-bulk.js.map +1 -0
  68. package/dist/commands/push.d.ts +19 -0
  69. package/dist/commands/push.d.ts.map +1 -0
  70. package/dist/commands/push.js +102 -0
  71. package/dist/commands/push.js.map +1 -0
  72. package/dist/commands/rollback.d.ts +13 -0
  73. package/dist/commands/rollback.d.ts.map +1 -0
  74. package/dist/commands/rollback.js +78 -0
  75. package/dist/commands/rollback.js.map +1 -0
  76. package/dist/commands/tokens.d.ts +8 -0
  77. package/dist/commands/tokens.d.ts.map +1 -0
  78. package/dist/commands/tokens.js +63 -0
  79. package/dist/commands/tokens.js.map +1 -0
  80. package/dist/commands/validate.d.ts +8 -0
  81. package/dist/commands/validate.d.ts.map +1 -0
  82. package/dist/commands/validate.js +60 -0
  83. package/dist/commands/validate.js.map +1 -0
  84. package/dist/config.d.ts +27 -0
  85. package/dist/config.d.ts.map +1 -0
  86. package/dist/config.js +112 -0
  87. package/dist/config.js.map +1 -0
  88. package/dist/input-resolver.d.ts +22 -0
  89. package/dist/input-resolver.d.ts.map +1 -0
  90. package/dist/input-resolver.js +55 -0
  91. package/dist/input-resolver.js.map +1 -0
  92. package/dist/levenshtein.d.ts +2 -0
  93. package/dist/levenshtein.d.ts.map +1 -0
  94. package/dist/levenshtein.js +2 -0
  95. package/dist/levenshtein.js.map +1 -0
  96. package/dist/lint/code-rules.d.ts +30 -0
  97. package/dist/lint/code-rules.d.ts.map +1 -0
  98. package/dist/lint/code-rules.js +81 -0
  99. package/dist/lint/code-rules.js.map +1 -0
  100. package/dist/lint/format.d.ts +12 -0
  101. package/dist/lint/format.d.ts.map +1 -0
  102. package/dist/lint/format.js +68 -0
  103. package/dist/lint/format.js.map +1 -0
  104. package/dist/lint/orchestrator.d.ts +17 -0
  105. package/dist/lint/orchestrator.d.ts.map +1 -0
  106. package/dist/lint/orchestrator.js +124 -0
  107. package/dist/lint/orchestrator.js.map +1 -0
  108. package/dist/lint/spec-discovery.d.ts +14 -0
  109. package/dist/lint/spec-discovery.d.ts.map +1 -0
  110. package/dist/lint/spec-discovery.js +72 -0
  111. package/dist/lint/spec-discovery.js.map +1 -0
  112. package/dist/lint/types.d.ts +72 -0
  113. package/dist/lint/types.d.ts.map +1 -0
  114. package/dist/lint/types.js +28 -0
  115. package/dist/lint/types.js.map +1 -0
  116. package/dist/output.d.ts +16 -0
  117. package/dist/output.d.ts.map +1 -0
  118. package/dist/output.js +91 -0
  119. package/dist/output.js.map +1 -0
  120. package/dist/stores/resolver.d.ts +12 -0
  121. package/dist/stores/resolver.d.ts.map +1 -0
  122. package/dist/stores/resolver.js +54 -0
  123. package/dist/stores/resolver.js.map +1 -0
  124. package/dist/toon.d.ts +12 -0
  125. package/dist/toon.d.ts.map +1 -0
  126. package/dist/toon.js +27 -0
  127. package/dist/toon.js.map +1 -0
  128. package/package.json +65 -0
package/dist/config.js ADDED
@@ -0,0 +1,112 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ export function loadConfig(options = {}) {
4
+ const cwd = options.cwd ?? process.cwd();
5
+ const flags = options.flags ?? {};
6
+ let config;
7
+ // Priority 1: CLI flags
8
+ if (flags.store) {
9
+ config = buildConfigFromFlags(flags);
10
+ }
11
+ // Priority 2: Env vars
12
+ else if (process.env.MYTHIK_STORE) {
13
+ config = buildConfigFromEnv();
14
+ }
15
+ // Priority 3: .mythikrc file (search upward)
16
+ else {
17
+ const rcPath = findRcFile(cwd);
18
+ if (!rcPath) {
19
+ throw new Error(`No configuration found\n\n` +
20
+ ` Looked for .mythikrc from ${cwd} upward.\n` +
21
+ ` Also checked: MYTHIK_STORE, MYTHIK_SUPABASE_URL env vars.\n\n` +
22
+ ` Fix: run mythik init\n` +
23
+ ` or create .mythikrc manually\n` +
24
+ ` or pass --store, --url, --key flags`);
25
+ }
26
+ const raw = JSON.parse(fs.readFileSync(rcPath, 'utf-8'));
27
+ config = resolveEnvVars(raw);
28
+ }
29
+ // --table flag overrides store table for any store type
30
+ if (flags.table) {
31
+ if (config.sqlserver)
32
+ config.sqlserver.table = flags.table;
33
+ if (config.supabase)
34
+ config.supabase.table = flags.table;
35
+ }
36
+ return config;
37
+ }
38
+ function findRcFile(startDir) {
39
+ let dir = path.resolve(startDir);
40
+ const root = path.parse(dir).root;
41
+ while (true) {
42
+ const candidate = path.join(dir, '.mythikrc');
43
+ if (fs.existsSync(candidate))
44
+ return candidate;
45
+ const parent = path.dirname(dir);
46
+ if (parent === dir || dir === root)
47
+ return null;
48
+ dir = parent;
49
+ }
50
+ }
51
+ function buildConfigFromFlags(flags) {
52
+ const config = { store: flags.store };
53
+ if (flags.store === 'supabase') {
54
+ config.supabase = { url: flags.url ?? '', apiKey: flags.key ?? '' };
55
+ }
56
+ else if (flags.store === 'sqlserver') {
57
+ config.sqlserver = {
58
+ server: flags.server ?? flags.url ?? '',
59
+ database: flags.database ?? flags.db ?? '',
60
+ user: flags.user ?? undefined,
61
+ password: flags.password ?? undefined,
62
+ };
63
+ }
64
+ else if (flags.store === 'file') {
65
+ config.file = { dir: flags.dir ?? './specs' };
66
+ }
67
+ return config;
68
+ }
69
+ function buildConfigFromEnv() {
70
+ const store = process.env.MYTHIK_STORE;
71
+ const config = { store };
72
+ if (store === 'supabase') {
73
+ config.supabase = {
74
+ url: process.env.MYTHIK_SUPABASE_URL ?? '',
75
+ apiKey: process.env.MYTHIK_API_KEY ?? '',
76
+ };
77
+ }
78
+ else if (store === 'file') {
79
+ config.file = { dir: process.env.MYTHIK_FILE_DIR ?? './specs' };
80
+ }
81
+ return config;
82
+ }
83
+ export function resolveEnvVars(config) {
84
+ const clone = structuredClone(config);
85
+ if (clone.supabase) {
86
+ clone.supabase.url = resolveValue(clone.supabase.url);
87
+ clone.supabase.apiKey = resolveValue(clone.supabase.apiKey);
88
+ }
89
+ if (clone.file) {
90
+ clone.file.dir = resolveValue(clone.file.dir);
91
+ }
92
+ if (clone.sqlserver) {
93
+ clone.sqlserver.server = resolveValue(clone.sqlserver.server);
94
+ clone.sqlserver.database = resolveValue(clone.sqlserver.database);
95
+ if (clone.sqlserver.user)
96
+ clone.sqlserver.user = resolveValue(clone.sqlserver.user);
97
+ if (clone.sqlserver.password)
98
+ clone.sqlserver.password = resolveValue(clone.sqlserver.password);
99
+ }
100
+ return clone;
101
+ }
102
+ function resolveValue(value) {
103
+ if (!value.startsWith('$'))
104
+ return value;
105
+ const envName = value.slice(1);
106
+ const resolved = process.env[envName];
107
+ if (resolved === undefined) {
108
+ throw new Error(`Environment variable ${envName} is not set (referenced as "${value}" in .mythikrc)`);
109
+ }
110
+ return resolved;
111
+ }
112
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAsBxB,MAAM,UAAU,UAAU,CAAC,UAA6B,EAAE;IACxD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;IAElC,IAAI,MAAoB,CAAC;IAEzB,wBAAwB;IACxB,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,MAAM,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IACD,uBAAuB;SAClB,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAClC,MAAM,GAAG,kBAAkB,EAAE,CAAC;IAChC,CAAC;IACD,6CAA6C;SACxC,CAAC;QACJ,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,4BAA4B;gBAC5B,+BAA+B,GAAG,YAAY;gBAC9C,iEAAiE;gBACjE,0BAA0B;gBAC1B,uCAAuC;gBACvC,4CAA4C,CAC7C,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAiB,CAAC;QACzE,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAED,wDAAwD;IACxD,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,IAAI,MAAM,CAAC,SAAS;YAAE,MAAM,CAAC,SAAS,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QAC3D,IAAI,MAAM,CAAC,QAAQ;YAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC3D,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,UAAU,CAAC,QAAgB;IAClC,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;IAElC,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAC9C,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,GAAG,IAAI,GAAG,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAChD,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,KAA6B;IACzD,MAAM,MAAM,GAAiB,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IAEpD,IAAI,KAAK,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;QAC/B,MAAM,CAAC,QAAQ,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC;IACtE,CAAC;SAAM,IAAI,KAAK,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;QACvC,MAAM,CAAC,SAAS,GAAG;YACjB,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,EAAE;YACvC,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE,IAAI,EAAE;YAC1C,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,SAAS;YAC7B,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,SAAS;SACtC,CAAC;IACJ,CAAC;SAAM,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;QAClC,MAAM,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,SAAS,EAAE,CAAC;IAChD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,kBAAkB;IACzB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAa,CAAC;IACxC,MAAM,MAAM,GAAiB,EAAE,KAAK,EAAE,CAAC;IAEvC,IAAI,KAAK,KAAK,UAAU,EAAE,CAAC;QACzB,MAAM,CAAC,QAAQ,GAAG;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,EAAE;YAC1C,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE;SACzC,CAAC;IACJ,CAAC;SAAM,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,SAAS,EAAE,CAAC;IAClE,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAoB;IACjD,MAAM,KAAK,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAEtC,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACnB,KAAK,CAAC,QAAQ,CAAC,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACtD,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC9D,KAAK,CAAC,SAAS,CAAC,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAClE,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI;YAAE,KAAK,CAAC,SAAS,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACpF,IAAI,KAAK,CAAC,SAAS,CAAC,QAAQ;YAAE,KAAK,CAAC,SAAS,CAAC,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAClG,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACzC,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CACb,wBAAwB,OAAO,+BAA+B,KAAK,iBAAiB,CACrF,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,22 @@
1
+ export interface ResolveInputOptions {
2
+ /** `--from-file <path>` flag value. `-` means stdin. */
3
+ fromFile?: string;
4
+ /** Positional argument (patch command only — passes raw JSON inline). */
5
+ positional?: string;
6
+ /** Stream to read from when fromFile is `-` or unset. Inject for testability. */
7
+ stdin: NodeJS.ReadableStream;
8
+ /** Whether stdin is a TTY (no piped input). Inject for testability. */
9
+ stdinIsTTY: boolean;
10
+ }
11
+ /**
12
+ * Resolves command input from one of the three approved sources:
13
+ * - `--from-file <path>` (cross-shell ergonomics)
14
+ * - `--from-file -` (stdin alias)
15
+ * - Stdin pipe / positional argument (legacy paths)
16
+ *
17
+ * Explicit sources win over ambient stdin. This avoids false conflicts in
18
+ * shells/agents where stdin is non-TTY even when no pipe was intended.
19
+ * Use `--from-file -` or omit explicit sources to read stdin.
20
+ */
21
+ export declare function resolveInput(opts: ResolveInputOptions): Promise<string>;
22
+ //# sourceMappingURL=input-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-resolver.d.ts","sourceRoot":"","sources":["../src/input-resolver.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAC,cAAc,CAAC;IAC7B,uEAAuE;IACvE,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmC7E"}
@@ -0,0 +1,55 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ /**
3
+ * Resolves command input from one of the three approved sources:
4
+ * - `--from-file <path>` (cross-shell ergonomics)
5
+ * - `--from-file -` (stdin alias)
6
+ * - Stdin pipe / positional argument (legacy paths)
7
+ *
8
+ * Explicit sources win over ambient stdin. This avoids false conflicts in
9
+ * shells/agents where stdin is non-TTY even when no pipe was intended.
10
+ * Use `--from-file -` or omit explicit sources to read stdin.
11
+ */
12
+ export async function resolveInput(opts) {
13
+ // Non-TTY stdin implies piped/redirected input. Actual emptiness is detected
14
+ // later when the stream yields no chunks.
15
+ const stdinHasContent = !opts.stdinIsTTY;
16
+ const sources = [];
17
+ if (opts.fromFile !== undefined)
18
+ sources.push('--from-file');
19
+ if (opts.positional !== undefined)
20
+ sources.push('positional argument');
21
+ if (sources.length > 1) {
22
+ throw new Error(`Conflicting input sources: ${sources.join(', ')}. Use ONE of: --from-file <path>, stdin pipe, or positional argument.`);
23
+ }
24
+ if (opts.fromFile !== undefined) {
25
+ if (opts.fromFile === '-') {
26
+ return readStream(opts.stdin);
27
+ }
28
+ try {
29
+ const content = await readFile(opts.fromFile, 'utf-8');
30
+ return content.trim();
31
+ }
32
+ catch (err) {
33
+ throw new Error(`Could not read file "${opts.fromFile}": ${err.message}`);
34
+ }
35
+ }
36
+ if (opts.positional !== undefined) {
37
+ return opts.positional;
38
+ }
39
+ if (stdinHasContent) {
40
+ return readStream(opts.stdin);
41
+ }
42
+ throw new Error('No input. Provide --from-file <path>, pipe stdin, or pass an argument.');
43
+ }
44
+ async function readStream(stream) {
45
+ // Stream may emit string OR Buffer chunks depending on the producer:
46
+ // - process.stdin → Buffer chunks (production CLI path)
47
+ // - Readable.from([strings]) → string chunks (test injections)
48
+ // Both paths active by design; do not reduce to Buffer-only without breaking tests.
49
+ const parts = [];
50
+ for await (const chunk of stream) {
51
+ parts.push(typeof chunk === 'string' ? chunk : chunk.toString('utf-8'));
52
+ }
53
+ return parts.join('').trim();
54
+ }
55
+ //# sourceMappingURL=input-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-resolver.js","sourceRoot":"","sources":["../src/input-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAa5C;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAyB;IAC1D,6EAA6E;IAC7E,0CAA0C;IAC1C,MAAM,eAAe,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC;IACzC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC7D,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAEvE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,8BAA8B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,uEAAuE,CACxH,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAChC,IAAI,IAAI,CAAC,QAAQ,KAAK,GAAG,EAAE,CAAC;YAC1B,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;QACD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACvD,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;QACxB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,CAAC,QAAQ,MAAO,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAED,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;AAC5F,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,MAA6B;IACrD,qEAAqE;IACrE,wDAAwD;IACxD,+DAA+D;IAC/D,oFAAoF;IACpF,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAE,KAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { levenshtein, suggest } from 'mythik';
2
+ //# sourceMappingURL=levenshtein.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"levenshtein.d.ts","sourceRoot":"","sources":["../src/levenshtein.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { levenshtein, suggest } from 'mythik';
2
+ //# sourceMappingURL=levenshtein.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"levenshtein.js","sourceRoot":"","sources":["../src/levenshtein.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Code lint rule motor — TypeScript Compiler API (peerDep optional).
3
+ *
4
+ * `typescript` is declared as peerDependency (optional) in mythik-cli.
5
+ * Most Mythik consumers already have TS installed; if not, code rules
6
+ * skip cleanly via graceful degradation (loadTypeScript returns null).
7
+ *
8
+ * Rule 4 implementation: code-store-save-bypass — see scanCodeFile (Task 7).
9
+ */
10
+ import type { LintFinding } from './types.js';
11
+ /**
12
+ * Dynamic import of `typescript` with graceful degradation.
13
+ * Returns null if TS not installed or import fails.
14
+ * Result is cached across calls (vi.resetModules() in tests resets the cache).
15
+ */
16
+ export declare function loadTypeScript(): Promise<typeof import('typescript') | null>;
17
+ /**
18
+ * Scan a TypeScript/JavaScript source file for code lint violations.
19
+ *
20
+ * Rule: code-store-save-bypass — error when calling `<identifier>.save(...)`
21
+ * where identifier matches case-insensitive `/store$/i` AND file is NOT inside
22
+ * `packages/core/` or `packages/cli/` (allowed framework internal paths).
23
+ *
24
+ * @param filePath - Relative path of the file (used in LintFinding.file + path filter).
25
+ * @param content - Source file content.
26
+ * @param ts - TypeScript Compiler API (from loadTypeScript()).
27
+ * @returns LintFinding[] — empty if no violations.
28
+ */
29
+ export declare function scanCodeFile(filePath: string, content: string, ts: typeof import('typescript')): LintFinding[];
30
+ //# sourceMappingURL=code-rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-rules.d.ts","sourceRoot":"","sources":["../../src/lint/code-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C;;;;GAIG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,cAAc,YAAY,CAAC,GAAG,IAAI,CAAC,CAQlF;AAYD;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,cAAc,YAAY,CAAC,GAC9B,WAAW,EAAE,CAiCf"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Code lint rule motor — TypeScript Compiler API (peerDep optional).
3
+ *
4
+ * `typescript` is declared as peerDependency (optional) in mythik-cli.
5
+ * Most Mythik consumers already have TS installed; if not, code rules
6
+ * skip cleanly via graceful degradation (loadTypeScript returns null).
7
+ *
8
+ * Rule 4 implementation: code-store-save-bypass — see scanCodeFile (Task 7).
9
+ */
10
+ let cachedTs = undefined;
11
+ /**
12
+ * Dynamic import of `typescript` with graceful degradation.
13
+ * Returns null if TS not installed or import fails.
14
+ * Result is cached across calls (vi.resetModules() in tests resets the cache).
15
+ */
16
+ export async function loadTypeScript() {
17
+ if (cachedTs !== undefined)
18
+ return cachedTs;
19
+ try {
20
+ cachedTs = await import('typescript');
21
+ }
22
+ catch {
23
+ cachedTs = null;
24
+ }
25
+ return cachedTs;
26
+ }
27
+ const STORE_NAME_PATTERN = /store$/i;
28
+ const ALLOWED_PATH_PATTERNS = [
29
+ /(^|[/\\])packages[/\\]core[/\\]/,
30
+ /(^|[/\\])packages[/\\]cli[/\\]/,
31
+ ];
32
+ function isAllowedFilePath(filePath) {
33
+ return ALLOWED_PATH_PATTERNS.some(re => re.test(filePath));
34
+ }
35
+ /**
36
+ * Scan a TypeScript/JavaScript source file for code lint violations.
37
+ *
38
+ * Rule: code-store-save-bypass — error when calling `<identifier>.save(...)`
39
+ * where identifier matches case-insensitive `/store$/i` AND file is NOT inside
40
+ * `packages/core/` or `packages/cli/` (allowed framework internal paths).
41
+ *
42
+ * @param filePath - Relative path of the file (used in LintFinding.file + path filter).
43
+ * @param content - Source file content.
44
+ * @param ts - TypeScript Compiler API (from loadTypeScript()).
45
+ * @returns LintFinding[] — empty if no violations.
46
+ */
47
+ export function scanCodeFile(filePath, content, ts) {
48
+ if (isAllowedFilePath(filePath))
49
+ return [];
50
+ const findings = [];
51
+ const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
52
+ function visit(node) {
53
+ if (ts.isCallExpression(node)) {
54
+ const callee = node.expression;
55
+ if (ts.isPropertyAccessExpression(callee) && callee.name.text === 'save') {
56
+ const receiver = callee.expression;
57
+ if (ts.isIdentifier(receiver) && STORE_NAME_PATTERN.test(receiver.text)) {
58
+ const lineCol = sourceFile.getLineAndCharacterOfPosition(callee.getStart(sourceFile));
59
+ findings.push({
60
+ file: filePath,
61
+ ruleId: 'code-store-save-bypass',
62
+ severity: 'error',
63
+ message: `${receiver.text}.save() bypasses validation pipeline — use runPush from mythik-cli/api or 'mythik push --from-file'`,
64
+ location: { line: lineCol.line + 1, column: lineCol.character },
65
+ suggestedFix: {
66
+ type: 'code-snippet',
67
+ before: `${receiver.text}.save(<id>, <doc>)`,
68
+ after: `await runPush({ store, screenId: <id>, doc: <doc> })`,
69
+ explanation: `Use runPush from mythik-cli/api for validated writes. Or: mythik push <id> --from-file <path>`,
70
+ },
71
+ docRef: 'reference-doc.md#rule-249',
72
+ });
73
+ }
74
+ }
75
+ }
76
+ ts.forEachChild(node, visit);
77
+ }
78
+ visit(sourceFile);
79
+ return findings;
80
+ }
81
+ //# sourceMappingURL=code-rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-rules.js","sourceRoot":"","sources":["../../src/lint/code-rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,IAAI,QAAQ,GAAmD,SAAS,CAAC;AAEzE;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IAC5C,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,QAAQ,GAAG,IAAI,CAAC;IAClB,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,kBAAkB,GAAG,SAAS,CAAC;AACrC,MAAM,qBAAqB,GAAG;IAC5B,iCAAiC;IACjC,gCAAgC;CACjC,CAAC;AAEF,SAAS,iBAAiB,CAAC,QAAgB;IACzC,OAAO,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY,CAC1B,QAAgB,EAChB,OAAe,EACf,EAA+B;IAE/B,IAAI,iBAAiB,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3C,MAAM,QAAQ,GAAkB,EAAE,CAAC;IACnC,MAAM,UAAU,GAAG,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAExF,SAAS,KAAK,CAAC,IAA+B;QAC5C,IAAI,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;YAC/B,IAAI,EAAE,CAAC,0BAA0B,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACzE,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC;gBACnC,IAAI,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBACxE,MAAM,OAAO,GAAG,UAAU,CAAC,6BAA6B,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;oBACtF,QAAQ,CAAC,IAAI,CAAC;wBACZ,IAAI,EAAE,QAAQ;wBACd,MAAM,EAAE,wBAAwB;wBAChC,QAAQ,EAAE,OAAO;wBACjB,OAAO,EAAE,GAAG,QAAQ,CAAC,IAAI,qGAAqG;wBAC9H,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE;wBAC/D,YAAY,EAAE;4BACZ,IAAI,EAAE,cAAc;4BACpB,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,oBAAoB;4BAC5C,KAAK,EAAE,sDAAsD;4BAC7D,WAAW,EAAE,+FAA+F;yBAC7G;wBACD,MAAM,EAAE,2BAA2B;qBACpC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QACD,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,KAAK,CAAC,UAAU,CAAC,CAAC;IAClB,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Output renderers for `mythik lint`.
3
+ *
4
+ * - formatHuman: file-grouped, color-coded, with suggested fixes inline
5
+ * - formatJson: structured machine output (one-line JSON)
6
+ * - computeExitCode: 0 if no errors (warnings OK), 1 if any error
7
+ */
8
+ import type { LintResult } from './types.js';
9
+ export declare function formatJson(result: LintResult): string;
10
+ export declare function formatHuman(result: LintResult): string;
11
+ export declare function computeExitCode(result: LintResult): number;
12
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/lint/format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAU7C,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAErD;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAiDtD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAE1D"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Output renderers for `mythik lint`.
3
+ *
4
+ * - formatHuman: file-grouped, color-coded, with suggested fixes inline
5
+ * - formatJson: structured machine output (one-line JSON)
6
+ * - computeExitCode: 0 if no errors (warnings OK), 1 if any error
7
+ */
8
+ const RED = '\x1b[31m';
9
+ const YELLOW = '\x1b[33m';
10
+ const GREEN = '\x1b[32m';
11
+ const CYAN = '\x1b[36m';
12
+ const DIM = '\x1b[2m';
13
+ const BOLD = '\x1b[1m';
14
+ const RESET = '\x1b[0m';
15
+ export function formatJson(result) {
16
+ return JSON.stringify(result);
17
+ }
18
+ export function formatHuman(result) {
19
+ const lines = [];
20
+ const { findings, summary } = result;
21
+ if (findings.length === 0) {
22
+ lines.push(`${GREEN}✓${RESET} ${BOLD}Lint clean${RESET} — ${summary.files} file${summary.files !== 1 ? 's' : ''} scanned, 0 errors, 0 warnings`);
23
+ return lines.join('\n');
24
+ }
25
+ // Group by file
26
+ const byFile = new Map();
27
+ for (const f of findings) {
28
+ if (!byFile.has(f.file))
29
+ byFile.set(f.file, []);
30
+ byFile.get(f.file).push(f);
31
+ }
32
+ for (const [file, fs] of byFile) {
33
+ lines.push('');
34
+ lines.push(`${BOLD}${file}${RESET}`);
35
+ for (const f of fs) {
36
+ const sevColor = f.severity === 'error' ? RED : YELLOW;
37
+ const sevSymbol = f.severity === 'error' ? '✗' : '⚠';
38
+ const loc = f.location.line !== undefined
39
+ ? `:${f.location.line}:${f.location.column ?? 0}`
40
+ : f.location.jsonPath ? ` ${f.location.jsonPath}` : '';
41
+ lines.push(` ${sevColor}${sevSymbol}${RESET} ${DIM}${f.ruleId}${RESET}${loc}`);
42
+ lines.push(` ${f.message}`);
43
+ if (f.suggestedFix) {
44
+ if (f.suggestedFix.type === 'json-patch') {
45
+ lines.push(` ${CYAN}→${RESET} ${f.suggestedFix.description}`);
46
+ lines.push(` ${DIM}${JSON.stringify(f.suggestedFix.patch)}${RESET}`);
47
+ }
48
+ else {
49
+ lines.push(` ${CYAN}→${RESET} ${f.suggestedFix.explanation}`);
50
+ lines.push(` ${DIM}before:${RESET} ${f.suggestedFix.before}`);
51
+ lines.push(` ${DIM}after:${RESET} ${f.suggestedFix.after}`);
52
+ }
53
+ }
54
+ if (f.docRef) {
55
+ lines.push(` ${DIM}see ${f.docRef}${RESET}`);
56
+ }
57
+ }
58
+ }
59
+ lines.push('');
60
+ const errClr = summary.errors > 0 ? RED : GREEN;
61
+ const warnClr = summary.warnings > 0 ? YELLOW : DIM;
62
+ lines.push(`${BOLD}Summary:${RESET} ${errClr}${summary.errors} error${summary.errors !== 1 ? 's' : ''}${RESET}, ${warnClr}${summary.warnings} warning${summary.warnings !== 1 ? 's' : ''}${RESET} across ${summary.files} file${summary.files !== 1 ? 's' : ''}`);
63
+ return lines.join('\n');
64
+ }
65
+ export function computeExitCode(result) {
66
+ return result.summary.errors > 0 ? 1 : 0;
67
+ }
68
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/lint/format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `runLint` — entry point for `mythik lint` command and `mythik-cli/api` programmatic export.
3
+ *
4
+ * Coordinates spec + code lint phases:
5
+ * 1. Discover targets (via spec-discovery)
6
+ * 2. Run spec rules (via mythik validators) — convert ValidationError to LintFinding
7
+ * 3. Run code rules (via lint/code-rules.ts) — TypeScript Compiler API scan
8
+ * 4. Aggregate findings + compute summary
9
+ *
10
+ * Spec rules: rule 1 in spec-validator.ts (Spec docs), rules 2+3 in api-spec-validator.ts (ApiSpec docs).
11
+ * Code rule: rule 4 in code-rules.ts (TypeScript Compiler API).
12
+ *
13
+ * peerDep TS optional: code rules degrade gracefully when typescript not installed.
14
+ */
15
+ import type { LintResult, LintOptions } from './types.js';
16
+ export declare function runLint(opts?: LintOptions): Promise<LintResult>;
17
+ //# sourceMappingURL=orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/lint/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAAe,UAAU,EAAE,WAAW,EAAgB,MAAM,YAAY,CAAC;AAsDrF,wBAAsB,OAAO,CAAC,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAqDzE"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * `runLint` — entry point for `mythik lint` command and `mythik-cli/api` programmatic export.
3
+ *
4
+ * Coordinates spec + code lint phases:
5
+ * 1. Discover targets (via spec-discovery)
6
+ * 2. Run spec rules (via mythik validators) — convert ValidationError to LintFinding
7
+ * 3. Run code rules (via lint/code-rules.ts) — TypeScript Compiler API scan
8
+ * 4. Aggregate findings + compute summary
9
+ *
10
+ * Spec rules: rule 1 in spec-validator.ts (Spec docs), rules 2+3 in api-spec-validator.ts (ApiSpec docs).
11
+ * Code rule: rule 4 in code-rules.ts (TypeScript Compiler API).
12
+ *
13
+ * peerDep TS optional: code rules degrade gracefully when typescript not installed.
14
+ */
15
+ import * as fs from 'node:fs';
16
+ import * as path from 'node:path';
17
+ import { validateSpec, validateApiSpec } from 'mythik';
18
+ import { validationErrorToLintFinding } from './types.js';
19
+ import { discoverSpecs, discoverCode } from './spec-discovery.js';
20
+ import { loadTypeScript, scanCodeFile } from './code-rules.js';
21
+ function detectDocKind(parsed) {
22
+ if (!parsed || typeof parsed !== 'object')
23
+ return 'unknown';
24
+ const o = parsed;
25
+ // Spec docs have root + elements
26
+ if (typeof o.root === 'string' && o.elements && typeof o.elements === 'object')
27
+ return 'spec';
28
+ // ApiSpec docs have endpoints (object) or catalogs.
29
+ // Note: ApiSpec.endpoints is Record<string, EndpointConfig> (object, not array) — see
30
+ // packages/server/src/types.ts and packages/core/src/security/api-spec-validator.ts:85.
31
+ if ((o.endpoints && typeof o.endpoints === 'object') || (o.catalogs && typeof o.catalogs === 'object'))
32
+ return 'apispec';
33
+ return 'unknown';
34
+ }
35
+ async function lintSpecFile(file, cwd) {
36
+ let parsed;
37
+ try {
38
+ parsed = JSON.parse(fs.readFileSync(file, 'utf-8'));
39
+ }
40
+ catch {
41
+ return []; // Not parseable as JSON — skip silently
42
+ }
43
+ const kind = detectDocKind(parsed);
44
+ if (kind === 'unknown')
45
+ return []; // Not a Mythik spec — skip
46
+ const findings = [];
47
+ const relFile = path.relative(cwd, file);
48
+ if (kind === 'spec') {
49
+ const result = validateSpec(parsed);
50
+ const lintWarnings = (result.warnings ?? []).filter(w => w.ruleId !== undefined);
51
+ for (const w of lintWarnings) {
52
+ findings.push(validationErrorToLintFinding(w, relFile, 'warning'));
53
+ }
54
+ }
55
+ else if (kind === 'apispec') {
56
+ const result = validateApiSpec(parsed);
57
+ const lintWarnings = result.lintWarnings ?? [];
58
+ for (const w of lintWarnings) {
59
+ // Severity inferred by ruleId — only spec-crud-id-collision is error
60
+ const severity = w.ruleId === 'spec-crud-id-collision' ? 'error' : 'warning';
61
+ findings.push(validationErrorToLintFinding(w, relFile, severity));
62
+ }
63
+ }
64
+ return findings;
65
+ }
66
+ async function lintCodeFile(file, ts, cwd) {
67
+ const content = fs.readFileSync(file, 'utf-8');
68
+ const relFile = path.relative(cwd, file);
69
+ return scanCodeFile(relFile, content, ts);
70
+ }
71
+ export async function runLint(opts = {}) {
72
+ const findings = [];
73
+ const scopes = new Set();
74
+ const filesScanned = new Set();
75
+ const cwd = opts.cwd ?? process.cwd();
76
+ // Spec phase
77
+ if (!opts.codeOnly) {
78
+ const specTargets = await discoverSpecs(opts);
79
+ if (specTargets.length > 0)
80
+ scopes.add('specs');
81
+ for (const file of specTargets) {
82
+ filesScanned.add(file);
83
+ const fileFindings = await lintSpecFile(file, cwd);
84
+ findings.push(...fileFindings);
85
+ }
86
+ }
87
+ // Code phase
88
+ if (!opts.specsOnly) {
89
+ const codeTargets = await discoverCode(opts);
90
+ if (codeTargets.length > 0)
91
+ scopes.add('code');
92
+ if (codeTargets.length > 0) {
93
+ const ts = await loadTypeScript();
94
+ if (!ts) {
95
+ findings.push({
96
+ file: '(global)',
97
+ ruleId: 'lint-meta-no-typescript',
98
+ severity: 'warning',
99
+ message: 'Code rules skipped: TypeScript not installed. Install with: pnpm add -D typescript',
100
+ location: {},
101
+ });
102
+ }
103
+ else {
104
+ for (const file of codeTargets) {
105
+ filesScanned.add(file);
106
+ const fileFindings = await lintCodeFile(file, ts, cwd);
107
+ findings.push(...fileFindings);
108
+ }
109
+ }
110
+ }
111
+ }
112
+ const errors = findings.filter(f => f.severity === 'error').length;
113
+ const warnings = findings.filter(f => f.severity === 'warning').length;
114
+ return {
115
+ findings,
116
+ summary: {
117
+ errors,
118
+ warnings,
119
+ files: filesScanned.size,
120
+ scopes: Array.from(scopes),
121
+ },
122
+ };
123
+ }
124
+ //# sourceMappingURL=orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/lint/orchestrator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Auto-discovery for `mythik lint` — finds spec files (`*.json`) and code
3
+ * files (`*.{ts,tsx,js,jsx}`) based on LintOptions.
4
+ *
5
+ * Resolution order:
6
+ * 1. Explicit `fromFile` flag → single file (filtered by extension)
7
+ * 2. Explicit `fromDir` flag → walk directory
8
+ * 3. No flags → spec auto-discovery via `.mythikrc` file store dir;
9
+ * code auto-discovery via `codeDir` (default './src')
10
+ */
11
+ import type { LintOptions } from './types.js';
12
+ export declare function discoverSpecs(opts: LintOptions): Promise<string[]>;
13
+ export declare function discoverCode(opts: LintOptions): Promise<string[]>;
14
+ //# sourceMappingURL=spec-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-discovery.d.ts","sourceRoot":"","sources":["../../src/lint/spec-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAwB9C,wBAAsB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAmBxE;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAavE"}