@getmikk/intent-engine 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.
package/src/suggester.ts CHANGED
@@ -1,104 +1,104 @@
1
- import type { MikkContract, MikkLock } from '@getmikk/core'
2
- import type { Intent, Suggestion } from './types.js'
3
-
4
- /**
5
- * Suggester — given validated intents, produces implementation suggestions
6
- * with affected files, new files, and estimated impact.
7
- */
8
- export class Suggester {
9
- constructor(
10
- private contract: MikkContract,
11
- private lock: MikkLock
12
- ) { }
13
-
14
- /** Generate suggestions for a list of intents */
15
- suggest(intents: Intent[]): Suggestion[] {
16
- return intents.map(intent => this.suggestForIntent(intent))
17
- }
18
-
19
- private suggestForIntent(intent: Intent): Suggestion {
20
- const affectedFiles: string[] = []
21
- const newFiles: string[] = []
22
-
23
- switch (intent.action) {
24
- case 'create': {
25
- // Find the target module's directory pattern
26
- const module = this.contract.declared.modules.find(m => m.id === intent.target.moduleId)
27
- if (module) {
28
- const dir = module.paths[0]?.replace('/**', '') || 'src'
29
- newFiles.push(`${dir}/${intent.target.name}.ts`)
30
- } else {
31
- newFiles.push(`src/${intent.target.name}.ts`)
32
- }
33
- break
34
- }
35
- case 'modify': {
36
- if (intent.target.filePath) {
37
- affectedFiles.push(intent.target.filePath)
38
- } else {
39
- // Find files by function name
40
- const fn = Object.values(this.lock.functions).find(
41
- f => f.name === intent.target.name
42
- )
43
- if (fn) {
44
- affectedFiles.push(fn.file)
45
- // Add callers
46
- for (const callerId of fn.calledBy) {
47
- const caller = this.lock.functions[callerId]
48
- if (caller) affectedFiles.push(caller.file)
49
- }
50
- }
51
- }
52
- break
53
- }
54
- case 'delete': {
55
- if (intent.target.filePath) {
56
- affectedFiles.push(intent.target.filePath)
57
- }
58
- break
59
- }
60
- case 'refactor':
61
- case 'move': {
62
- if (intent.target.filePath) {
63
- affectedFiles.push(intent.target.filePath)
64
- }
65
- // Add all files that import from the target
66
- const fn = Object.values(this.lock.functions).find(
67
- f => f.name === intent.target.name
68
- )
69
- if (fn) {
70
- for (const callerId of fn.calledBy) {
71
- const caller = this.lock.functions[callerId]
72
- if (caller && !affectedFiles.includes(caller.file)) {
73
- affectedFiles.push(caller.file)
74
- }
75
- }
76
- }
77
- break
78
- }
79
- }
80
-
81
- return {
82
- intent,
83
- affectedFiles: [...new Set(affectedFiles)],
84
- newFiles,
85
- estimatedImpact: affectedFiles.length + newFiles.length,
86
- implementation: this.generateDescription(intent),
87
- }
88
- }
89
-
90
- private generateDescription(intent: Intent): string {
91
- switch (intent.action) {
92
- case 'create':
93
- return `Create new ${intent.target.type} "${intent.target.name}" in module ${intent.target.moduleId || 'auto-detected'}`
94
- case 'modify':
95
- return `Modify ${intent.target.type} "${intent.target.name}" — ${intent.reason}`
96
- case 'delete':
97
- return `Delete ${intent.target.type} "${intent.target.name}" and update all references`
98
- case 'refactor':
99
- return `Refactor ${intent.target.type} "${intent.target.name}" in place`
100
- case 'move':
101
- return `Move ${intent.target.type} "${intent.target.name}" to new location`
102
- }
103
- }
104
- }
1
+ import type { MikkContract, MikkLock } from '@getmikk/core'
2
+ import type { Intent, Suggestion } from './types.js'
3
+
4
+ /**
5
+ * Suggester — given validated intents, produces implementation suggestions
6
+ * with affected files, new files, and estimated impact.
7
+ */
8
+ export class Suggester {
9
+ constructor(
10
+ private contract: MikkContract,
11
+ private lock: MikkLock
12
+ ) { }
13
+
14
+ /** Generate suggestions for a list of intents */
15
+ suggest(intents: Intent[]): Suggestion[] {
16
+ return intents.map(intent => this.suggestForIntent(intent))
17
+ }
18
+
19
+ private suggestForIntent(intent: Intent): Suggestion {
20
+ const affectedFiles: string[] = []
21
+ const newFiles: string[] = []
22
+
23
+ switch (intent.action) {
24
+ case 'create': {
25
+ // Find the target module's directory pattern
26
+ const module = this.contract.declared.modules.find(m => m.id === intent.target.moduleId)
27
+ if (module) {
28
+ const dir = module.paths[0]?.replace('/**', '') || 'src'
29
+ newFiles.push(`${dir}/${intent.target.name}.ts`)
30
+ } else {
31
+ newFiles.push(`src/${intent.target.name}.ts`)
32
+ }
33
+ break
34
+ }
35
+ case 'modify': {
36
+ if (intent.target.filePath) {
37
+ affectedFiles.push(intent.target.filePath)
38
+ } else {
39
+ // Find files by function name
40
+ const fn = Object.values(this.lock.functions).find(
41
+ f => f.name === intent.target.name
42
+ )
43
+ if (fn) {
44
+ affectedFiles.push(fn.file)
45
+ // Add callers
46
+ for (const callerId of fn.calledBy) {
47
+ const caller = this.lock.functions[callerId]
48
+ if (caller) affectedFiles.push(caller.file)
49
+ }
50
+ }
51
+ }
52
+ break
53
+ }
54
+ case 'delete': {
55
+ if (intent.target.filePath) {
56
+ affectedFiles.push(intent.target.filePath)
57
+ }
58
+ break
59
+ }
60
+ case 'refactor':
61
+ case 'move': {
62
+ if (intent.target.filePath) {
63
+ affectedFiles.push(intent.target.filePath)
64
+ }
65
+ // Add all files that import from the target
66
+ const fn = Object.values(this.lock.functions).find(
67
+ f => f.name === intent.target.name
68
+ )
69
+ if (fn) {
70
+ for (const callerId of fn.calledBy) {
71
+ const caller = this.lock.functions[callerId]
72
+ if (caller && !affectedFiles.includes(caller.file)) {
73
+ affectedFiles.push(caller.file)
74
+ }
75
+ }
76
+ }
77
+ break
78
+ }
79
+ }
80
+
81
+ return {
82
+ intent,
83
+ affectedFiles: [...new Set(affectedFiles)],
84
+ newFiles,
85
+ estimatedImpact: affectedFiles.length + newFiles.length,
86
+ implementation: this.generateDescription(intent),
87
+ }
88
+ }
89
+
90
+ private generateDescription(intent: Intent): string {
91
+ switch (intent.action) {
92
+ case 'create':
93
+ return `Create new ${intent.target.type} "${intent.target.name}" in module ${intent.target.moduleId || 'auto-detected'}`
94
+ case 'modify':
95
+ return `Modify ${intent.target.type} "${intent.target.name}" — ${intent.reason}`
96
+ case 'delete':
97
+ return `Delete ${intent.target.type} "${intent.target.name}" and update all references`
98
+ case 'refactor':
99
+ return `Refactor ${intent.target.type} "${intent.target.name}" in place`
100
+ case 'move':
101
+ return `Move ${intent.target.type} "${intent.target.name}" to new location`
102
+ }
103
+ }
104
+ }
package/src/types.ts CHANGED
@@ -1,54 +1,54 @@
1
- import { z } from 'zod'
2
-
3
- /** A single candidate intent parsed from user prompt */
4
- export const IntentSchema = z.object({
5
- action: z.enum(['create', 'modify', 'delete', 'refactor', 'move']),
6
- target: z.object({
7
- type: z.enum(['function', 'file', 'module', 'class']),
8
- name: z.string(),
9
- moduleId: z.string().optional(),
10
- filePath: z.string().optional(),
11
- }),
12
- reason: z.string(),
13
- confidence: z.number().min(0).max(1),
14
- })
15
-
16
- export type Intent = z.infer<typeof IntentSchema>
17
-
18
- /** Result of conflict detection */
19
- export interface ConflictResult {
20
- hasConflicts: boolean
21
- conflicts: Conflict[]
22
- }
23
-
24
- export interface Conflict {
25
- type: 'constraint-violation' | 'ownership-conflict' | 'boundary-crossing' | 'missing-dependency'
26
- severity: 'error' | 'warning'
27
- message: string
28
- relatedIntent: Intent
29
- suggestedFix?: string
30
- }
31
-
32
- /** A suggestion for how to implement an intent */
33
- export interface Suggestion {
34
- intent: Intent
35
- affectedFiles: string[]
36
- newFiles: string[]
37
- estimatedImpact: number
38
- implementation: string
39
- }
40
-
41
- /** Configuration for the AI provider */
42
- export interface AIProviderConfig {
43
- provider: 'anthropic' | 'openai' | 'local'
44
- apiKey?: string
45
- model?: string
46
- }
47
-
48
- /** Preflight result — the final output of the intent pipeline */
49
- export interface PreflightResult {
50
- intents: Intent[]
51
- conflicts: ConflictResult
52
- suggestions: Suggestion[]
53
- approved: boolean
54
- }
1
+ import { z } from 'zod'
2
+
3
+ /** A single candidate intent parsed from user prompt */
4
+ export const IntentSchema = z.object({
5
+ action: z.enum(['create', 'modify', 'delete', 'refactor', 'move']),
6
+ target: z.object({
7
+ type: z.enum(['function', 'file', 'module', 'class']),
8
+ name: z.string(),
9
+ moduleId: z.string().optional(),
10
+ filePath: z.string().optional(),
11
+ }),
12
+ reason: z.string(),
13
+ confidence: z.number().min(0).max(1),
14
+ })
15
+
16
+ export type Intent = z.infer<typeof IntentSchema>
17
+
18
+ /** Result of conflict detection */
19
+ export interface ConflictResult {
20
+ hasConflicts: boolean
21
+ conflicts: Conflict[]
22
+ }
23
+
24
+ export interface Conflict {
25
+ type: 'constraint-violation' | 'ownership-conflict' | 'boundary-crossing' | 'missing-dependency'
26
+ severity: 'error' | 'warning'
27
+ message: string
28
+ relatedIntent: Intent
29
+ suggestedFix?: string
30
+ }
31
+
32
+ /** A suggestion for how to implement an intent */
33
+ export interface Suggestion {
34
+ intent: Intent
35
+ affectedFiles: string[]
36
+ newFiles: string[]
37
+ estimatedImpact: number
38
+ implementation: string
39
+ }
40
+
41
+ /** Configuration for the AI provider */
42
+ export interface AIProviderConfig {
43
+ provider: 'anthropic' | 'openai' | 'local'
44
+ apiKey?: string
45
+ model?: string
46
+ }
47
+
48
+ /** Preflight result — the final output of the intent pipeline */
49
+ export interface PreflightResult {
50
+ intents: Intent[]
51
+ conflicts: ConflictResult
52
+ suggestions: Suggestion[]
53
+ approved: boolean
54
+ }