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
package/core/commands/base.ts
CHANGED
|
@@ -1,281 +1,105 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Base class and helpers for PrjctCommands
|
|
3
|
+
*
|
|
4
|
+
* Delegates to service modules for business logic.
|
|
5
|
+
* This class maintains backward compatibility while services handle implementation.
|
|
3
6
|
*/
|
|
4
7
|
|
|
5
8
|
import commandExecutor from '../agentic/command-executor'
|
|
6
9
|
import contextBuilder from '../agentic/context-builder'
|
|
7
10
|
import toolRegistry from '../agentic/tool-registry'
|
|
8
|
-
import AgentRouter from '../agentic/agent-router'
|
|
9
11
|
import pathManager from '../infrastructure/path-manager'
|
|
10
12
|
import configManager from '../infrastructure/config-manager'
|
|
11
|
-
import authorDetector from '../infrastructure/author-detector'
|
|
12
|
-
import agentDetector from '../infrastructure/agent-detector'
|
|
13
13
|
import UpdateChecker from '../infrastructure/update-checker'
|
|
14
14
|
import dateHelper from '../utils/date-helper'
|
|
15
15
|
import jsonlHelper from '../utils/jsonl-helper'
|
|
16
16
|
import * as fileHelper from '../utils/file-helper'
|
|
17
17
|
import out from '../utils/output'
|
|
18
18
|
|
|
19
|
+
// Services
|
|
20
|
+
import { agentService, projectService, memoryService, breakdownService } from '../services'
|
|
21
|
+
|
|
19
22
|
import type {
|
|
20
23
|
CommandResult,
|
|
21
24
|
AgentInfo,
|
|
22
25
|
Author,
|
|
23
26
|
AgentAssignmentResult,
|
|
24
|
-
|
|
25
|
-
} from '
|
|
26
|
-
import { ProjectError, AgentError } from '../errors'
|
|
27
|
-
|
|
28
|
-
// Valid agent types - whitelist for security (prevents path traversal)
|
|
29
|
-
const VALID_AGENT_TYPES = ['claude'] as const
|
|
30
|
-
type ValidAgentType = typeof VALID_AGENT_TYPES[number]
|
|
31
|
-
|
|
32
|
-
// Lazy-loaded to avoid circular dependencies
|
|
33
|
-
let _planningCommands: import('./planning').PlanningCommands | null = null
|
|
34
|
-
async function getPlanningCommands(): Promise<import('./planning').PlanningCommands> {
|
|
35
|
-
if (!_planningCommands) {
|
|
36
|
-
const { PlanningCommands } = await import('./planning')
|
|
37
|
-
_planningCommands = new PlanningCommands()
|
|
38
|
-
}
|
|
39
|
-
return _planningCommands
|
|
40
|
-
}
|
|
27
|
+
ProjectContext
|
|
28
|
+
} from '../types'
|
|
41
29
|
|
|
42
30
|
/**
|
|
43
31
|
* Base class with shared state and utilities
|
|
32
|
+
* Delegates to service modules for implementation
|
|
44
33
|
*/
|
|
45
34
|
export class PrjctCommandsBase {
|
|
46
|
-
agent: unknown
|
|
47
|
-
agentInfo: AgentInfo | null
|
|
48
|
-
currentAuthor: Author | null
|
|
49
35
|
prjctDir: string
|
|
50
36
|
updateChecker: UpdateChecker
|
|
51
37
|
updateNotificationShown: boolean
|
|
52
38
|
commandExecutor: typeof commandExecutor
|
|
53
|
-
agentRouter: AgentRouter
|
|
54
39
|
|
|
55
40
|
constructor() {
|
|
56
|
-
this.agent = null
|
|
57
|
-
this.agentInfo = null
|
|
58
|
-
this.currentAuthor = null
|
|
59
41
|
this.prjctDir = '.prjct'
|
|
60
42
|
this.updateChecker = new UpdateChecker()
|
|
61
43
|
this.updateNotificationShown = false
|
|
62
44
|
this.commandExecutor = commandExecutor
|
|
63
|
-
this.agentRouter = new AgentRouter()
|
|
64
45
|
}
|
|
65
46
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (this.agent) return this.agent
|
|
71
|
-
|
|
72
|
-
this.agentInfo = await agentDetector.detect()
|
|
73
|
-
|
|
74
|
-
if (!this.agentInfo.isSupported) {
|
|
75
|
-
throw AgentError.notSupported(this.agentInfo.type)
|
|
76
|
-
}
|
|
47
|
+
// Agent accessors (delegate to agentService)
|
|
48
|
+
get agent(): unknown {
|
|
49
|
+
return agentService.getAgent()
|
|
50
|
+
}
|
|
77
51
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
throw AgentError.notSupported(this.agentInfo.type)
|
|
82
|
-
}
|
|
52
|
+
get agentInfo(): AgentInfo | null {
|
|
53
|
+
return agentService.getInfo()
|
|
54
|
+
}
|
|
83
55
|
|
|
84
|
-
|
|
85
|
-
|
|
56
|
+
get currentAuthor(): Author | null {
|
|
57
|
+
return projectService.getCurrentAuthor()
|
|
58
|
+
}
|
|
86
59
|
|
|
87
|
-
|
|
60
|
+
async initializeAgent(): Promise<unknown> {
|
|
61
|
+
return agentService.initialize()
|
|
88
62
|
}
|
|
89
63
|
|
|
90
|
-
/**
|
|
91
|
-
* Ensure project is initialized
|
|
92
|
-
*/
|
|
93
64
|
async ensureProjectInit(projectPath: string): Promise<CommandResult> {
|
|
94
|
-
|
|
95
|
-
return { success: true }
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
out.spin('initializing project...')
|
|
99
|
-
const planning = await getPlanningCommands()
|
|
100
|
-
const initResult = await planning.init(null, projectPath)
|
|
101
|
-
if (!initResult.success) {
|
|
102
|
-
return initResult
|
|
103
|
-
}
|
|
104
|
-
return { success: true }
|
|
65
|
+
return projectService.ensureInit(projectPath)
|
|
105
66
|
}
|
|
106
67
|
|
|
107
|
-
/**
|
|
108
|
-
* Ensure author information is loaded
|
|
109
|
-
*/
|
|
110
68
|
async ensureAuthor(): Promise<Author> {
|
|
111
|
-
|
|
112
|
-
// detectAuthorForLogs returns a string (username), detect() returns full Author
|
|
113
|
-
const authorObj = await authorDetector.detect()
|
|
114
|
-
this.currentAuthor = {
|
|
115
|
-
name: authorObj.name,
|
|
116
|
-
email: authorObj.email,
|
|
117
|
-
github: authorObj.github
|
|
118
|
-
}
|
|
119
|
-
return this.currentAuthor
|
|
69
|
+
return projectService.ensureAuthor()
|
|
120
70
|
}
|
|
121
71
|
|
|
122
|
-
/**
|
|
123
|
-
* Get global project path
|
|
124
|
-
*/
|
|
125
72
|
async getGlobalProjectPath(projectPath: string): Promise<string> {
|
|
126
|
-
|
|
127
|
-
if (!projectId) {
|
|
128
|
-
throw ProjectError.notInitialized()
|
|
129
|
-
}
|
|
130
|
-
await pathManager.ensureProjectStructure(projectId)
|
|
131
|
-
return pathManager.getGlobalProjectPath(projectId)
|
|
73
|
+
return projectService.getGlobalPath(projectPath)
|
|
132
74
|
}
|
|
133
75
|
|
|
134
|
-
/**
|
|
135
|
-
* Log to memory
|
|
136
|
-
*/
|
|
137
76
|
async logToMemory(projectPath: string, action: string, data: Record<string, unknown>): Promise<void> {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const projectId = await configManager.getProjectId(projectPath)
|
|
141
|
-
const memoryPath = pathManager.getFilePath(projectId!, 'memory', 'context.jsonl')
|
|
142
|
-
|
|
143
|
-
const entry = {
|
|
144
|
-
timestamp: dateHelper.getTimestamp(),
|
|
145
|
-
action,
|
|
146
|
-
data,
|
|
147
|
-
author: author.name,
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
await jsonlHelper.appendJsonLine(memoryPath, entry)
|
|
151
|
-
} catch {
|
|
152
|
-
// Non-critical - don't fail the command
|
|
153
|
-
}
|
|
77
|
+
const author = await this.ensureAuthor()
|
|
78
|
+
return memoryService.log(projectPath, action, data, author.name)
|
|
154
79
|
}
|
|
155
80
|
|
|
156
|
-
/**
|
|
157
|
-
* Detect if directory is empty (excluding common files)
|
|
158
|
-
*/
|
|
159
81
|
async _detectEmptyDirectory(projectPath: string): Promise<boolean> {
|
|
160
|
-
|
|
161
|
-
const entries = await fileHelper.listFiles(projectPath)
|
|
162
|
-
const meaningfulFiles = entries.filter(
|
|
163
|
-
(name) =>
|
|
164
|
-
!name.startsWith('.') &&
|
|
165
|
-
name !== 'node_modules' &&
|
|
166
|
-
name !== 'package.json' &&
|
|
167
|
-
name !== 'package-lock.json' &&
|
|
168
|
-
name !== 'README.md'
|
|
169
|
-
)
|
|
170
|
-
return meaningfulFiles.length === 0
|
|
171
|
-
} catch {
|
|
172
|
-
return true
|
|
173
|
-
}
|
|
82
|
+
return projectService.isEmptyDirectory(projectPath)
|
|
174
83
|
}
|
|
175
84
|
|
|
176
|
-
/**
|
|
177
|
-
* Detect if directory has existing code
|
|
178
|
-
*/
|
|
179
85
|
async _detectExistingCode(projectPath: string): Promise<boolean> {
|
|
180
|
-
|
|
181
|
-
const codePatterns = [
|
|
182
|
-
'src', 'lib', 'app', 'components', 'pages', 'api',
|
|
183
|
-
'main.go', 'main.rs', 'main.py',
|
|
184
|
-
]
|
|
185
|
-
const entries = await fileHelper.listFiles(projectPath)
|
|
186
|
-
return entries.some((name) => codePatterns.includes(name))
|
|
187
|
-
} catch {
|
|
188
|
-
return false
|
|
189
|
-
}
|
|
86
|
+
return projectService.hasExistingCode(projectPath)
|
|
190
87
|
}
|
|
191
88
|
|
|
192
|
-
/**
|
|
193
|
-
* Breakdown feature into tasks
|
|
194
|
-
*/
|
|
195
89
|
_breakdownFeatureTasks(description: string): string[] {
|
|
196
|
-
return
|
|
197
|
-
`Analyze and plan: ${description}`,
|
|
198
|
-
'Implement core functionality',
|
|
199
|
-
'Test and validate',
|
|
200
|
-
'Document changes',
|
|
201
|
-
]
|
|
90
|
+
return breakdownService.breakdownFeature(description)
|
|
202
91
|
}
|
|
203
92
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
*/
|
|
207
|
-
_detectBugSeverity(_description: string): string {
|
|
208
|
-
return 'medium'
|
|
93
|
+
_detectBugSeverity(description: string): string {
|
|
94
|
+
return breakdownService.detectBugSeverity(description)
|
|
209
95
|
}
|
|
210
96
|
|
|
211
|
-
/**
|
|
212
|
-
* Assign agent for a task using AgentRouter
|
|
213
|
-
* Returns agent info for Claude to delegate work
|
|
214
|
-
*/
|
|
215
97
|
async _assignAgentForTask(
|
|
216
98
|
task: string,
|
|
217
99
|
projectPath: string,
|
|
218
|
-
|
|
100
|
+
context: ProjectContext
|
|
219
101
|
): Promise<AgentAssignmentResult> {
|
|
220
|
-
|
|
221
|
-
await this.agentRouter.initialize(projectPath)
|
|
222
|
-
const agents = await this.agentRouter.getAgentNames()
|
|
223
|
-
|
|
224
|
-
if (agents.length === 0) {
|
|
225
|
-
return {
|
|
226
|
-
agent: { name: 'generalist' },
|
|
227
|
-
routing: {
|
|
228
|
-
confidence: 1.0,
|
|
229
|
-
reason: 'No specialized agents available',
|
|
230
|
-
availableAgents: [],
|
|
231
|
-
},
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Simple keyword matching for agent assignment
|
|
236
|
-
// Claude will make the final decision via templates
|
|
237
|
-
const taskLower = task.toLowerCase()
|
|
238
|
-
let bestMatch = 'generalist'
|
|
239
|
-
|
|
240
|
-
for (const agentName of agents) {
|
|
241
|
-
const nameLower = agentName.toLowerCase()
|
|
242
|
-
if (taskLower.includes(nameLower) || nameLower.includes('general')) {
|
|
243
|
-
bestMatch = agentName
|
|
244
|
-
break
|
|
245
|
-
}
|
|
246
|
-
// Common domain keywords
|
|
247
|
-
if ((nameLower.includes('fe') || nameLower.includes('frontend')) &&
|
|
248
|
-
(taskLower.includes('ui') || taskLower.includes('component') || taskLower.includes('react'))) {
|
|
249
|
-
bestMatch = agentName
|
|
250
|
-
break
|
|
251
|
-
}
|
|
252
|
-
if ((nameLower.includes('be') || nameLower.includes('backend')) &&
|
|
253
|
-
(taskLower.includes('api') || taskLower.includes('server') || taskLower.includes('database'))) {
|
|
254
|
-
bestMatch = agentName
|
|
255
|
-
break
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
await this.agentRouter.logUsage(task, bestMatch, projectPath)
|
|
260
|
-
|
|
261
|
-
return {
|
|
262
|
-
agent: { name: bestMatch },
|
|
263
|
-
routing: {
|
|
264
|
-
confidence: 0.7,
|
|
265
|
-
reason: 'Keyword-based agent matching',
|
|
266
|
-
availableAgents: agents,
|
|
267
|
-
},
|
|
268
|
-
_agenticNote: 'Claude should verify this assignment using agent context',
|
|
269
|
-
}
|
|
270
|
-
} catch {
|
|
271
|
-
return {
|
|
272
|
-
agent: { name: 'generalist' },
|
|
273
|
-
routing: {
|
|
274
|
-
confidence: 1.0,
|
|
275
|
-
reason: 'Agent routing unavailable',
|
|
276
|
-
},
|
|
277
|
-
}
|
|
278
|
-
}
|
|
102
|
+
return agentService.assignForTask(task, projectPath, context)
|
|
279
103
|
}
|
|
280
104
|
}
|
|
281
105
|
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cleanup Commands
|
|
3
|
+
*
|
|
4
|
+
* Memory and project file cleanup operations.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import path from 'path'
|
|
8
|
+
|
|
9
|
+
import type { CommandResult, CleanupOptions } from '../types'
|
|
10
|
+
import {
|
|
11
|
+
pathManager,
|
|
12
|
+
configManager,
|
|
13
|
+
jsonlHelper,
|
|
14
|
+
dateHelper,
|
|
15
|
+
out
|
|
16
|
+
} from './base'
|
|
17
|
+
import { ideasStorage, queueStorage } from '../storage'
|
|
18
|
+
import { memoryService } from '../services'
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Memory cleanup helper
|
|
22
|
+
*/
|
|
23
|
+
export async function cleanupMemory(projectPath: string): Promise<{
|
|
24
|
+
success: boolean
|
|
25
|
+
results: { rotated: string[]; totalSize: number; freedSpace: number }
|
|
26
|
+
}> {
|
|
27
|
+
const projectId = await configManager.getProjectId(projectPath)
|
|
28
|
+
|
|
29
|
+
const results = { rotated: [] as string[], totalSize: 0, freedSpace: 0 }
|
|
30
|
+
const jsonlFiles = [
|
|
31
|
+
pathManager.getFilePath(projectId!, 'memory', 'context.jsonl'),
|
|
32
|
+
pathManager.getFilePath(projectId!, 'progress', 'shipped.md'),
|
|
33
|
+
pathManager.getFilePath(projectId!, 'planning', 'ideas.md'),
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
for (const filePath of jsonlFiles) {
|
|
37
|
+
try {
|
|
38
|
+
const sizeMB = await jsonlHelper.getFileSizeMB(filePath)
|
|
39
|
+
if (sizeMB > 0) {
|
|
40
|
+
results.totalSize += sizeMB
|
|
41
|
+
const rotated = await jsonlHelper.rotateJsonLinesIfNeeded(filePath, 10)
|
|
42
|
+
if (rotated) {
|
|
43
|
+
results.rotated.push(path.basename(filePath))
|
|
44
|
+
results.freedSpace += sizeMB
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
} catch {
|
|
48
|
+
// skip
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return { success: true, results }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Internal cleanup helper for memory during normal cleanup
|
|
57
|
+
*/
|
|
58
|
+
export async function cleanupMemoryInternal(projectPath: string): Promise<void> {
|
|
59
|
+
const projectId = await configManager.getProjectId(projectPath)
|
|
60
|
+
const memoryPath = pathManager.getFilePath(projectId!, 'memory', 'context.jsonl')
|
|
61
|
+
await jsonlHelper.rotateJsonLinesIfNeeded(memoryPath, 10)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* /p:cleanup - Clean temp files and old entries
|
|
66
|
+
*/
|
|
67
|
+
export async function cleanup(
|
|
68
|
+
options: CleanupOptions = {},
|
|
69
|
+
projectPath: string = process.cwd()
|
|
70
|
+
): Promise<CommandResult> {
|
|
71
|
+
try {
|
|
72
|
+
const isMemoryMode = options.memory === true || options.type === 'memory'
|
|
73
|
+
|
|
74
|
+
if (isMemoryMode) {
|
|
75
|
+
out.spin('cleaning memory...')
|
|
76
|
+
const result = await cleanupMemory(projectPath)
|
|
77
|
+
out.done('memory cleaned')
|
|
78
|
+
return result
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
out.spin('cleaning up...')
|
|
82
|
+
|
|
83
|
+
const projectId = await configManager.getProjectId(projectPath)
|
|
84
|
+
if (!projectId) {
|
|
85
|
+
out.fail('no project ID')
|
|
86
|
+
return { success: false, error: 'No project ID found' }
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const cleaned: string[] = []
|
|
90
|
+
|
|
91
|
+
// Clean memory (keep last 100 entries)
|
|
92
|
+
const memoryPath = pathManager.getFilePath(projectId, 'memory', 'context.jsonl')
|
|
93
|
+
try {
|
|
94
|
+
const entries = await jsonlHelper.readJsonLines(memoryPath)
|
|
95
|
+
|
|
96
|
+
if (entries.length > 100) {
|
|
97
|
+
const kept = entries.slice(-100)
|
|
98
|
+
await jsonlHelper.writeJsonLines(memoryPath, kept)
|
|
99
|
+
cleaned.push(`Memory: ${entries.length - 100} old entries removed`)
|
|
100
|
+
} else {
|
|
101
|
+
cleaned.push('Memory: No cleanup needed')
|
|
102
|
+
}
|
|
103
|
+
} catch {
|
|
104
|
+
cleaned.push('Memory: No file found')
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Clean ideas using ideasStorage
|
|
108
|
+
try {
|
|
109
|
+
const result = await ideasStorage.cleanup(projectId)
|
|
110
|
+
if (result.removed > 0) {
|
|
111
|
+
cleaned.push(`Ideas: ${result.removed} old archived ideas removed`)
|
|
112
|
+
} else {
|
|
113
|
+
cleaned.push('Ideas: No cleanup needed')
|
|
114
|
+
}
|
|
115
|
+
} catch {
|
|
116
|
+
cleaned.push('Ideas: No file found')
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Check queue for completed tasks using queueStorage
|
|
120
|
+
try {
|
|
121
|
+
const tasks = await queueStorage.getActiveTasks(projectId)
|
|
122
|
+
const completedTasks = tasks.filter(t => t.completed).length
|
|
123
|
+
|
|
124
|
+
if (completedTasks > 0) {
|
|
125
|
+
cleaned.push(
|
|
126
|
+
`Queue: ${completedTasks} completed tasks found (not removed - use /p:done to clear)`
|
|
127
|
+
)
|
|
128
|
+
} else {
|
|
129
|
+
cleaned.push('Queue: No completed tasks')
|
|
130
|
+
}
|
|
131
|
+
} catch {
|
|
132
|
+
cleaned.push('Queue: No file found')
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
await cleanupMemoryInternal(projectPath)
|
|
136
|
+
|
|
137
|
+
await memoryService.log(projectPath, 'cleanup_performed', {
|
|
138
|
+
items: cleaned.length,
|
|
139
|
+
timestamp: dateHelper.getTimestamp(),
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
out.done(`${cleaned.length} items cleaned`)
|
|
143
|
+
return { success: true, cleaned }
|
|
144
|
+
} catch (error) {
|
|
145
|
+
out.fail((error as Error).message)
|
|
146
|
+
return { success: false, error: (error as Error).message }
|
|
147
|
+
}
|
|
148
|
+
}
|