prjct-cli 0.45.0 → 0.45.3
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 +75 -0
- package/bin/prjct.ts +117 -10
- package/core/__tests__/agentic/memory-system.test.ts +39 -26
- package/core/__tests__/agentic/plan-mode.test.ts +64 -46
- package/core/__tests__/agentic/prompt-builder.test.ts +14 -14
- package/core/__tests__/services/project-index.test.ts +353 -0
- package/core/__tests__/types/fs.test.ts +3 -3
- package/core/__tests__/utils/date-helper.test.ts +10 -10
- package/core/__tests__/utils/output.test.ts +9 -6
- package/core/__tests__/utils/project-commands.test.ts +5 -6
- package/core/agentic/agent-router.ts +9 -10
- package/core/agentic/chain-of-thought.ts +16 -4
- package/core/agentic/command-executor.ts +66 -40
- package/core/agentic/context-builder.ts +8 -5
- package/core/agentic/ground-truth.ts +15 -9
- package/core/agentic/index.ts +145 -152
- package/core/agentic/loop-detector.ts +40 -11
- package/core/agentic/memory-system.ts +98 -35
- package/core/agentic/orchestrator-executor.ts +135 -71
- package/core/agentic/plan-mode.ts +46 -16
- package/core/agentic/prompt-builder.ts +108 -42
- package/core/agentic/services.ts +10 -9
- package/core/agentic/skill-loader.ts +9 -15
- package/core/agentic/smart-context.ts +129 -79
- package/core/agentic/template-executor.ts +13 -12
- package/core/agentic/template-loader.ts +7 -4
- package/core/agentic/tool-registry.ts +16 -13
- package/core/agents/index.ts +1 -1
- package/core/agents/performance.ts +10 -27
- package/core/ai-tools/formatters.ts +8 -6
- package/core/ai-tools/generator.ts +4 -4
- package/core/ai-tools/index.ts +1 -1
- package/core/ai-tools/registry.ts +21 -11
- package/core/bus/bus.ts +23 -16
- package/core/bus/index.ts +2 -2
- package/core/cli/linear.ts +3 -5
- package/core/cli/start.ts +28 -25
- package/core/commands/analysis.ts +58 -39
- package/core/commands/analytics.ts +52 -44
- package/core/commands/base.ts +15 -13
- package/core/commands/cleanup.ts +6 -13
- package/core/commands/command-data.ts +28 -4
- package/core/commands/commands.ts +57 -24
- package/core/commands/context.ts +4 -4
- package/core/commands/design.ts +3 -10
- package/core/commands/index.ts +5 -8
- package/core/commands/maintenance.ts +7 -4
- package/core/commands/planning.ts +179 -56
- package/core/commands/register.ts +13 -9
- package/core/commands/registry.ts +15 -14
- package/core/commands/setup.ts +26 -14
- package/core/commands/shipping.ts +11 -16
- package/core/commands/snapshots.ts +16 -32
- package/core/commands/uninstall.ts +541 -0
- package/core/commands/workflow.ts +24 -28
- package/core/constants/index.ts +10 -22
- package/core/context/generator.ts +82 -33
- package/core/context-tools/files-tool.ts +18 -19
- package/core/context-tools/imports-tool.ts +13 -33
- package/core/context-tools/index.ts +29 -54
- package/core/context-tools/recent-tool.ts +16 -22
- package/core/context-tools/signatures-tool.ts +17 -26
- package/core/context-tools/summary-tool.ts +20 -22
- package/core/context-tools/token-counter.ts +25 -20
- package/core/context-tools/types.ts +5 -5
- package/core/domain/agent-generator.ts +7 -5
- package/core/domain/agent-loader.ts +2 -2
- package/core/domain/analyzer.ts +19 -16
- package/core/domain/architecture-generator.ts +6 -3
- package/core/domain/context-estimator.ts +3 -4
- package/core/domain/snapshot-manager.ts +25 -22
- package/core/domain/task-stack.ts +24 -14
- package/core/errors.ts +1 -1
- package/core/events/events.ts +2 -4
- package/core/events/index.ts +1 -2
- package/core/index.ts +28 -16
- package/core/infrastructure/agent-detector.ts +3 -3
- package/core/infrastructure/ai-provider.ts +23 -20
- package/core/infrastructure/author-detector.ts +16 -10
- package/core/infrastructure/capability-installer.ts +2 -2
- package/core/infrastructure/claude-agent.ts +6 -6
- package/core/infrastructure/command-installer.ts +22 -17
- package/core/infrastructure/config-manager.ts +18 -14
- package/core/infrastructure/editors-config.ts +8 -4
- package/core/infrastructure/path-manager.ts +8 -6
- package/core/infrastructure/permission-manager.ts +20 -17
- package/core/infrastructure/setup.ts +42 -38
- package/core/infrastructure/update-checker.ts +5 -5
- package/core/integrations/issue-tracker/enricher.ts +8 -19
- package/core/integrations/issue-tracker/index.ts +2 -2
- package/core/integrations/issue-tracker/manager.ts +15 -15
- package/core/integrations/issue-tracker/types.ts +5 -22
- package/core/integrations/jira/client.ts +67 -59
- package/core/integrations/jira/index.ts +11 -14
- package/core/integrations/jira/mcp-adapter.ts +5 -10
- package/core/integrations/jira/service.ts +10 -10
- package/core/integrations/linear/client.ts +27 -18
- package/core/integrations/linear/index.ts +9 -12
- package/core/integrations/linear/service.ts +11 -11
- package/core/integrations/linear/sync.ts +8 -8
- package/core/outcomes/analyzer.ts +5 -18
- package/core/outcomes/index.ts +2 -2
- package/core/outcomes/recorder.ts +3 -3
- package/core/plugin/builtin/webhook.ts +19 -15
- package/core/plugin/hooks.ts +29 -21
- package/core/plugin/index.ts +7 -7
- package/core/plugin/loader.ts +19 -19
- package/core/plugin/registry.ts +12 -23
- package/core/schemas/agents.ts +1 -1
- package/core/schemas/analysis.ts +1 -1
- package/core/schemas/enriched-task.ts +62 -49
- package/core/schemas/ideas.ts +13 -13
- package/core/schemas/index.ts +17 -27
- package/core/schemas/issues.ts +40 -25
- package/core/schemas/metrics.ts +25 -25
- package/core/schemas/outcomes.ts +70 -62
- package/core/schemas/permissions.ts +15 -12
- package/core/schemas/prd.ts +27 -14
- package/core/schemas/project.ts +3 -3
- package/core/schemas/roadmap.ts +47 -34
- package/core/schemas/schemas.ts +3 -4
- package/core/schemas/shipped.ts +3 -3
- package/core/schemas/state.ts +43 -29
- package/core/server/index.ts +5 -6
- package/core/server/routes-extended.ts +68 -72
- package/core/server/routes.ts +3 -3
- package/core/server/server.ts +31 -26
- package/core/services/agent-generator.ts +237 -0
- package/core/services/agent-service.ts +2 -2
- package/core/services/breakdown-service.ts +2 -4
- package/core/services/context-generator.ts +299 -0
- package/core/services/context-selector.ts +420 -0
- package/core/services/doctor-service.ts +426 -0
- package/core/services/file-categorizer.ts +448 -0
- package/core/services/file-scorer.ts +270 -0
- package/core/services/git-analyzer.ts +267 -0
- package/core/services/index.ts +27 -10
- package/core/services/memory-service.ts +3 -4
- package/core/services/project-index.ts +911 -0
- package/core/services/project-service.ts +4 -4
- package/core/services/skill-installer.ts +14 -17
- package/core/services/skill-lock.ts +3 -3
- package/core/services/skill-service.ts +12 -6
- package/core/services/stack-detector.ts +245 -0
- package/core/services/sync-service.ts +87 -345
- package/core/services/watch-service.ts +294 -0
- package/core/session/compaction.ts +23 -31
- package/core/session/index.ts +11 -5
- package/core/session/log-migration.ts +3 -3
- package/core/session/metrics.ts +19 -14
- package/core/session/session-log-manager.ts +12 -17
- package/core/session/task-session-manager.ts +25 -25
- package/core/session/utils.ts +1 -1
- package/core/storage/ideas-storage.ts +41 -57
- package/core/storage/index-storage.ts +514 -0
- package/core/storage/index.ts +41 -17
- package/core/storage/metrics-storage.ts +39 -34
- package/core/storage/queue-storage.ts +35 -45
- package/core/storage/shipped-storage.ts +17 -20
- package/core/storage/state-storage.ts +50 -30
- package/core/storage/storage-manager.ts +6 -6
- package/core/storage/storage.ts +18 -15
- package/core/sync/auth-config.ts +3 -3
- package/core/sync/index.ts +13 -19
- package/core/sync/oauth-handler.ts +3 -3
- package/core/sync/sync-client.ts +4 -9
- package/core/sync/sync-manager.ts +12 -14
- package/core/types/commands.ts +42 -7
- package/core/types/index.ts +284 -305
- package/core/types/integrations.ts +3 -3
- package/core/types/storage.ts +14 -14
- package/core/types/utils.ts +3 -3
- package/core/utils/agent-stream.ts +3 -1
- package/core/utils/animations.ts +14 -11
- package/core/utils/branding.ts +7 -7
- package/core/utils/cache.ts +1 -3
- package/core/utils/collection-filters.ts +3 -15
- package/core/utils/date-helper.ts +2 -7
- package/core/utils/file-helper.ts +13 -8
- package/core/utils/jsonl-helper.ts +13 -10
- package/core/utils/keychain.ts +4 -8
- package/core/utils/logger.ts +1 -1
- package/core/utils/next-steps.ts +3 -3
- package/core/utils/output.ts +58 -11
- package/core/utils/project-commands.ts +6 -6
- package/core/utils/project-credentials.ts +5 -12
- package/core/utils/runtime.ts +2 -2
- package/core/utils/session-helper.ts +3 -4
- package/core/utils/version.ts +3 -3
- package/core/wizard/index.ts +13 -0
- package/core/wizard/onboarding.ts +633 -0
- package/core/workflow/state-machine.ts +7 -7
- package/dist/bin/prjct.mjs +18755 -15574
- package/dist/core/infrastructure/command-installer.js +86 -79
- package/dist/core/infrastructure/editors-config.js +6 -6
- package/dist/core/infrastructure/setup.js +246 -225
- package/dist/core/utils/version.js +9 -9
- package/package.json +11 -12
- package/scripts/build.js +3 -3
- package/scripts/postinstall.js +2 -2
- package/templates/mcp-config.json +6 -1
- package/templates/permissions/permissive.jsonc +1 -1
- package/templates/permissions/strict.jsonc +5 -9
- package/templates/global/docs/agents.md +0 -88
- package/templates/global/docs/architecture.md +0 -103
- package/templates/global/docs/commands.md +0 -96
- package/templates/global/docs/validation.md +0 -95
|
@@ -5,14 +5,8 @@
|
|
|
5
5
|
* Powers the learning loop for better estimates and agent selection.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import type { AgentMetrics, DetectedPattern, Outcome, OutcomeSummary } from '../types'
|
|
8
9
|
import outcomeRecorder from './recorder'
|
|
9
|
-
import type {
|
|
10
|
-
Outcome,
|
|
11
|
-
OutcomeSummary,
|
|
12
|
-
QualityScore,
|
|
13
|
-
DetectedPattern,
|
|
14
|
-
AgentMetrics,
|
|
15
|
-
} from '../types'
|
|
16
10
|
|
|
17
11
|
/**
|
|
18
12
|
* OutcomeAnalyzer - Extracts insights from outcomes.
|
|
@@ -36,8 +30,7 @@ export class OutcomeAnalyzer {
|
|
|
36
30
|
}
|
|
37
31
|
|
|
38
32
|
// Calculate average quality
|
|
39
|
-
const avgQuality =
|
|
40
|
-
outcomes.reduce((sum, o) => sum + o.qualityScore, 0) / outcomes.length
|
|
33
|
+
const avgQuality = outcomes.reduce((sum, o) => sum + o.qualityScore, 0) / outcomes.length
|
|
41
34
|
|
|
42
35
|
// Calculate estimate accuracy
|
|
43
36
|
const estimateAccuracy = await outcomeRecorder.getEstimateAccuracy(projectId)
|
|
@@ -98,8 +91,7 @@ export class OutcomeAnalyzer {
|
|
|
98
91
|
const successful = agentOutcomes.filter((o) => o.completedAsPlanned)
|
|
99
92
|
const successRate = Math.round((successful.length / tasksCompleted) * 100)
|
|
100
93
|
|
|
101
|
-
const avgQuality =
|
|
102
|
-
agentOutcomes.reduce((sum, o) => sum + o.qualityScore, 0) / tasksCompleted
|
|
94
|
+
const avgQuality = agentOutcomes.reduce((sum, o) => sum + o.qualityScore, 0) / tasksCompleted
|
|
103
95
|
|
|
104
96
|
// Calculate estimate accuracy for this agent
|
|
105
97
|
const accurateEstimates = agentOutcomes.filter((o) => {
|
|
@@ -109,9 +101,7 @@ export class OutcomeAnalyzer {
|
|
|
109
101
|
if (estimated === 0) return false
|
|
110
102
|
return Math.abs(variance) / estimated <= 0.2
|
|
111
103
|
})
|
|
112
|
-
const estimateAccuracy = Math.round(
|
|
113
|
-
(accurateEstimates.length / tasksCompleted) * 100
|
|
114
|
-
)
|
|
104
|
+
const estimateAccuracy = Math.round((accurateEstimates.length / tasksCompleted) * 100)
|
|
115
105
|
|
|
116
106
|
// Find best task types
|
|
117
107
|
const taskTypes = new Map<string, number>()
|
|
@@ -214,10 +204,7 @@ export class OutcomeAnalyzer {
|
|
|
214
204
|
/**
|
|
215
205
|
* Suggest estimate for a task type based on history.
|
|
216
206
|
*/
|
|
217
|
-
async suggestEstimate(
|
|
218
|
-
projectId: string,
|
|
219
|
-
taskType: string
|
|
220
|
-
): Promise<string | null> {
|
|
207
|
+
async suggestEstimate(projectId: string, taskType: string): Promise<string | null> {
|
|
221
208
|
const outcomes = await outcomeRecorder.getAll(projectId)
|
|
222
209
|
|
|
223
210
|
// Filter by task type (using tags)
|
package/core/outcomes/index.ts
CHANGED
|
@@ -29,6 +29,6 @@
|
|
|
29
29
|
* ```
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
|
-
export { OutcomeRecorder, default as outcomeRecorder } from './recorder'
|
|
33
|
-
export { OutcomeAnalyzer, default as outcomeAnalyzer } from './analyzer'
|
|
34
32
|
export * from '../types'
|
|
33
|
+
export { default as outcomeAnalyzer, OutcomeAnalyzer } from './analyzer'
|
|
34
|
+
export { default as outcomeRecorder, OutcomeRecorder } from './recorder'
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
* Appends to JSONL files for efficient streaming.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import path from 'path'
|
|
9
|
-
import * as fileHelper from '../utils/file-helper'
|
|
8
|
+
import path from 'node:path'
|
|
10
9
|
import pathManager from '../infrastructure/path-manager'
|
|
11
10
|
import { generateUUID } from '../schemas'
|
|
12
|
-
import type { Outcome,
|
|
11
|
+
import type { Outcome, OutcomeFilter, OutcomeInput } from '../types'
|
|
12
|
+
import * as fileHelper from '../utils/file-helper'
|
|
13
13
|
|
|
14
14
|
const OUTCOMES_DIR = 'outcomes'
|
|
15
15
|
const OUTCOMES_FILE = 'outcomes.jsonl'
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
* }
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import crypto from 'crypto'
|
|
20
|
+
import crypto from 'node:crypto'
|
|
21
21
|
import { EventTypes } from '../../bus'
|
|
22
|
+
import type { WebhookConfig, WebhookPayload, WebhookPluginContext } from '../../types'
|
|
22
23
|
import { HookPoints } from '../hooks'
|
|
23
|
-
import type { WebhookConfig, WebhookPluginContext, WebhookPayload } from '../../types'
|
|
24
24
|
|
|
25
25
|
const plugin = {
|
|
26
26
|
name: 'webhook',
|
|
@@ -47,7 +47,7 @@ const plugin = {
|
|
|
47
47
|
plugin.enabledEvents = config.events || [
|
|
48
48
|
EventTypes.SESSION_COMPLETED,
|
|
49
49
|
EventTypes.FEATURE_SHIPPED,
|
|
50
|
-
EventTypes.SNAPSHOT_CREATED
|
|
50
|
+
EventTypes.SNAPSHOT_CREATED,
|
|
51
51
|
]
|
|
52
52
|
},
|
|
53
53
|
|
|
@@ -62,34 +62,38 @@ const plugin = {
|
|
|
62
62
|
* Event handlers
|
|
63
63
|
*/
|
|
64
64
|
events: {
|
|
65
|
-
[EventTypes.SESSION_COMPLETED]: async
|
|
65
|
+
[EventTypes.SESSION_COMPLETED]: async (data: unknown): Promise<void> => {
|
|
66
66
|
await plugin.sendWebhook('session.completed', data)
|
|
67
67
|
},
|
|
68
68
|
|
|
69
|
-
[EventTypes.FEATURE_SHIPPED]: async
|
|
69
|
+
[EventTypes.FEATURE_SHIPPED]: async (data: unknown): Promise<void> => {
|
|
70
70
|
await plugin.sendWebhook('feature.shipped', data)
|
|
71
71
|
},
|
|
72
72
|
|
|
73
|
-
[EventTypes.SNAPSHOT_CREATED]: async
|
|
73
|
+
[EventTypes.SNAPSHOT_CREATED]: async (data: unknown): Promise<void> => {
|
|
74
74
|
await plugin.sendWebhook('snapshot.created', data)
|
|
75
75
|
},
|
|
76
76
|
|
|
77
|
-
[EventTypes.TASK_COMPLETED]: async
|
|
77
|
+
[EventTypes.TASK_COMPLETED]: async (data: unknown): Promise<void> => {
|
|
78
78
|
await plugin.sendWebhook('task.completed', data)
|
|
79
|
-
}
|
|
79
|
+
},
|
|
80
80
|
},
|
|
81
81
|
|
|
82
82
|
/**
|
|
83
83
|
* Hook handlers
|
|
84
84
|
*/
|
|
85
85
|
hooks: {
|
|
86
|
-
[HookPoints.AFTER_FEATURE_SHIP]: async
|
|
86
|
+
[HookPoints.AFTER_FEATURE_SHIP]: async (data: {
|
|
87
|
+
feature: string
|
|
88
|
+
version: string
|
|
89
|
+
timestamp: string
|
|
90
|
+
}): Promise<void> => {
|
|
87
91
|
await plugin.sendWebhook('feature.shipped', {
|
|
88
92
|
feature: data.feature,
|
|
89
93
|
version: data.version,
|
|
90
|
-
timestamp: data.timestamp
|
|
94
|
+
timestamp: data.timestamp,
|
|
91
95
|
})
|
|
92
|
-
}
|
|
96
|
+
},
|
|
93
97
|
},
|
|
94
98
|
|
|
95
99
|
/**
|
|
@@ -107,13 +111,13 @@ const plugin = {
|
|
|
107
111
|
event,
|
|
108
112
|
timestamp: new Date().toISOString(),
|
|
109
113
|
source: 'prjct-cli',
|
|
110
|
-
data
|
|
114
|
+
data,
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
try {
|
|
114
118
|
const headers: Record<string, string> = {
|
|
115
119
|
'Content-Type': 'application/json',
|
|
116
|
-
'User-Agent': 'prjct-cli/webhook'
|
|
120
|
+
'User-Agent': 'prjct-cli/webhook',
|
|
117
121
|
}
|
|
118
122
|
|
|
119
123
|
// Add signature if secret is configured
|
|
@@ -128,7 +132,7 @@ const plugin = {
|
|
|
128
132
|
const response = await fetch(plugin.config.url, {
|
|
129
133
|
method: 'POST',
|
|
130
134
|
headers,
|
|
131
|
-
body: JSON.stringify(payload)
|
|
135
|
+
body: JSON.stringify(payload),
|
|
132
136
|
})
|
|
133
137
|
|
|
134
138
|
if (!response.ok) {
|
|
@@ -137,7 +141,7 @@ const plugin = {
|
|
|
137
141
|
} catch (error) {
|
|
138
142
|
console.error(`[webhook] Error sending webhook:`, (error as Error).message)
|
|
139
143
|
}
|
|
140
|
-
}
|
|
144
|
+
},
|
|
141
145
|
}
|
|
142
146
|
|
|
143
147
|
export default plugin
|
package/core/plugin/hooks.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @version 1.0.0
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { EventTypes, eventBus } from '../bus'
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Hook Points - Where plugins can intercept
|
|
@@ -37,10 +37,10 @@ const HookPoints = {
|
|
|
37
37
|
// Transform hooks (must return modified data)
|
|
38
38
|
TRANSFORM_COMMIT_MESSAGE: 'transform:commit.message',
|
|
39
39
|
TRANSFORM_TASK_DATA: 'transform:task.data',
|
|
40
|
-
TRANSFORM_METRICS: 'transform:metrics'
|
|
40
|
+
TRANSFORM_METRICS: 'transform:metrics',
|
|
41
41
|
} as const
|
|
42
42
|
|
|
43
|
-
type HookPoint = typeof HookPoints[keyof typeof HookPoints]
|
|
43
|
+
type HookPoint = (typeof HookPoints)[keyof typeof HookPoints]
|
|
44
44
|
type HookHandler = (data: unknown, context?: unknown) => unknown | Promise<unknown>
|
|
45
45
|
|
|
46
46
|
interface HookEntry {
|
|
@@ -83,7 +83,7 @@ class HookSystem {
|
|
|
83
83
|
handler,
|
|
84
84
|
pluginName,
|
|
85
85
|
priority,
|
|
86
|
-
id: `${pluginName}:${Date.now()}
|
|
86
|
+
id: `${pluginName}:${Date.now()}`,
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
this.hooks.get(hookPoint)!.push(hookEntry)
|
|
@@ -107,7 +107,7 @@ class HookSystem {
|
|
|
107
107
|
unregister(hookPoint: string, id: string): void {
|
|
108
108
|
const hooks = this.hooks.get(hookPoint)
|
|
109
109
|
if (hooks) {
|
|
110
|
-
const index = hooks.findIndex(h => h.id === id)
|
|
110
|
+
const index = hooks.findIndex((h) => h.id === id)
|
|
111
111
|
if (index !== -1) {
|
|
112
112
|
hooks.splice(index, 1)
|
|
113
113
|
}
|
|
@@ -130,7 +130,10 @@ class HookSystem {
|
|
|
130
130
|
/**
|
|
131
131
|
* Execute a "before" hook (can modify data)
|
|
132
132
|
*/
|
|
133
|
-
async executeBefore(
|
|
133
|
+
async executeBefore(
|
|
134
|
+
hookPoint: string,
|
|
135
|
+
data: Record<string, unknown>
|
|
136
|
+
): Promise<Record<string, unknown>> {
|
|
134
137
|
const hooks = this.hooks.get(hookPoint) || []
|
|
135
138
|
let result = { ...data }
|
|
136
139
|
|
|
@@ -157,11 +160,14 @@ class HookSystem {
|
|
|
157
160
|
|
|
158
161
|
// Execute all hooks in parallel for after hooks
|
|
159
162
|
await Promise.allSettled(
|
|
160
|
-
hooks.map(async hook => {
|
|
163
|
+
hooks.map(async (hook) => {
|
|
161
164
|
try {
|
|
162
165
|
await hook.handler(data)
|
|
163
166
|
} catch (error) {
|
|
164
|
-
console.error(
|
|
167
|
+
console.error(
|
|
168
|
+
`Hook error [${hook.pluginName}] at ${hookPoint}:`,
|
|
169
|
+
(error as Error).message
|
|
170
|
+
)
|
|
165
171
|
}
|
|
166
172
|
})
|
|
167
173
|
)
|
|
@@ -176,7 +182,11 @@ class HookSystem {
|
|
|
176
182
|
/**
|
|
177
183
|
* Execute a "transform" hook (must return modified value)
|
|
178
184
|
*/
|
|
179
|
-
async executeTransform<T>(
|
|
185
|
+
async executeTransform<T>(
|
|
186
|
+
hookPoint: string,
|
|
187
|
+
value: T,
|
|
188
|
+
context: Record<string, unknown> = {}
|
|
189
|
+
): Promise<T> {
|
|
180
190
|
const hooks = this.hooks.get(hookPoint) || []
|
|
181
191
|
let result = value
|
|
182
192
|
|
|
@@ -187,7 +197,10 @@ class HookSystem {
|
|
|
187
197
|
result = transformed as T
|
|
188
198
|
}
|
|
189
199
|
} catch (error) {
|
|
190
|
-
console.error(
|
|
200
|
+
console.error(
|
|
201
|
+
`Transform hook error [${hook.pluginName}] at ${hookPoint}:`,
|
|
202
|
+
(error as Error).message
|
|
203
|
+
)
|
|
191
204
|
// Keep previous value on error
|
|
192
205
|
}
|
|
193
206
|
}
|
|
@@ -210,7 +223,7 @@ class HookSystem {
|
|
|
210
223
|
[HookPoints.AFTER_SNAPSHOT_RESTORE]: EventTypes.SNAPSHOT_RESTORED,
|
|
211
224
|
[HookPoints.AFTER_COMMIT]: EventTypes.COMMIT_CREATED,
|
|
212
225
|
[HookPoints.AFTER_PUSH]: EventTypes.PUSH_COMPLETED,
|
|
213
|
-
[HookPoints.AFTER_SYNC]: EventTypes.PROJECT_SYNCED
|
|
226
|
+
[HookPoints.AFTER_SYNC]: EventTypes.PROJECT_SYNCED,
|
|
214
227
|
}
|
|
215
228
|
return mapping[hookPoint] || null
|
|
216
229
|
}
|
|
@@ -219,9 +232,9 @@ class HookSystem {
|
|
|
219
232
|
* Get all registered hooks for a point
|
|
220
233
|
*/
|
|
221
234
|
getHooks(hookPoint: string): Array<{ pluginName: string; priority: number }> {
|
|
222
|
-
return (this.hooks.get(hookPoint) || []).map(h => ({
|
|
235
|
+
return (this.hooks.get(hookPoint) || []).map((h) => ({
|
|
223
236
|
pluginName: h.pluginName,
|
|
224
|
-
priority: h.priority
|
|
237
|
+
priority: h.priority,
|
|
225
238
|
}))
|
|
226
239
|
}
|
|
227
240
|
|
|
@@ -230,7 +243,7 @@ class HookSystem {
|
|
|
230
243
|
*/
|
|
231
244
|
getPluginHooks(pluginName: string): string[] {
|
|
232
245
|
const entries = this.pluginHooks.get(pluginName) || []
|
|
233
|
-
return entries.map(e => e.hookPoint)
|
|
246
|
+
return entries.map((e) => e.hookPoint)
|
|
234
247
|
}
|
|
235
248
|
|
|
236
249
|
/**
|
|
@@ -298,14 +311,9 @@ const hooks = {
|
|
|
298
311
|
*/
|
|
299
312
|
runTransform: <T>(point: string, value: T, context?: Record<string, unknown>) => {
|
|
300
313
|
return hookSystem.executeTransform(`transform:${point}`, value, context)
|
|
301
|
-
}
|
|
314
|
+
},
|
|
302
315
|
}
|
|
303
316
|
|
|
304
|
-
export {
|
|
305
|
-
HookSystem,
|
|
306
|
-
HookPoints,
|
|
307
|
-
hookSystem,
|
|
308
|
-
hooks
|
|
309
|
-
}
|
|
317
|
+
export { HookSystem, HookPoints, hookSystem, hooks }
|
|
310
318
|
|
|
311
319
|
export default { HookSystem, HookPoints, hookSystem, hooks }
|
package/core/plugin/index.ts
CHANGED
|
@@ -6,14 +6,17 @@
|
|
|
6
6
|
* @version 1.0.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { HookPoints, HookSystem, hookSystem, hooks } from './hooks'
|
|
10
10
|
import { PluginLoader, pluginLoader } from './loader'
|
|
11
11
|
import { PluginRegistry, pluginRegistry } from './registry'
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Initialize the complete plugin system
|
|
15
15
|
*/
|
|
16
|
-
async function initializePlugins(
|
|
16
|
+
async function initializePlugins(
|
|
17
|
+
projectPath: string,
|
|
18
|
+
config: Record<string, unknown> = {}
|
|
19
|
+
): Promise<void> {
|
|
17
20
|
await pluginRegistry.initialize()
|
|
18
21
|
await pluginLoader.initialize(projectPath, config)
|
|
19
22
|
}
|
|
@@ -35,18 +38,15 @@ export {
|
|
|
35
38
|
HookPoints,
|
|
36
39
|
hookSystem,
|
|
37
40
|
hooks,
|
|
38
|
-
|
|
39
41
|
// Plugin loader
|
|
40
42
|
PluginLoader,
|
|
41
43
|
pluginLoader,
|
|
42
|
-
|
|
43
44
|
// Plugin registry
|
|
44
45
|
PluginRegistry,
|
|
45
46
|
pluginRegistry,
|
|
46
|
-
|
|
47
47
|
// Convenience functions
|
|
48
48
|
initializePlugins,
|
|
49
|
-
shutdownPlugins
|
|
49
|
+
shutdownPlugins,
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
export default {
|
|
@@ -59,5 +59,5 @@ export default {
|
|
|
59
59
|
PluginRegistry,
|
|
60
60
|
pluginRegistry,
|
|
61
61
|
initializePlugins,
|
|
62
|
-
shutdownPlugins
|
|
62
|
+
shutdownPlugins,
|
|
63
63
|
}
|
package/core/plugin/loader.ts
CHANGED
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
* @version 1.0.0
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import fs from 'fs/promises'
|
|
13
|
-
import path from 'path'
|
|
14
|
-
import {
|
|
15
|
-
import { eventBus, type EventCallback } from '../bus'
|
|
12
|
+
import fs from 'node:fs/promises'
|
|
13
|
+
import path from 'node:path'
|
|
14
|
+
import { type EventCallback, eventBus } from '../bus'
|
|
16
15
|
import pathManager from '../infrastructure/path-manager'
|
|
17
16
|
import { isNotFoundError } from '../types/fs'
|
|
17
|
+
import { hookSystem } from './hooks'
|
|
18
18
|
|
|
19
19
|
type PluginSource = 'builtin' | 'global' | 'project'
|
|
20
20
|
type HookHandler = (data: unknown) => unknown | Promise<unknown>
|
|
@@ -118,9 +118,10 @@ class PluginLoader {
|
|
|
118
118
|
for (const file of files) {
|
|
119
119
|
const filePath = path.join(globalPath, file)
|
|
120
120
|
if (file.endsWith('.js') || file.endsWith('.ts') || (await this.isDirectory(filePath))) {
|
|
121
|
-
const pluginPath =
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
const pluginPath =
|
|
122
|
+
file.endsWith('.js') || file.endsWith('.ts')
|
|
123
|
+
? filePath
|
|
124
|
+
: path.join(filePath, 'index.js')
|
|
124
125
|
await this.loadPlugin(pluginPath, 'global')
|
|
125
126
|
}
|
|
126
127
|
}
|
|
@@ -169,7 +170,11 @@ class PluginLoader {
|
|
|
169
170
|
/**
|
|
170
171
|
* Load a single plugin
|
|
171
172
|
*/
|
|
172
|
-
async loadPlugin(
|
|
173
|
+
async loadPlugin(
|
|
174
|
+
pluginPath: string,
|
|
175
|
+
source: PluginSource,
|
|
176
|
+
config: Record<string, unknown> = {}
|
|
177
|
+
): Promise<void> {
|
|
173
178
|
try {
|
|
174
179
|
// Check if file exists
|
|
175
180
|
await fs.access(pluginPath)
|
|
@@ -192,7 +197,7 @@ class PluginLoader {
|
|
|
192
197
|
this.plugins.set(plugin.name, {
|
|
193
198
|
...plugin,
|
|
194
199
|
source,
|
|
195
|
-
config: { ...config, ...(this.config[plugin.name] as Record<string, unknown> || {}) }
|
|
200
|
+
config: { ...config, ...((this.config[plugin.name] as Record<string, unknown>) || {}) },
|
|
196
201
|
})
|
|
197
202
|
this.pluginPaths.set(plugin.name, pluginPath)
|
|
198
203
|
|
|
@@ -212,10 +217,9 @@ class PluginLoader {
|
|
|
212
217
|
config: this.plugins.get(plugin.name)!.config!,
|
|
213
218
|
eventBus,
|
|
214
219
|
hookSystem,
|
|
215
|
-
projectPath: this.projectPath
|
|
220
|
+
projectPath: this.projectPath,
|
|
216
221
|
})
|
|
217
222
|
}
|
|
218
|
-
|
|
219
223
|
} catch (error) {
|
|
220
224
|
const err = error as NodeJS.ErrnoException
|
|
221
225
|
if (err.code === 'ENOENT') {
|
|
@@ -235,7 +239,7 @@ class PluginLoader {
|
|
|
235
239
|
for (const [hookPoint, handler] of Object.entries(plugin.hooks || {})) {
|
|
236
240
|
hookSystem.register(hookPoint, handler, {
|
|
237
241
|
pluginName: plugin.name,
|
|
238
|
-
priority: plugin.priority || 10
|
|
242
|
+
priority: plugin.priority || 10,
|
|
239
243
|
})
|
|
240
244
|
}
|
|
241
245
|
}
|
|
@@ -304,7 +308,7 @@ class PluginLoader {
|
|
|
304
308
|
* Get plugins by source
|
|
305
309
|
*/
|
|
306
310
|
getPluginsBySource(source: PluginSource): Plugin[] {
|
|
307
|
-
return this.getAllPlugins().filter(p => p.source === source)
|
|
311
|
+
return this.getAllPlugins().filter((p) => p.source === source)
|
|
308
312
|
}
|
|
309
313
|
|
|
310
314
|
/**
|
|
@@ -319,7 +323,7 @@ class PluginLoader {
|
|
|
319
323
|
commands[name] = {
|
|
320
324
|
handler: handler.handler,
|
|
321
325
|
plugin: plugin.name,
|
|
322
|
-
description: handler.description || `Command from ${plugin.name}
|
|
326
|
+
description: handler.description || `Command from ${plugin.name}`,
|
|
323
327
|
}
|
|
324
328
|
}
|
|
325
329
|
}
|
|
@@ -347,10 +351,6 @@ class PluginLoader {
|
|
|
347
351
|
// Singleton instance
|
|
348
352
|
const pluginLoader = new PluginLoader()
|
|
349
353
|
|
|
350
|
-
export {
|
|
351
|
-
PluginLoader,
|
|
352
|
-
pluginLoader,
|
|
353
|
-
Plugin
|
|
354
|
-
}
|
|
354
|
+
export { PluginLoader, pluginLoader, type Plugin }
|
|
355
355
|
|
|
356
356
|
export default { PluginLoader, pluginLoader }
|
package/core/plugin/registry.ts
CHANGED
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
* @version 1.0.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import fs from 'fs/promises'
|
|
10
|
-
import path from 'path'
|
|
9
|
+
import fs from 'node:fs/promises'
|
|
10
|
+
import path from 'node:path'
|
|
11
11
|
import pathManager from '../infrastructure/path-manager'
|
|
12
|
-
import { pluginLoader } from './loader'
|
|
13
12
|
import { isNotFoundError } from '../types/fs'
|
|
13
|
+
import { pluginLoader } from './loader'
|
|
14
14
|
|
|
15
15
|
type PluginSource = 'builtin' | 'global' | 'project'
|
|
16
16
|
|
|
@@ -51,16 +51,10 @@ class PluginRegistry {
|
|
|
51
51
|
*/
|
|
52
52
|
async discoverPlugins(): Promise<void> {
|
|
53
53
|
// Built-in plugins
|
|
54
|
-
await this.discoverFromPath(
|
|
55
|
-
path.join(__dirname, '..', 'plugins'),
|
|
56
|
-
'builtin'
|
|
57
|
-
)
|
|
54
|
+
await this.discoverFromPath(path.join(__dirname, '..', 'plugins'), 'builtin')
|
|
58
55
|
|
|
59
56
|
// Global plugins
|
|
60
|
-
await this.discoverFromPath(
|
|
61
|
-
path.join(pathManager.getGlobalBasePath(), 'plugins'),
|
|
62
|
-
'global'
|
|
63
|
-
)
|
|
57
|
+
await this.discoverFromPath(path.join(pathManager.getGlobalBasePath(), 'plugins'), 'global')
|
|
64
58
|
}
|
|
65
59
|
|
|
66
60
|
/**
|
|
@@ -91,7 +85,7 @@ class PluginRegistry {
|
|
|
91
85
|
this.availablePlugins.set(metadata.name, {
|
|
92
86
|
...metadata,
|
|
93
87
|
path: pluginPath,
|
|
94
|
-
source
|
|
88
|
+
source,
|
|
95
89
|
})
|
|
96
90
|
}
|
|
97
91
|
} catch (error) {
|
|
@@ -125,7 +119,7 @@ class PluginRegistry {
|
|
|
125
119
|
return {
|
|
126
120
|
name: nameMatch[1],
|
|
127
121
|
version: versionMatch ? versionMatch[1] : '1.0.0',
|
|
128
|
-
description: descMatch ? descMatch[1] : ''
|
|
122
|
+
description: descMatch ? descMatch[1] : '',
|
|
129
123
|
}
|
|
130
124
|
}
|
|
131
125
|
|
|
@@ -137,7 +131,7 @@ class PluginRegistry {
|
|
|
137
131
|
return {
|
|
138
132
|
name: plugin.name,
|
|
139
133
|
version: plugin.version || '1.0.0',
|
|
140
|
-
description: plugin.description || ''
|
|
134
|
+
description: plugin.description || '',
|
|
141
135
|
}
|
|
142
136
|
}
|
|
143
137
|
} catch (error) {
|
|
@@ -161,7 +155,7 @@ class PluginRegistry {
|
|
|
161
155
|
* Get available plugins by source
|
|
162
156
|
*/
|
|
163
157
|
getAvailableBySource(source: PluginSource): PluginMetadata[] {
|
|
164
|
-
return this.getAvailable().filter(p => p.source === source)
|
|
158
|
+
return this.getAvailable().filter((p) => p.source === source)
|
|
165
159
|
}
|
|
166
160
|
|
|
167
161
|
/**
|
|
@@ -190,7 +184,7 @@ class PluginRegistry {
|
|
|
190
184
|
return {
|
|
191
185
|
...(available || { name, version: '1.0.0', description: '' }),
|
|
192
186
|
loaded: !!loaded,
|
|
193
|
-
active: loaded
|
|
187
|
+
active: !!loaded,
|
|
194
188
|
}
|
|
195
189
|
}
|
|
196
190
|
|
|
@@ -287,7 +281,7 @@ class PluginRegistry {
|
|
|
287
281
|
const bySource: Record<PluginSource, PluginMetadata[]> = {
|
|
288
282
|
builtin: [],
|
|
289
283
|
global: [],
|
|
290
|
-
project: []
|
|
284
|
+
project: [],
|
|
291
285
|
}
|
|
292
286
|
|
|
293
287
|
for (const plugin of available) {
|
|
@@ -329,11 +323,6 @@ class PluginRegistry {
|
|
|
329
323
|
// Singleton instance
|
|
330
324
|
const pluginRegistry = new PluginRegistry()
|
|
331
325
|
|
|
332
|
-
export {
|
|
333
|
-
PluginRegistry,
|
|
334
|
-
pluginRegistry,
|
|
335
|
-
PluginMetadata,
|
|
336
|
-
PluginInfo
|
|
337
|
-
}
|
|
326
|
+
export { PluginRegistry, pluginRegistry, type PluginMetadata, type PluginInfo }
|
|
338
327
|
|
|
339
328
|
export default { PluginRegistry, pluginRegistry }
|
package/core/schemas/agents.ts
CHANGED
package/core/schemas/analysis.ts
CHANGED