prjct-cli 0.15.1 → 0.17.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/CHANGELOG.md +35 -0
- package/bin/dev.js +0 -1
- package/bin/serve.js +19 -20
- package/core/agentic/agent-router.ts +79 -14
- package/core/agentic/command-executor/command-executor.ts +2 -74
- package/core/agentic/services.ts +0 -48
- package/core/agentic/template-loader.ts +35 -1
- package/core/commands/base.ts +96 -77
- package/core/commands/planning.ts +13 -2
- package/core/commands/setup.ts +3 -85
- package/core/errors.ts +209 -0
- package/core/infrastructure/config-manager.ts +22 -5
- package/core/infrastructure/setup.ts +5 -50
- package/core/storage/storage-manager.ts +42 -6
- package/core/utils/logger.ts +19 -12
- package/package.json +2 -4
- package/templates/agentic/subagent-generation.md +109 -0
- package/templates/commands/sync.md +74 -13
- package/templates/subagents/domain/backend.md +105 -0
- package/templates/subagents/domain/database.md +118 -0
- package/templates/subagents/domain/devops.md +148 -0
- package/templates/subagents/domain/frontend.md +99 -0
- package/templates/subagents/domain/testing.md +169 -0
- package/templates/subagents/workflow/prjct-planner.md +158 -0
- package/templates/subagents/workflow/prjct-shipper.md +179 -0
- package/templates/subagents/workflow/prjct-workflow.md +98 -0
- package/bin/generate-views.js +0 -209
- package/bin/migrate-to-json.js +0 -742
- package/core/agentic/context-filter.ts +0 -365
- package/core/agentic/parallel-tools.ts +0 -165
- package/core/agentic/response-templates.ts +0 -164
- package/core/agentic/semantic-compression.ts +0 -273
- package/core/agentic/think-blocks.ts +0 -202
- package/core/agentic/validation-rules.ts +0 -313
- package/core/domain/agent-matcher.ts +0 -130
- package/core/domain/agent-validator.ts +0 -250
- package/core/domain/architect-session.ts +0 -315
- package/core/domain/product-standards.ts +0 -106
- package/core/domain/smart-cache.ts +0 -167
- package/core/domain/task-analyzer.ts +0 -296
- package/core/infrastructure/legacy-installer-detector/cleanup.ts +0 -216
- package/core/infrastructure/legacy-installer-detector/detection.ts +0 -95
- package/core/infrastructure/legacy-installer-detector/index.ts +0 -171
- package/core/infrastructure/legacy-installer-detector/migration.ts +0 -87
- package/core/infrastructure/legacy-installer-detector/types.ts +0 -42
- package/core/infrastructure/legacy-installer-detector.ts +0 -7
- package/core/infrastructure/migrator/file-operations.ts +0 -125
- package/core/infrastructure/migrator/index.ts +0 -288
- package/core/infrastructure/migrator/project-scanner.ts +0 -90
- package/core/infrastructure/migrator/reports.ts +0 -117
- package/core/infrastructure/migrator/types.ts +0 -124
- package/core/infrastructure/migrator/validation.ts +0 -94
- package/core/infrastructure/migrator/version-migration.ts +0 -117
- package/core/infrastructure/migrator.ts +0 -10
- package/core/infrastructure/uuid-migration.ts +0 -750
- package/templates/commands/migrate-all.md +0 -96
- package/templates/commands/migrate.md +0 -140
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Semantic Compression
|
|
3
|
-
* Compresses context while preserving meaning
|
|
4
|
-
*
|
|
5
|
-
* @module agentic/semantic-compression
|
|
6
|
-
* @version 1.0.0
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
interface CompressionResult {
|
|
10
|
-
summary: string
|
|
11
|
-
originalLength: number
|
|
12
|
-
compressedLength: number
|
|
13
|
-
ratio: number
|
|
14
|
-
key: string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface CompressionMetrics {
|
|
18
|
-
totalOriginal: number
|
|
19
|
-
totalCompressed: number
|
|
20
|
-
overallRatio: number
|
|
21
|
-
compressions: number
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
class SemanticCompression {
|
|
25
|
-
private metrics: CompressionMetrics
|
|
26
|
-
|
|
27
|
-
constructor() {
|
|
28
|
-
this.metrics = {
|
|
29
|
-
totalOriginal: 0,
|
|
30
|
-
totalCompressed: 0,
|
|
31
|
-
overallRatio: 1,
|
|
32
|
-
compressions: 0,
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Compress content while preserving semantic meaning
|
|
38
|
-
*/
|
|
39
|
-
compress(content: string, key: string): CompressionResult {
|
|
40
|
-
if (!content || !content.trim()) {
|
|
41
|
-
return {
|
|
42
|
-
summary: 'Empty',
|
|
43
|
-
originalLength: 0,
|
|
44
|
-
compressedLength: 0,
|
|
45
|
-
ratio: 1,
|
|
46
|
-
key,
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const originalLength = content.length
|
|
51
|
-
let summary: string
|
|
52
|
-
|
|
53
|
-
// Apply key-specific compression strategies
|
|
54
|
-
switch (key) {
|
|
55
|
-
case 'now':
|
|
56
|
-
summary = this.compressNow(content)
|
|
57
|
-
break
|
|
58
|
-
case 'next':
|
|
59
|
-
summary = this.compressNext(content)
|
|
60
|
-
break
|
|
61
|
-
case 'shipped':
|
|
62
|
-
summary = this.compressShipped(content)
|
|
63
|
-
break
|
|
64
|
-
case 'analysis':
|
|
65
|
-
summary = this.compressAnalysis(content)
|
|
66
|
-
break
|
|
67
|
-
case 'roadmap':
|
|
68
|
-
summary = this.compressRoadmap(content)
|
|
69
|
-
break
|
|
70
|
-
case 'codePatterns':
|
|
71
|
-
summary = this.compressCodePatterns(content)
|
|
72
|
-
break
|
|
73
|
-
default:
|
|
74
|
-
summary = this.compressGeneric(content)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const compressedLength = summary.length
|
|
78
|
-
const ratio = originalLength > 0 ? compressedLength / originalLength : 1
|
|
79
|
-
|
|
80
|
-
// Update metrics
|
|
81
|
-
this.metrics.totalOriginal += originalLength
|
|
82
|
-
this.metrics.totalCompressed += compressedLength
|
|
83
|
-
this.metrics.compressions++
|
|
84
|
-
this.metrics.overallRatio =
|
|
85
|
-
this.metrics.totalOriginal > 0 ? this.metrics.totalCompressed / this.metrics.totalOriginal : 1
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
summary,
|
|
89
|
-
originalLength,
|
|
90
|
-
compressedLength,
|
|
91
|
-
ratio,
|
|
92
|
-
key,
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Compress now.md content
|
|
98
|
-
*/
|
|
99
|
-
private compressNow(content: string): string {
|
|
100
|
-
// Extract task description
|
|
101
|
-
const taskMatch = content.match(/task:\s*["']?([^"'\n]+)["']?/i) || content.match(/#+\s*(.+)/m)
|
|
102
|
-
const task = taskMatch ? taskMatch[1].trim() : 'Unknown task'
|
|
103
|
-
|
|
104
|
-
// Extract started time
|
|
105
|
-
const startedMatch = content.match(/started:\s*(.+)/i)
|
|
106
|
-
const started = startedMatch ? startedMatch[1].trim() : ''
|
|
107
|
-
|
|
108
|
-
// Extract agent if present
|
|
109
|
-
const agentMatch = content.match(/agent:\s*(.+)/i)
|
|
110
|
-
const agent = agentMatch ? agentMatch[1].trim() : ''
|
|
111
|
-
|
|
112
|
-
let summary = `Task: ${task}`
|
|
113
|
-
if (started) summary += ` | Started: ${started}`
|
|
114
|
-
if (agent) summary += ` | Agent: ${agent}`
|
|
115
|
-
|
|
116
|
-
return summary
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Compress next.md content
|
|
121
|
-
*/
|
|
122
|
-
private compressNext(content: string): string {
|
|
123
|
-
// Count tasks
|
|
124
|
-
const pending = (content.match(/- \[ \]/g) || []).length
|
|
125
|
-
const completed = (content.match(/- \[x\]/gi) || []).length
|
|
126
|
-
const total = pending + completed
|
|
127
|
-
|
|
128
|
-
// Get first few pending tasks
|
|
129
|
-
const taskLines = content.match(/- \[ \] .+/g) || []
|
|
130
|
-
const topTasks = taskLines.slice(0, 3).map((t) => t.replace('- [ ] ', '').trim())
|
|
131
|
-
|
|
132
|
-
let summary = `Queue: ${pending} pending, ${completed} done (${total} total)`
|
|
133
|
-
if (topTasks.length > 0) {
|
|
134
|
-
summary += ` | Next: ${topTasks.join(', ')}`
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return summary
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Compress shipped.md content
|
|
142
|
-
*/
|
|
143
|
-
private compressShipped(content: string): string {
|
|
144
|
-
// Count shipped items
|
|
145
|
-
const shipped = (content.match(/^##\s+/gm) || []).length
|
|
146
|
-
const lines = content.split('\n')
|
|
147
|
-
|
|
148
|
-
// Get most recent ship
|
|
149
|
-
let recentShip = ''
|
|
150
|
-
for (const line of lines) {
|
|
151
|
-
if (line.startsWith('## ')) {
|
|
152
|
-
recentShip = line.replace('## ', '').trim()
|
|
153
|
-
break
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
let summary = `Shipped: ${shipped} items`
|
|
158
|
-
if (recentShip) summary += ` | Recent: ${recentShip.substring(0, 50)}`
|
|
159
|
-
|
|
160
|
-
return summary
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Compress analysis content
|
|
165
|
-
*/
|
|
166
|
-
private compressAnalysis(content: string): string {
|
|
167
|
-
// Extract stack
|
|
168
|
-
const stackMatch =
|
|
169
|
-
content.match(/stack[:\s]+([^\n]+)/i) ||
|
|
170
|
-
content.match(/technology[:\s]+([^\n]+)/i) ||
|
|
171
|
-
content.match(/framework[:\s]+([^\n]+)/i)
|
|
172
|
-
const stack = stackMatch ? stackMatch[1].trim() : 'Unknown'
|
|
173
|
-
|
|
174
|
-
// Extract file count if present
|
|
175
|
-
const filesMatch = content.match(/(\d+)\s*files/i)
|
|
176
|
-
const files = filesMatch ? filesMatch[1] : ''
|
|
177
|
-
|
|
178
|
-
// Extract language
|
|
179
|
-
const langMatch = content.match(/language[:\s]+([^\n]+)/i) || content.match(/primary[:\s]+([^\n]+)/i)
|
|
180
|
-
const language = langMatch ? langMatch[1].trim() : ''
|
|
181
|
-
|
|
182
|
-
let summary = `Stack: ${stack}`
|
|
183
|
-
if (language) summary += ` | Language: ${language}`
|
|
184
|
-
if (files) summary += ` | Files: ${files}`
|
|
185
|
-
|
|
186
|
-
return summary
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Compress roadmap content
|
|
191
|
-
*/
|
|
192
|
-
private compressRoadmap(content: string): string {
|
|
193
|
-
// Count features
|
|
194
|
-
const features = (content.match(/^##\s+/gm) || []).length
|
|
195
|
-
|
|
196
|
-
// Get feature names
|
|
197
|
-
const featureNames: string[] = []
|
|
198
|
-
const matches = content.match(/^##\s+(.+)/gm) || []
|
|
199
|
-
matches.slice(0, 3).forEach((m) => {
|
|
200
|
-
featureNames.push(m.replace(/^##\s+/, '').trim())
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
let summary = `Roadmap: ${features} features`
|
|
204
|
-
if (featureNames.length > 0) {
|
|
205
|
-
summary += ` | Top: ${featureNames.join(', ')}`
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return summary
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Compress code patterns content
|
|
213
|
-
*/
|
|
214
|
-
private compressCodePatterns(content: string): string {
|
|
215
|
-
// Extract conventions section
|
|
216
|
-
const conventionsMatch = content.match(/## Conventions[\s\S]*?(?=##|$)/i)
|
|
217
|
-
let conventions = ''
|
|
218
|
-
if (conventionsMatch) {
|
|
219
|
-
const lines = conventionsMatch[0]
|
|
220
|
-
.split('\n')
|
|
221
|
-
.filter((l) => l.includes(':') || l.startsWith('-'))
|
|
222
|
-
.slice(0, 3)
|
|
223
|
-
conventions = lines.join(' | ')
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// Check for anti-patterns
|
|
227
|
-
const hasAntiPatterns = content.toLowerCase().includes('anti-pattern')
|
|
228
|
-
|
|
229
|
-
let summary = 'Code patterns loaded'
|
|
230
|
-
if (conventions) summary += ` | ${conventions.substring(0, 100)}`
|
|
231
|
-
if (hasAntiPatterns) summary += ' | Has anti-patterns'
|
|
232
|
-
|
|
233
|
-
return summary
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Generic compression
|
|
238
|
-
*/
|
|
239
|
-
private compressGeneric(content: string): string {
|
|
240
|
-
// Take first meaningful lines
|
|
241
|
-
const lines = content.split('\n').filter((l) => l.trim() && !l.startsWith('#'))
|
|
242
|
-
const preview = lines.slice(0, 2).join(' | ')
|
|
243
|
-
|
|
244
|
-
if (preview.length > 150) {
|
|
245
|
-
return preview.substring(0, 150) + '...'
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return preview || 'Content available'
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Get compression metrics
|
|
253
|
-
*/
|
|
254
|
-
getMetrics(): CompressionMetrics {
|
|
255
|
-
return { ...this.metrics }
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Reset metrics
|
|
260
|
-
*/
|
|
261
|
-
resetMetrics(): void {
|
|
262
|
-
this.metrics = {
|
|
263
|
-
totalOriginal: 0,
|
|
264
|
-
totalCompressed: 0,
|
|
265
|
-
overallRatio: 1,
|
|
266
|
-
compressions: 0,
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const semanticCompression = new SemanticCompression()
|
|
272
|
-
export default semanticCompression
|
|
273
|
-
export { SemanticCompression }
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Think Blocks
|
|
3
|
-
* Dynamic reasoning blocks for complex decisions
|
|
4
|
-
*
|
|
5
|
-
* @module agentic/think-blocks
|
|
6
|
-
* @version 1.0.0
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
interface Context {
|
|
10
|
-
params: Record<string, unknown>
|
|
11
|
-
[key: string]: unknown
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
interface State {
|
|
15
|
-
now?: string | null
|
|
16
|
-
analysis?: string | null
|
|
17
|
-
codePatterns?: string | null
|
|
18
|
-
[key: string]: unknown
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface ThinkTrigger {
|
|
22
|
-
type: string
|
|
23
|
-
reason: string
|
|
24
|
-
priority: 'high' | 'medium' | 'low'
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
interface ThinkBlock {
|
|
28
|
-
trigger: ThinkTrigger
|
|
29
|
-
commandName: string
|
|
30
|
-
conclusions: string[]
|
|
31
|
-
plan: string[]
|
|
32
|
-
confidence: number
|
|
33
|
-
generatedAt: string
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Detect if a think block is needed
|
|
38
|
-
*/
|
|
39
|
-
function detectTrigger(commandName: string, context: Context, state: State): ThinkTrigger | null {
|
|
40
|
-
// High-priority triggers (always think)
|
|
41
|
-
const highPriorityCommands = ['ship', 'cleanup', 'migrate']
|
|
42
|
-
if (highPriorityCommands.includes(commandName)) {
|
|
43
|
-
return {
|
|
44
|
-
type: 'critical_command',
|
|
45
|
-
reason: `${commandName} is a critical command requiring careful planning`,
|
|
46
|
-
priority: 'high',
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Check for complex task
|
|
51
|
-
const taskDescription = (context.params.task as string) || (context.params.description as string) || ''
|
|
52
|
-
if (taskDescription.length > 100) {
|
|
53
|
-
return {
|
|
54
|
-
type: 'complex_task',
|
|
55
|
-
reason: 'Task description is complex, requiring analysis',
|
|
56
|
-
priority: 'medium',
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Check for existing task (potential conflict)
|
|
61
|
-
if (state.now && !state.now.includes('No current task') && commandName === 'now') {
|
|
62
|
-
return {
|
|
63
|
-
type: 'task_conflict',
|
|
64
|
-
reason: 'Already has active task, need to decide how to handle',
|
|
65
|
-
priority: 'medium',
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Check if analysis exists (context-aware)
|
|
70
|
-
if (!state.analysis && ['feature', 'spec', 'design'].includes(commandName)) {
|
|
71
|
-
return {
|
|
72
|
-
type: 'missing_context',
|
|
73
|
-
reason: 'No project analysis available, may need /p:sync first',
|
|
74
|
-
priority: 'low',
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Check for code patterns
|
|
79
|
-
if (!state.codePatterns && ['now', 'build', 'fix'].includes(commandName)) {
|
|
80
|
-
return {
|
|
81
|
-
type: 'missing_patterns',
|
|
82
|
-
reason: 'No code patterns detected, may produce inconsistent code',
|
|
83
|
-
priority: 'low',
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return null
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Generate a think block
|
|
92
|
-
*/
|
|
93
|
-
async function generate(
|
|
94
|
-
trigger: ThinkTrigger,
|
|
95
|
-
commandName: string,
|
|
96
|
-
context: Context,
|
|
97
|
-
state: State
|
|
98
|
-
): Promise<ThinkBlock> {
|
|
99
|
-
const conclusions: string[] = []
|
|
100
|
-
const plan: string[] = []
|
|
101
|
-
let confidence = 0.8
|
|
102
|
-
|
|
103
|
-
switch (trigger.type) {
|
|
104
|
-
case 'critical_command':
|
|
105
|
-
conclusions.push(`${commandName} requires careful execution`)
|
|
106
|
-
conclusions.push('Will verify state before proceeding')
|
|
107
|
-
plan.push('Check current state')
|
|
108
|
-
plan.push('Verify prerequisites')
|
|
109
|
-
plan.push('Execute with confirmation')
|
|
110
|
-
plan.push('Verify results')
|
|
111
|
-
confidence = 0.9
|
|
112
|
-
break
|
|
113
|
-
|
|
114
|
-
case 'complex_task':
|
|
115
|
-
conclusions.push('Task appears complex, breaking down')
|
|
116
|
-
conclusions.push('Will analyze dependencies first')
|
|
117
|
-
plan.push('Parse task requirements')
|
|
118
|
-
plan.push('Identify affected components')
|
|
119
|
-
plan.push('Create execution plan')
|
|
120
|
-
plan.push('Execute incrementally')
|
|
121
|
-
confidence = 0.7
|
|
122
|
-
break
|
|
123
|
-
|
|
124
|
-
case 'task_conflict':
|
|
125
|
-
conclusions.push('Existing task detected')
|
|
126
|
-
conclusions.push('Should complete or pause current task first')
|
|
127
|
-
plan.push('Check current task status')
|
|
128
|
-
plan.push('Decide: complete, pause, or replace')
|
|
129
|
-
plan.push('Update task state')
|
|
130
|
-
plan.push('Proceed with new task')
|
|
131
|
-
confidence = 0.6
|
|
132
|
-
break
|
|
133
|
-
|
|
134
|
-
case 'missing_context':
|
|
135
|
-
conclusions.push('Project analysis not available')
|
|
136
|
-
conclusions.push('May produce less optimal results')
|
|
137
|
-
plan.push('Proceed with available context')
|
|
138
|
-
plan.push('Note recommendation to run /p:sync')
|
|
139
|
-
confidence = 0.5
|
|
140
|
-
break
|
|
141
|
-
|
|
142
|
-
case 'missing_patterns':
|
|
143
|
-
conclusions.push('Code patterns not detected')
|
|
144
|
-
conclusions.push('Will use best-effort pattern matching')
|
|
145
|
-
plan.push('Read existing code for patterns')
|
|
146
|
-
plan.push('Match detected style')
|
|
147
|
-
plan.push('Generate consistent code')
|
|
148
|
-
confidence = 0.6
|
|
149
|
-
break
|
|
150
|
-
|
|
151
|
-
default:
|
|
152
|
-
conclusions.push('Standard execution path')
|
|
153
|
-
plan.push('Execute command as specified')
|
|
154
|
-
confidence = 0.8
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return {
|
|
158
|
-
trigger,
|
|
159
|
-
commandName,
|
|
160
|
-
conclusions,
|
|
161
|
-
plan,
|
|
162
|
-
confidence,
|
|
163
|
-
generatedAt: new Date().toISOString(),
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Format think block for display
|
|
169
|
-
*/
|
|
170
|
-
function format(thinkBlock: ThinkBlock | null, verbose: boolean = false): string {
|
|
171
|
-
if (!thinkBlock) {
|
|
172
|
-
return ''
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const lines: string[] = []
|
|
176
|
-
|
|
177
|
-
if (verbose) {
|
|
178
|
-
lines.push(`🧠 Think Block: ${thinkBlock.commandName}`)
|
|
179
|
-
lines.push(`Trigger: ${thinkBlock.trigger.type} (${thinkBlock.trigger.priority})`)
|
|
180
|
-
lines.push(`Reason: ${thinkBlock.trigger.reason}`)
|
|
181
|
-
lines.push('')
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
lines.push('Conclusions:')
|
|
185
|
-
thinkBlock.conclusions.forEach((c) => {
|
|
186
|
-
lines.push(` → ${c}`)
|
|
187
|
-
})
|
|
188
|
-
|
|
189
|
-
lines.push('')
|
|
190
|
-
lines.push('Plan:')
|
|
191
|
-
thinkBlock.plan.forEach((p, i) => {
|
|
192
|
-
lines.push(` ${i + 1}. ${p}`)
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
lines.push('')
|
|
196
|
-
lines.push(`Confidence: ${Math.round(thinkBlock.confidence * 100)}%`)
|
|
197
|
-
|
|
198
|
-
return lines.join('\n')
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
export { detectTrigger, generate, format }
|
|
202
|
-
export default { detectTrigger, generate, format }
|