@getmikk/core 1.2.0 → 1.3.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 (44) hide show
  1. package/README.md +431 -0
  2. package/package.json +6 -2
  3. package/src/contract/contract-generator.ts +85 -85
  4. package/src/contract/contract-reader.ts +28 -28
  5. package/src/contract/contract-writer.ts +114 -114
  6. package/src/contract/index.ts +12 -12
  7. package/src/contract/lock-compiler.ts +221 -221
  8. package/src/contract/lock-reader.ts +34 -34
  9. package/src/contract/schema.ts +147 -147
  10. package/src/graph/cluster-detector.ts +312 -312
  11. package/src/graph/graph-builder.ts +211 -211
  12. package/src/graph/impact-analyzer.ts +55 -55
  13. package/src/graph/index.ts +4 -4
  14. package/src/graph/types.ts +59 -59
  15. package/src/hash/file-hasher.ts +30 -30
  16. package/src/hash/hash-store.ts +119 -119
  17. package/src/hash/index.ts +3 -3
  18. package/src/hash/tree-hasher.ts +20 -20
  19. package/src/index.ts +12 -12
  20. package/src/parser/base-parser.ts +16 -16
  21. package/src/parser/boundary-checker.ts +211 -211
  22. package/src/parser/index.ts +46 -46
  23. package/src/parser/types.ts +90 -90
  24. package/src/parser/typescript/ts-extractor.ts +543 -543
  25. package/src/parser/typescript/ts-parser.ts +41 -41
  26. package/src/parser/typescript/ts-resolver.ts +86 -86
  27. package/src/utils/errors.ts +42 -42
  28. package/src/utils/fs.ts +75 -75
  29. package/src/utils/fuzzy-match.ts +186 -186
  30. package/src/utils/logger.ts +36 -36
  31. package/src/utils/minimatch.ts +19 -19
  32. package/tests/contract.test.ts +134 -134
  33. package/tests/fixtures/simple-api/package.json +5 -5
  34. package/tests/fixtures/simple-api/src/auth/middleware.ts +9 -9
  35. package/tests/fixtures/simple-api/src/auth/verify.ts +6 -6
  36. package/tests/fixtures/simple-api/src/index.ts +9 -9
  37. package/tests/fixtures/simple-api/src/utils/jwt.ts +3 -3
  38. package/tests/fixtures/simple-api/tsconfig.json +8 -8
  39. package/tests/fuzzy-match.test.ts +142 -142
  40. package/tests/graph.test.ts +169 -169
  41. package/tests/hash.test.ts +49 -49
  42. package/tests/helpers.ts +83 -83
  43. package/tests/parser.test.ts +218 -218
  44. package/tsconfig.json +15 -15
@@ -1,114 +1,114 @@
1
- import * as fs from 'node:fs/promises'
2
- import * as path from 'node:path'
3
- import type { MikkContract } from './schema.js'
4
- import { hashContent } from '../hash/file-hasher.js'
5
-
6
- const VERSION = 'mikk-cli@1.0.0'
7
-
8
- export interface UpdateResult {
9
- updated: boolean
10
- reason?: string
11
- requiresConfirmation?: boolean
12
- proposedChanges?: object
13
- }
14
-
15
- /**
16
- * ContractWriter — writes mikk.json to disk.
17
- * Implements the permission model (never / ask / explicit).
18
- */
19
- export class ContractWriter {
20
- /** Write a new mikk.json — safe for first write */
21
- async writeNew(contract: MikkContract, outputPath: string): Promise<void> {
22
- await fs.mkdir(path.dirname(outputPath), { recursive: true })
23
- const json = JSON.stringify(contract, null, 2)
24
- await fs.writeFile(outputPath, json, 'utf-8')
25
- }
26
-
27
- /** Update an existing mikk.json respecting overwrite mode */
28
- async update(
29
- existing: MikkContract,
30
- updates: Partial<MikkContract>,
31
- outputPath: string
32
- ): Promise<UpdateResult> {
33
- const mode = existing.overwrite?.mode ?? 'never'
34
-
35
- if (mode === 'never') {
36
- return { updated: false, reason: 'overwrite mode is never' }
37
- }
38
-
39
- if (mode === 'ask') {
40
- return {
41
- updated: false,
42
- requiresConfirmation: true,
43
- proposedChanges: this.diffContracts(existing, updates),
44
- }
45
- }
46
-
47
- if (mode === 'explicit') {
48
- const updated = this.mergeContracts(existing, updates)
49
- updated.overwrite = {
50
- ...updated.overwrite,
51
- lastOverwrittenBy: VERSION,
52
- lastOverwrittenAt: new Date().toISOString(),
53
- }
54
- await this.writeNew(updated, outputPath)
55
- await this.writeAuditLog(existing, updated, outputPath)
56
- return { updated: true }
57
- }
58
-
59
- return { updated: false, reason: 'unknown mode' }
60
- }
61
-
62
- /** Merge two contracts — updates overwrite existing fields */
63
- private mergeContracts(existing: MikkContract, updates: Partial<MikkContract>): MikkContract {
64
- return {
65
- ...existing,
66
- ...updates,
67
- declared: {
68
- ...existing.declared,
69
- ...(updates.declared || {}),
70
- modules: updates.declared?.modules || existing.declared.modules,
71
- constraints: updates.declared?.constraints || existing.declared.constraints,
72
- decisions: updates.declared?.decisions || existing.declared.decisions,
73
- },
74
- project: {
75
- ...existing.project,
76
- ...(updates.project || {}),
77
- },
78
- }
79
- }
80
-
81
- /** Compute diff between two contracts */
82
- private diffContracts(existing: MikkContract, updates: Partial<MikkContract>): object {
83
- return {
84
- before: existing.declared,
85
- after: updates.declared || existing.declared,
86
- }
87
- }
88
-
89
- /** Write audit log to .mikk/overwrite-history.json */
90
- private async writeAuditLog(
91
- before: MikkContract,
92
- after: MikkContract,
93
- contractPath: string
94
- ): Promise<void> {
95
- const historyPath = path.join(path.dirname(contractPath), '.mikk', 'overwrite-history.json')
96
- let history: object[] = []
97
-
98
- try {
99
- const existing = await fs.readFile(historyPath, 'utf-8')
100
- history = JSON.parse(existing)
101
- } catch {
102
- // No history file yet
103
- }
104
-
105
- history.push({
106
- timestamp: new Date().toISOString(),
107
- before: before.declared,
108
- after: after.declared,
109
- })
110
-
111
- await fs.mkdir(path.dirname(historyPath), { recursive: true })
112
- await fs.writeFile(historyPath, JSON.stringify(history, null, 2), 'utf-8')
113
- }
114
- }
1
+ import * as fs from 'node:fs/promises'
2
+ import * as path from 'node:path'
3
+ import type { MikkContract } from './schema.js'
4
+ import { hashContent } from '../hash/file-hasher.js'
5
+
6
+ const VERSION = '@getmikk/cli@1.2.1'
7
+
8
+ export interface UpdateResult {
9
+ updated: boolean
10
+ reason?: string
11
+ requiresConfirmation?: boolean
12
+ proposedChanges?: object
13
+ }
14
+
15
+ /**
16
+ * ContractWriter — writes mikk.json to disk.
17
+ * Implements the permission model (never / ask / explicit).
18
+ */
19
+ export class ContractWriter {
20
+ /** Write a new mikk.json — safe for first write */
21
+ async writeNew(contract: MikkContract, outputPath: string): Promise<void> {
22
+ await fs.mkdir(path.dirname(outputPath), { recursive: true })
23
+ const json = JSON.stringify(contract, null, 2)
24
+ await fs.writeFile(outputPath, json, 'utf-8')
25
+ }
26
+
27
+ /** Update an existing mikk.json respecting overwrite mode */
28
+ async update(
29
+ existing: MikkContract,
30
+ updates: Partial<MikkContract>,
31
+ outputPath: string
32
+ ): Promise<UpdateResult> {
33
+ const mode = existing.overwrite?.mode ?? 'never'
34
+
35
+ if (mode === 'never') {
36
+ return { updated: false, reason: 'overwrite mode is never' }
37
+ }
38
+
39
+ if (mode === 'ask') {
40
+ return {
41
+ updated: false,
42
+ requiresConfirmation: true,
43
+ proposedChanges: this.diffContracts(existing, updates),
44
+ }
45
+ }
46
+
47
+ if (mode === 'explicit') {
48
+ const updated = this.mergeContracts(existing, updates)
49
+ updated.overwrite = {
50
+ ...updated.overwrite,
51
+ lastOverwrittenBy: VERSION,
52
+ lastOverwrittenAt: new Date().toISOString(),
53
+ }
54
+ await this.writeNew(updated, outputPath)
55
+ await this.writeAuditLog(existing, updated, outputPath)
56
+ return { updated: true }
57
+ }
58
+
59
+ return { updated: false, reason: 'unknown mode' }
60
+ }
61
+
62
+ /** Merge two contracts — updates overwrite existing fields */
63
+ private mergeContracts(existing: MikkContract, updates: Partial<MikkContract>): MikkContract {
64
+ return {
65
+ ...existing,
66
+ ...updates,
67
+ declared: {
68
+ ...existing.declared,
69
+ ...(updates.declared || {}),
70
+ modules: updates.declared?.modules || existing.declared.modules,
71
+ constraints: updates.declared?.constraints || existing.declared.constraints,
72
+ decisions: updates.declared?.decisions || existing.declared.decisions,
73
+ },
74
+ project: {
75
+ ...existing.project,
76
+ ...(updates.project || {}),
77
+ },
78
+ }
79
+ }
80
+
81
+ /** Compute diff between two contracts */
82
+ private diffContracts(existing: MikkContract, updates: Partial<MikkContract>): object {
83
+ return {
84
+ before: existing.declared,
85
+ after: updates.declared || existing.declared,
86
+ }
87
+ }
88
+
89
+ /** Write audit log to .mikk/overwrite-history.json */
90
+ private async writeAuditLog(
91
+ before: MikkContract,
92
+ after: MikkContract,
93
+ contractPath: string
94
+ ): Promise<void> {
95
+ const historyPath = path.join(path.dirname(contractPath), '.mikk', 'overwrite-history.json')
96
+ let history: object[] = []
97
+
98
+ try {
99
+ const existing = await fs.readFile(historyPath, 'utf-8')
100
+ history = JSON.parse(existing)
101
+ } catch {
102
+ // No history file yet
103
+ }
104
+
105
+ history.push({
106
+ timestamp: new Date().toISOString(),
107
+ before: before.declared,
108
+ after: after.declared,
109
+ })
110
+
111
+ await fs.mkdir(path.dirname(historyPath), { recursive: true })
112
+ await fs.writeFile(historyPath, JSON.stringify(history, null, 2), 'utf-8')
113
+ }
114
+ }
@@ -1,12 +1,12 @@
1
- export {
2
- MikkContractSchema, MikkLockSchema,
3
- MikkModuleSchema, MikkDecisionSchema, MikkOverwriteSchema,
4
- MikkLockFunctionSchema, MikkLockModuleSchema, MikkLockFileSchema,
5
- type MikkContract, type MikkLock, type MikkModule, type MikkDecision,
6
- type MikkLockFunction, type MikkLockModule, type MikkLockFile,
7
- } from './schema.js'
8
- export { LockCompiler } from './lock-compiler.js'
9
- export { ContractWriter, type UpdateResult } from './contract-writer.js'
10
- export { ContractReader } from './contract-reader.js'
11
- export { LockReader } from './lock-reader.js'
12
- export { ContractGenerator } from './contract-generator.js'
1
+ export {
2
+ MikkContractSchema, MikkLockSchema,
3
+ MikkModuleSchema, MikkDecisionSchema, MikkOverwriteSchema,
4
+ MikkLockFunctionSchema, MikkLockModuleSchema, MikkLockFileSchema,
5
+ type MikkContract, type MikkLock, type MikkModule, type MikkDecision,
6
+ type MikkLockFunction, type MikkLockModule, type MikkLockFile,
7
+ } from './schema.js'
8
+ export { LockCompiler } from './lock-compiler.js'
9
+ export { ContractWriter, type UpdateResult } from './contract-writer.js'
10
+ export { ContractReader } from './contract-reader.js'
11
+ export { LockReader } from './lock-reader.js'
12
+ export { ContractGenerator } from './contract-generator.js'