prjct-cli 0.20.0 → 0.21.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 +24 -6
- package/CLAUDE.md +56 -15
- package/README.md +5 -6
- package/bin/prjct +59 -42
- package/bin/prjct.ts +60 -0
- package/core/__tests__/agentic/memory-system.test.ts +18 -3
- package/core/__tests__/agentic/plan-mode.test.ts +55 -26
- package/core/__tests__/agentic/prompt-builder.test.ts +6 -6
- package/core/__tests__/utils/project-commands.test.ts +72 -0
- package/core/agentic/agent-router.ts +3 -12
- package/core/agentic/command-executor.ts +372 -3
- package/core/agentic/context-builder.ts +7 -27
- package/core/agentic/ground-truth.ts +604 -5
- package/core/agentic/index.ts +180 -0
- package/core/agentic/loop-detector.ts +418 -4
- package/core/agentic/memory-system.ts +857 -3
- package/core/agentic/plan-mode.ts +491 -4
- package/core/agentic/prompt-builder.ts +44 -65
- package/core/agentic/services.ts +13 -5
- package/core/agentic/skill-loader.ts +112 -0
- package/core/agentic/smart-context.ts +37 -122
- package/core/agentic/template-loader.ts +79 -122
- package/core/agentic/tool-registry.ts +5 -11
- package/core/agents/index.ts +1 -1
- package/core/agents/performance.ts +4 -2
- package/core/bus/bus.ts +262 -0
- package/core/bus/index.ts +3 -313
- package/core/commands/analysis.ts +5 -5
- package/core/commands/analytics.ts +11 -11
- package/core/commands/base.ts +33 -209
- package/core/commands/cleanup.ts +148 -0
- package/core/commands/command-data.ts +346 -0
- package/core/commands/commands.ts +216 -0
- package/core/commands/design.ts +83 -0
- package/core/commands/index.ts +13 -207
- package/core/commands/maintenance.ts +52 -473
- package/core/commands/planning.ts +3 -3
- package/core/commands/register.ts +104 -0
- package/core/commands/registry.ts +441 -0
- package/core/commands/setup.ts +25 -9
- package/core/commands/shipping.ts +48 -11
- package/core/commands/snapshots.ts +299 -0
- package/core/commands/workflow.ts +2 -2
- package/core/constants/index.ts +254 -4
- package/core/domain/agent-loader.ts +5 -6
- package/core/domain/task-stack.ts +555 -4
- package/core/errors.ts +127 -1
- package/core/events/events.ts +87 -0
- package/core/events/index.ts +4 -138
- package/core/index.ts +15 -23
- package/core/infrastructure/agent-detector.ts +126 -201
- package/core/infrastructure/author-detector.ts +99 -171
- package/core/infrastructure/command-installer.ts +476 -4
- package/core/infrastructure/config-manager.ts +41 -37
- package/core/infrastructure/path-manager.ts +59 -9
- package/core/infrastructure/permission-manager.ts +286 -0
- package/core/integrations/notion/client.ts +323 -0
- package/core/integrations/notion/index.ts +43 -0
- package/core/integrations/notion/setup.ts +230 -0
- package/core/integrations/notion/sync.ts +311 -0
- package/core/integrations/notion/templates.ts +234 -0
- package/core/outcomes/analyzer.ts +7 -41
- package/core/outcomes/index.ts +1 -1
- package/core/outcomes/recorder.ts +1 -1
- package/core/plugin/builtin/notion.ts +178 -0
- package/core/{plugins → plugin/builtin}/webhook.ts +6 -22
- package/core/plugin/loader.ts +5 -5
- package/core/plugin/registry.ts +2 -2
- package/core/schemas/ideas.ts +85 -54
- package/core/schemas/index.ts +14 -33
- package/core/schemas/permissions.ts +177 -0
- package/core/schemas/project.ts +39 -12
- package/core/schemas/roadmap.ts +94 -59
- package/core/schemas/schemas.ts +39 -0
- package/core/schemas/shipped.ts +87 -60
- package/core/schemas/state.ts +110 -70
- package/core/server/index.ts +21 -0
- package/core/server/routes.ts +165 -0
- package/core/server/server.ts +136 -0
- package/core/server/sse.ts +135 -0
- package/core/services/agent-service.ts +170 -0
- package/core/services/breakdown-service.ts +126 -0
- package/core/services/index.ts +21 -0
- package/core/services/memory-service.ts +108 -0
- package/core/services/project-service.ts +146 -0
- package/core/services/skill-service.ts +253 -0
- package/core/session/compaction.ts +257 -0
- package/core/session/index.ts +20 -8
- package/core/{infrastructure/session-manager/migration.ts → session/log-migration.ts} +9 -9
- package/core/{infrastructure/session-manager/session-manager.ts → session/session-log-manager.ts} +27 -26
- package/core/session/{session-manager.ts → task-session-manager.ts} +7 -4
- package/core/session/utils.ts +1 -1
- package/core/storage/ideas-storage.ts +10 -26
- package/core/storage/index.ts +14 -162
- package/core/storage/queue-storage.ts +13 -11
- package/core/storage/shipped-storage.ts +4 -17
- package/core/storage/state-storage.ts +35 -43
- package/core/storage/storage-manager.ts +42 -52
- package/core/storage/storage.ts +160 -0
- package/core/sync/auth-config.ts +1 -8
- package/core/sync/index.ts +17 -10
- package/core/sync/oauth-handler.ts +1 -6
- package/core/sync/sync-client.ts +6 -34
- package/core/sync/sync-manager.ts +11 -40
- package/core/types/agentic.ts +577 -0
- package/core/types/agents.ts +145 -0
- package/core/types/bus.ts +82 -0
- package/core/types/commands.ts +366 -0
- package/core/types/config.ts +70 -0
- package/core/types/core.ts +96 -0
- package/core/types/domain.ts +71 -0
- package/core/types/events.ts +42 -0
- package/core/types/fs.ts +56 -0
- package/core/types/index.ts +396 -500
- package/core/types/infrastructure.ts +196 -0
- package/core/types/integrations.ts +57 -0
- package/core/{agentic/memory-system/types.ts → types/memory.ts} +33 -8
- package/core/{outcomes/types.ts → types/outcomes.ts} +53 -8
- package/core/types/plugin.ts +25 -0
- package/core/types/server.ts +54 -0
- package/core/types/services.ts +65 -0
- package/core/types/session.ts +135 -0
- package/core/types/storage.ts +148 -0
- package/core/types/sync.ts +121 -0
- package/core/types/task.ts +72 -0
- package/core/types/template.ts +24 -0
- package/core/types/utils.ts +90 -0
- package/core/utils/cache.ts +195 -0
- package/core/utils/collection-filters.ts +245 -0
- package/core/utils/date-helper.ts +1 -5
- package/core/utils/file-helper.ts +20 -10
- package/core/utils/jsonl-helper.ts +5 -8
- package/core/utils/markdown-builder.ts +277 -0
- package/core/utils/project-commands.ts +132 -0
- package/core/utils/runtime.ts +119 -0
- package/dist/bin/prjct.mjs +12568 -0
- package/package.json +13 -8
- package/scripts/build.js +106 -0
- package/scripts/postinstall.js +50 -8
- package/templates/agentic/subagent-generation.md +1 -1
- package/templates/commands/init.md +43 -0
- package/templates/commands/notion-setup.md +191 -0
- package/templates/commands/serve.md +118 -0
- package/templates/commands/ship.md +13 -2
- package/templates/commands/skill.md +110 -0
- package/templates/commands/sync.md +1 -1
- package/templates/commands/test.md +23 -4
- package/templates/mcp-config.json +28 -0
- package/templates/permissions/default.jsonc +60 -0
- package/templates/permissions/permissive.jsonc +49 -0
- package/templates/permissions/strict.jsonc +62 -0
- package/templates/skills/code-review.md +47 -0
- package/templates/skills/debug.md +61 -0
- package/templates/skills/refactor.md +47 -0
- package/templates/subagents/domain/devops.md +1 -1
- package/templates/subagents/domain/testing.md +6 -10
- package/templates/subagents/workflow/prjct-shipper.md +16 -7
- package/templates/tools/bash.txt +22 -0
- package/templates/tools/edit.txt +18 -0
- package/templates/tools/glob.txt +19 -0
- package/templates/tools/grep.txt +21 -0
- package/templates/tools/read.txt +14 -0
- package/templates/tools/task.txt +20 -0
- package/templates/tools/webfetch.txt +16 -0
- package/templates/tools/websearch.txt +18 -0
- package/templates/tools/write.txt +17 -0
- package/core/agentic/command-executor/command-executor.ts +0 -312
- package/core/agentic/command-executor/index.ts +0 -16
- package/core/agentic/command-executor/status-signal.ts +0 -38
- package/core/agentic/command-executor/types.ts +0 -79
- package/core/agentic/ground-truth/index.ts +0 -76
- package/core/agentic/ground-truth/types.ts +0 -33
- package/core/agentic/ground-truth/utils.ts +0 -48
- package/core/agentic/ground-truth/verifiers/analyze.ts +0 -54
- package/core/agentic/ground-truth/verifiers/done.ts +0 -75
- package/core/agentic/ground-truth/verifiers/feature.ts +0 -70
- package/core/agentic/ground-truth/verifiers/index.ts +0 -37
- package/core/agentic/ground-truth/verifiers/init.ts +0 -52
- package/core/agentic/ground-truth/verifiers/now.ts +0 -57
- package/core/agentic/ground-truth/verifiers/ship.ts +0 -85
- package/core/agentic/ground-truth/verifiers/spec.ts +0 -45
- package/core/agentic/ground-truth/verifiers/sync.ts +0 -47
- package/core/agentic/ground-truth/verifiers.ts +0 -6
- package/core/agentic/loop-detector/error-analysis.ts +0 -97
- package/core/agentic/loop-detector/hallucination.ts +0 -71
- package/core/agentic/loop-detector/index.ts +0 -41
- package/core/agentic/loop-detector/loop-detector.ts +0 -222
- package/core/agentic/loop-detector/types.ts +0 -66
- package/core/agentic/memory-system/history.ts +0 -53
- package/core/agentic/memory-system/index.ts +0 -192
- package/core/agentic/memory-system/patterns.ts +0 -156
- package/core/agentic/memory-system/semantic-memories.ts +0 -278
- package/core/agentic/memory-system/session.ts +0 -21
- package/core/agentic/plan-mode/approval.ts +0 -57
- package/core/agentic/plan-mode/constants.ts +0 -44
- package/core/agentic/plan-mode/index.ts +0 -28
- package/core/agentic/plan-mode/plan-mode.ts +0 -407
- package/core/agentic/plan-mode/types.ts +0 -193
- package/core/agents/types.ts +0 -126
- package/core/command-registry/categories.ts +0 -23
- package/core/command-registry/commands.ts +0 -15
- package/core/command-registry/core-commands.ts +0 -344
- package/core/command-registry/index.ts +0 -158
- package/core/command-registry/optional-commands.ts +0 -163
- package/core/command-registry/setup-commands.ts +0 -83
- package/core/command-registry/types.ts +0 -59
- package/core/command-registry.ts +0 -9
- package/core/commands/types.ts +0 -185
- package/core/commands.ts +0 -11
- package/core/constants/formats.ts +0 -187
- package/core/context-sync.ts +0 -18
- package/core/data/index.ts +0 -27
- package/core/data/md-base-manager.ts +0 -203
- package/core/data/md-ideas-manager.ts +0 -155
- package/core/data/md-queue-manager.ts +0 -180
- package/core/data/md-shipped-manager.ts +0 -90
- package/core/data/md-state-manager.ts +0 -137
- package/core/domain/task-stack/index.ts +0 -19
- package/core/domain/task-stack/parser.ts +0 -86
- package/core/domain/task-stack/storage.ts +0 -123
- package/core/domain/task-stack/task-stack.ts +0 -340
- package/core/domain/task-stack/types.ts +0 -51
- package/core/infrastructure/command-installer/command-installer.ts +0 -327
- package/core/infrastructure/command-installer/global-config.ts +0 -136
- package/core/infrastructure/command-installer/index.ts +0 -25
- package/core/infrastructure/command-installer/types.ts +0 -41
- package/core/infrastructure/session-manager/index.ts +0 -23
- package/core/infrastructure/session-manager/types.ts +0 -45
- package/core/infrastructure/session-manager.ts +0 -8
- package/core/serializers/ideas-serializer.ts +0 -187
- package/core/serializers/index.ts +0 -36
- package/core/serializers/queue-serializer.ts +0 -210
- package/core/serializers/shipped-serializer.ts +0 -108
- package/core/serializers/state-serializer.ts +0 -136
- package/core/session/types.ts +0 -29
- /package/core/infrastructure/{agents/claude-agent.ts → claude-agent.ts} +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Loader for Agentic System
|
|
3
|
+
*
|
|
4
|
+
* Integrates skills into the prompt builder and context system.
|
|
5
|
+
* Formats skills for Claude consumption.
|
|
6
|
+
*
|
|
7
|
+
* @version 1.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import skillService from '../services/skill-service'
|
|
11
|
+
import type { Skill, FormattedSkill, SkillContext } from '../types'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Format a skill for inclusion in prompts
|
|
15
|
+
*/
|
|
16
|
+
function formatSkillForPrompt(skill: Skill): FormattedSkill {
|
|
17
|
+
return {
|
|
18
|
+
id: skill.id,
|
|
19
|
+
name: skill.name,
|
|
20
|
+
description: skill.description,
|
|
21
|
+
prompt: skill.content,
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Generate markdown listing of available skills
|
|
27
|
+
*/
|
|
28
|
+
function generateSkillsMarkdown(skills: Skill[]): string {
|
|
29
|
+
if (skills.length === 0) {
|
|
30
|
+
return ''
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const lines: string[] = [
|
|
34
|
+
'## Available Skills',
|
|
35
|
+
'',
|
|
36
|
+
'The following skills can be invoked:',
|
|
37
|
+
'',
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
for (const skill of skills) {
|
|
41
|
+
lines.push(`- **${skill.name}** (\`${skill.id}\`): ${skill.description || 'No description'}`)
|
|
42
|
+
if (skill.metadata.agent) {
|
|
43
|
+
lines.push(` - Agent: ${skill.metadata.agent}`)
|
|
44
|
+
}
|
|
45
|
+
if (skill.metadata.tags?.length) {
|
|
46
|
+
lines.push(` - Tags: ${skill.metadata.tags.join(', ')}`)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return lines.join('\n')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Load skills and prepare context for prompts
|
|
55
|
+
*/
|
|
56
|
+
export async function loadSkillContext(projectPath?: string): Promise<SkillContext> {
|
|
57
|
+
const skills = await skillService.getAll(projectPath)
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
availableSkills: skills.map(formatSkillForPrompt),
|
|
61
|
+
skillsMarkdown: generateSkillsMarkdown(skills),
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get a specific skill's prompt content
|
|
67
|
+
*/
|
|
68
|
+
export async function getSkillPrompt(skillId: string, projectPath?: string): Promise<string | null> {
|
|
69
|
+
const skill = await skillService.get(skillId, projectPath)
|
|
70
|
+
return skill?.content || null
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Find best matching skill for a query
|
|
75
|
+
*/
|
|
76
|
+
export async function findBestSkill(query: string, projectPath?: string): Promise<Skill | null> {
|
|
77
|
+
const results = await skillService.search(query, projectPath)
|
|
78
|
+
return results[0]?.skill || null
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Format skill invocation result
|
|
83
|
+
*/
|
|
84
|
+
export function formatSkillResult(skill: Skill, result: string): string {
|
|
85
|
+
return [
|
|
86
|
+
`## Skill Executed: ${skill.name}`,
|
|
87
|
+
'',
|
|
88
|
+
result,
|
|
89
|
+
'',
|
|
90
|
+
`---`,
|
|
91
|
+
`*Skill: ${skill.id} | Source: ${skill.source}*`,
|
|
92
|
+
].join('\n')
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Build skill section for system prompt
|
|
97
|
+
*/
|
|
98
|
+
export async function buildSkillSystemPrompt(projectPath?: string): Promise<string> {
|
|
99
|
+
const { availableSkills, skillsMarkdown } = await loadSkillContext(projectPath)
|
|
100
|
+
|
|
101
|
+
if (availableSkills.length === 0) {
|
|
102
|
+
return ''
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return [
|
|
106
|
+
'<skills>',
|
|
107
|
+
skillsMarkdown,
|
|
108
|
+
'',
|
|
109
|
+
'To invoke a skill, use the skill ID.',
|
|
110
|
+
'</skills>',
|
|
111
|
+
].join('\n')
|
|
112
|
+
}
|
|
@@ -10,127 +10,30 @@
|
|
|
10
10
|
|
|
11
11
|
import { agentPerformanceTracker } from '../agents'
|
|
12
12
|
import { outcomeAnalyzer } from '../outcomes'
|
|
13
|
-
import type { TaskType } from '../
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
/** Roadmap features */
|
|
38
|
-
roadmap: FeatureInfo[]
|
|
39
|
-
|
|
40
|
-
/** Detected patterns */
|
|
41
|
-
patterns: PatternInfo[]
|
|
42
|
-
|
|
43
|
-
/** Tech stack info */
|
|
44
|
-
stack: StackInfo
|
|
45
|
-
|
|
46
|
-
/** File list */
|
|
47
|
-
files: string[]
|
|
48
|
-
|
|
49
|
-
/** Project path */
|
|
50
|
-
projectPath: string
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Filtered context optimized for a task domain.
|
|
55
|
-
*/
|
|
56
|
-
export interface FilteredContext {
|
|
57
|
-
/** Filtered agents (domain-relevant only) */
|
|
58
|
-
agents: AgentInfo[]
|
|
59
|
-
|
|
60
|
-
/** Filtered roadmap (related features only) */
|
|
61
|
-
roadmap: FeatureInfo[]
|
|
62
|
-
|
|
63
|
-
/** Filtered patterns (domain-relevant only) */
|
|
64
|
-
patterns: PatternInfo[]
|
|
65
|
-
|
|
66
|
-
/** Filtered stack info */
|
|
67
|
-
stack: Partial<StackInfo>
|
|
68
|
-
|
|
69
|
-
/** Filtered files */
|
|
70
|
-
files: string[]
|
|
71
|
-
|
|
72
|
-
/** Filtering metrics */
|
|
73
|
-
metrics: FilterMetrics
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Agent info for context.
|
|
78
|
-
*/
|
|
79
|
-
export interface AgentInfo {
|
|
80
|
-
name: string
|
|
81
|
-
domain: ContextDomain
|
|
82
|
-
skills: string[]
|
|
83
|
-
successRate?: number
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Feature info for context.
|
|
88
|
-
*/
|
|
89
|
-
export interface FeatureInfo {
|
|
90
|
-
id: string
|
|
91
|
-
name: string
|
|
92
|
-
relatedTo: ContextDomain[]
|
|
93
|
-
status: string
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Pattern info for context.
|
|
98
|
-
*/
|
|
99
|
-
export interface PatternInfo {
|
|
100
|
-
description: string
|
|
101
|
-
domain: ContextDomain
|
|
102
|
-
confidence: number
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Stack info for context.
|
|
107
|
-
*/
|
|
108
|
-
export interface StackInfo {
|
|
109
|
-
frontend: string[]
|
|
110
|
-
backend: string[]
|
|
111
|
-
devops: string[]
|
|
112
|
-
database: string[]
|
|
113
|
-
testing: string[]
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Filtering metrics.
|
|
118
|
-
*/
|
|
119
|
-
export interface FilterMetrics {
|
|
120
|
-
originalSize: number
|
|
121
|
-
filteredSize: number
|
|
122
|
-
reductionPercent: number
|
|
123
|
-
domain: ContextDomain
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Domain detection result.
|
|
128
|
-
*/
|
|
129
|
-
interface DomainAnalysis {
|
|
130
|
-
primary: ContextDomain
|
|
131
|
-
secondary: ContextDomain[]
|
|
132
|
-
confidence: number
|
|
133
|
-
}
|
|
13
|
+
import type { TaskType } from '../types'
|
|
14
|
+
import type {
|
|
15
|
+
ContextDomain,
|
|
16
|
+
SmartContextProjectState,
|
|
17
|
+
FullContext,
|
|
18
|
+
FilteredContext,
|
|
19
|
+
StackInfo,
|
|
20
|
+
DomainAnalysis,
|
|
21
|
+
} from '../types'
|
|
22
|
+
|
|
23
|
+
// Re-export types for convenience
|
|
24
|
+
export type {
|
|
25
|
+
ContextDomain,
|
|
26
|
+
FullContext,
|
|
27
|
+
FilteredContext,
|
|
28
|
+
AgentInfo,
|
|
29
|
+
FeatureInfo,
|
|
30
|
+
PatternInfo,
|
|
31
|
+
StackInfo,
|
|
32
|
+
FilterMetrics,
|
|
33
|
+
} from '../types'
|
|
34
|
+
|
|
35
|
+
// Local type alias for backward compatibility
|
|
36
|
+
type ProjectState = SmartContextProjectState
|
|
134
37
|
|
|
135
38
|
/**
|
|
136
39
|
* SmartContext - Intelligent context filtering.
|
|
@@ -171,7 +74,19 @@ class SmartContext {
|
|
|
171
74
|
|
|
172
75
|
// Testing indicators
|
|
173
76
|
const testingKeywords = [
|
|
174
|
-
'test', 'spec',
|
|
77
|
+
'test', 'spec',
|
|
78
|
+
// JS/TS
|
|
79
|
+
'bun', 'bun test', 'jest', 'mocha', 'cypress', 'playwright',
|
|
80
|
+
// Python
|
|
81
|
+
'pytest', 'unittest',
|
|
82
|
+
// Go
|
|
83
|
+
'go test',
|
|
84
|
+
// Rust
|
|
85
|
+
'cargo test',
|
|
86
|
+
// .NET
|
|
87
|
+
'dotnet test',
|
|
88
|
+
// Java
|
|
89
|
+
'mvn test', 'gradle test', 'gradlew test',
|
|
175
90
|
'e2e', 'unit', 'integration', 'coverage', 'mock', 'fixture'
|
|
176
91
|
]
|
|
177
92
|
|
|
@@ -3,153 +3,110 @@
|
|
|
3
3
|
* Loads and parses command templates with frontmatter.
|
|
4
4
|
*
|
|
5
5
|
* @module agentic/template-loader
|
|
6
|
-
* @version 1.0.0
|
|
7
6
|
*/
|
|
8
7
|
|
|
9
8
|
import fs from 'fs/promises'
|
|
10
9
|
import path from 'path'
|
|
11
10
|
import { TemplateError } from '../errors'
|
|
11
|
+
import type { Frontmatter, ParsedTemplate } from '../types'
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
// ============ Module State (LRU Cache) ============
|
|
14
|
+
|
|
15
|
+
const TEMPLATES_DIR = path.join(__dirname, '..', '..', 'templates', 'commands')
|
|
16
|
+
const MAX_CACHE_SIZE = 50
|
|
17
|
+
|
|
18
|
+
const cache = new Map<string, ParsedTemplate>()
|
|
19
|
+
const cacheOrder: string[] = []
|
|
20
|
+
|
|
21
|
+
// ============ Cache Helpers ============
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
function updateLruOrder(key: string): void {
|
|
24
|
+
const index = cacheOrder.indexOf(key)
|
|
25
|
+
if (index > -1) cacheOrder.splice(index, 1)
|
|
26
|
+
cacheOrder.push(key)
|
|
23
27
|
}
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
*/
|
|
30
|
-
class TemplateLoader {
|
|
31
|
-
templatesDir: string
|
|
32
|
-
cache: Map<string, ParsedTemplate>
|
|
33
|
-
cacheOrder: string[] // Track access order for LRU eviction
|
|
34
|
-
maxCacheSize: number
|
|
35
|
-
|
|
36
|
-
constructor() {
|
|
37
|
-
this.templatesDir = path.join(__dirname, '..', '..', 'templates', 'commands')
|
|
38
|
-
this.cache = new Map()
|
|
39
|
-
this.cacheOrder = []
|
|
40
|
-
this.maxCacheSize = 50 // More than enough for all commands
|
|
29
|
+
function evictLru(): void {
|
|
30
|
+
while (cache.size >= MAX_CACHE_SIZE && cacheOrder.length > 0) {
|
|
31
|
+
const oldest = cacheOrder.shift()
|
|
32
|
+
if (oldest) cache.delete(oldest)
|
|
41
33
|
}
|
|
34
|
+
}
|
|
42
35
|
|
|
43
|
-
|
|
44
|
-
* Update LRU order - move key to end (most recently used)
|
|
45
|
-
*/
|
|
46
|
-
private updateLruOrder(key: string): void {
|
|
47
|
-
const index = this.cacheOrder.indexOf(key)
|
|
48
|
-
if (index > -1) {
|
|
49
|
-
this.cacheOrder.splice(index, 1)
|
|
50
|
-
}
|
|
51
|
-
this.cacheOrder.push(key)
|
|
52
|
-
}
|
|
36
|
+
// ============ Parsing Functions ============
|
|
53
37
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (oldest) {
|
|
61
|
-
this.cache.delete(oldest)
|
|
62
|
-
}
|
|
63
|
-
}
|
|
38
|
+
export function parseFrontmatter(content: string): ParsedTemplate {
|
|
39
|
+
const frontmatterRegex = /^---\n([\s\S]+?)\n---\n([\s\S]*)$/
|
|
40
|
+
const match = content.match(frontmatterRegex)
|
|
41
|
+
|
|
42
|
+
if (!match) {
|
|
43
|
+
return { frontmatter: {}, content: content.trim() }
|
|
64
44
|
}
|
|
65
45
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
*/
|
|
69
|
-
async load(commandName: string): Promise<ParsedTemplate> {
|
|
70
|
-
// Check cache first
|
|
71
|
-
if (this.cache.has(commandName)) {
|
|
72
|
-
this.updateLruOrder(commandName)
|
|
73
|
-
return this.cache.get(commandName)!
|
|
74
|
-
}
|
|
46
|
+
const [, frontmatterText, mainContent] = match
|
|
47
|
+
const frontmatter: Frontmatter = {}
|
|
75
48
|
|
|
76
|
-
|
|
49
|
+
frontmatterText.split('\n').forEach((line) => {
|
|
50
|
+
const [key, ...valueParts] = line.split(':')
|
|
51
|
+
if (key && valueParts.length > 0) {
|
|
52
|
+
const value = valueParts.join(':').trim()
|
|
77
53
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
54
|
+
// Parse arrays
|
|
55
|
+
if (value.startsWith('[') && value.endsWith(']')) {
|
|
56
|
+
frontmatter[key.trim()] = value.slice(1, -1).split(',').map((v) => v.trim())
|
|
57
|
+
} else {
|
|
58
|
+
// Remove quotes if present
|
|
59
|
+
frontmatter[key.trim()] = value.replace(/^["']|["']$/g, '')
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
})
|
|
81
63
|
|
|
82
|
-
|
|
83
|
-
|
|
64
|
+
return { frontmatter, content: mainContent.trim() }
|
|
65
|
+
}
|
|
84
66
|
|
|
85
|
-
|
|
86
|
-
this.cache.set(commandName, parsed)
|
|
87
|
-
this.cacheOrder.push(commandName)
|
|
67
|
+
// ============ Main Functions ============
|
|
88
68
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
69
|
+
export async function load(commandName: string): Promise<ParsedTemplate> {
|
|
70
|
+
// Check cache first
|
|
71
|
+
if (cache.has(commandName)) {
|
|
72
|
+
updateLruOrder(commandName)
|
|
73
|
+
return cache.get(commandName)!
|
|
93
74
|
}
|
|
94
75
|
|
|
95
|
-
|
|
96
|
-
* Parse frontmatter from markdown
|
|
97
|
-
*/
|
|
98
|
-
parseFrontmatter(content: string): ParsedTemplate {
|
|
99
|
-
const frontmatterRegex = /^---\n([\s\S]+?)\n---\n([\s\S]*)$/
|
|
100
|
-
const match = content.match(frontmatterRegex)
|
|
101
|
-
|
|
102
|
-
if (!match) {
|
|
103
|
-
return {
|
|
104
|
-
frontmatter: {},
|
|
105
|
-
content: content.trim(),
|
|
106
|
-
}
|
|
107
|
-
}
|
|
76
|
+
const templatePath = path.join(TEMPLATES_DIR, `${commandName}.md`)
|
|
108
77
|
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
// Parse frontmatter lines
|
|
113
|
-
frontmatterText.split('\n').forEach((line) => {
|
|
114
|
-
const [key, ...valueParts] = line.split(':')
|
|
115
|
-
if (key && valueParts.length > 0) {
|
|
116
|
-
const value = valueParts.join(':').trim()
|
|
117
|
-
|
|
118
|
-
// Parse arrays
|
|
119
|
-
if (value.startsWith('[') && value.endsWith(']')) {
|
|
120
|
-
frontmatter[key.trim()] = value
|
|
121
|
-
.slice(1, -1)
|
|
122
|
-
.split(',')
|
|
123
|
-
.map((v) => v.trim())
|
|
124
|
-
} else {
|
|
125
|
-
// Remove quotes if present
|
|
126
|
-
frontmatter[key.trim()] = value.replace(/^["']|["']$/g, '')
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
})
|
|
78
|
+
try {
|
|
79
|
+
const rawContent = await fs.readFile(templatePath, 'utf-8')
|
|
80
|
+
const parsed = parseFrontmatter(rawContent)
|
|
130
81
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
content: mainContent.trim(),
|
|
134
|
-
}
|
|
135
|
-
}
|
|
82
|
+
// Evict LRU if needed before adding
|
|
83
|
+
evictLru()
|
|
136
84
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
async getAllowedTools(commandName: string): Promise<string[]> {
|
|
141
|
-
const template = await this.load(commandName)
|
|
142
|
-
return template.frontmatter['allowed-tools'] || []
|
|
143
|
-
}
|
|
85
|
+
// Cache result
|
|
86
|
+
cache.set(commandName, parsed)
|
|
87
|
+
cacheOrder.push(commandName)
|
|
144
88
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
clearCache(): void {
|
|
149
|
-
this.cache.clear()
|
|
89
|
+
return parsed
|
|
90
|
+
} catch {
|
|
91
|
+
throw TemplateError.notFound(commandName)
|
|
150
92
|
}
|
|
151
93
|
}
|
|
152
94
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
95
|
+
export async function getAllowedTools(commandName: string): Promise<string[]> {
|
|
96
|
+
const template = await load(commandName)
|
|
97
|
+
return template.frontmatter['allowed-tools'] || []
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function clearCache(): void {
|
|
101
|
+
cache.clear()
|
|
102
|
+
cacheOrder.length = 0
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ============ Default Export (backwards compat) ============
|
|
106
|
+
|
|
107
|
+
export default {
|
|
108
|
+
load,
|
|
109
|
+
parseFrontmatter,
|
|
110
|
+
getAllowedTools,
|
|
111
|
+
clearCache
|
|
112
|
+
}
|
|
@@ -9,20 +9,14 @@
|
|
|
9
9
|
import fs from 'fs/promises'
|
|
10
10
|
import { exec } from 'child_process'
|
|
11
11
|
import { promisify } from 'util'
|
|
12
|
+
import type { ToolFunction, ToolRegistryInterface } from '../types'
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
type ToolFunction = (...args: unknown[]) => Promise<unknown>
|
|
14
|
+
// Re-export types for convenience
|
|
15
|
+
export type { ToolFunction, ToolRegistryInterface } from '../types'
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
tools: Map<string, ToolFunction>
|
|
19
|
-
register(name: string, fn: ToolFunction): void
|
|
20
|
-
get(name: string): ToolFunction | undefined
|
|
21
|
-
isAllowed(name: string, allowedTools: string[]): boolean
|
|
22
|
-
list(): string[]
|
|
23
|
-
}
|
|
17
|
+
const execAsync = promisify(exec)
|
|
24
18
|
|
|
25
|
-
const toolRegistry:
|
|
19
|
+
const toolRegistry: ToolRegistryInterface = {
|
|
26
20
|
tools: new Map(),
|
|
27
21
|
|
|
28
22
|
/**
|
package/core/agents/index.ts
CHANGED
|
@@ -14,7 +14,7 @@ import type {
|
|
|
14
14
|
AgentSuggestion,
|
|
15
15
|
AgentPerformanceSummary,
|
|
16
16
|
TaskType,
|
|
17
|
-
} from '
|
|
17
|
+
} from '../types'
|
|
18
18
|
|
|
19
19
|
const PERFORMANCE_DIR = 'analysis'
|
|
20
20
|
const PERFORMANCE_FILE = 'agent-performance.json'
|
|
@@ -98,7 +98,7 @@ export class AgentPerformanceTracker {
|
|
|
98
98
|
perfPath,
|
|
99
99
|
{ agents: [] }
|
|
100
100
|
)
|
|
101
|
-
return data
|
|
101
|
+
return data?.agents ?? []
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
/**
|
|
@@ -127,6 +127,8 @@ export class AgentPerformanceTracker {
|
|
|
127
127
|
{ agents: [] }
|
|
128
128
|
)
|
|
129
129
|
|
|
130
|
+
if (!data) return
|
|
131
|
+
|
|
130
132
|
// Find or create agent performance
|
|
131
133
|
let agentPerf = data.agents.find((a) => a.agentName === record.agentName)
|
|
132
134
|
|