codingbuddy 5.3.0 → 5.4.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/dist/src/agent/index.d.ts +1 -0
- package/dist/src/agent/index.js +1 -0
- package/dist/src/agent/stack-matcher.d.ts +13 -0
- package/dist/src/agent/stack-matcher.js +81 -0
- package/dist/src/collaboration/index.d.ts +0 -2
- package/dist/src/collaboration/index.js +1 -3
- package/dist/src/keyword/keyword.module.js +39 -2
- package/dist/src/keyword/keyword.service.d.ts +5 -0
- package/dist/src/keyword/keyword.service.js +90 -6
- package/dist/src/keyword/keyword.types.d.ts +24 -2
- package/dist/src/keyword/permission-forecast.d.ts +2 -0
- package/dist/src/keyword/permission-forecast.js +94 -0
- package/dist/src/mcp/handlers/agent.handler.js +1 -1
- package/dist/src/mcp/handlers/clarification-gate.d.ts +22 -0
- package/dist/src/mcp/handlers/clarification-gate.js +129 -0
- package/dist/src/mcp/handlers/council-scene.builder.d.ts +9 -0
- package/dist/src/mcp/handlers/council-scene.builder.js +115 -0
- package/dist/src/mcp/handlers/council-scene.types.d.ts +11 -0
- package/dist/src/{collaboration/council-summary.types.js → mcp/handlers/council-scene.types.js} +1 -1
- package/dist/src/mcp/handlers/discussion.handler.d.ts +1 -0
- package/dist/src/mcp/handlers/discussion.handler.js +23 -4
- package/dist/src/mcp/handlers/discussion.types.d.ts +12 -0
- package/dist/src/mcp/handlers/discussion.types.js +4 -1
- package/dist/src/mcp/handlers/execution-gate.d.ts +29 -0
- package/dist/src/mcp/handlers/execution-gate.js +49 -0
- package/dist/src/mcp/handlers/index.d.ts +1 -0
- package/dist/src/mcp/handlers/index.js +3 -1
- package/dist/src/mcp/handlers/mode.handler.d.ts +5 -0
- package/dist/src/mcp/handlers/mode.handler.js +127 -2
- package/dist/src/mcp/handlers/planning-contract.d.ts +2 -0
- package/dist/src/mcp/handlers/planning-contract.js +28 -0
- package/dist/src/mcp/handlers/planning-stage.d.ts +20 -0
- package/dist/src/mcp/handlers/planning-stage.js +58 -0
- package/dist/src/mcp/handlers/review-pr.handler.d.ts +12 -0
- package/dist/src/mcp/handlers/review-pr.handler.js +81 -0
- package/dist/src/mcp/mcp.module.js +1 -0
- package/dist/src/shared/version.d.ts +1 -1
- package/dist/src/shared/version.js +1 -1
- package/dist/src/ship/review-pr.service.d.ts +15 -0
- package/dist/src/ship/review-pr.service.js +136 -0
- package/dist/src/ship/review-pr.types.d.ts +21 -0
- package/dist/src/ship/review-pr.types.js +3 -0
- package/dist/src/ship/ship.module.js +5 -2
- package/package.json +2 -2
- package/dist/src/collaboration/council-summary.service.d.ts +0 -2
- package/dist/src/collaboration/council-summary.service.js +0 -114
- package/dist/src/collaboration/council-summary.types.d.ts +0 -24
package/dist/src/agent/index.js
CHANGED
|
@@ -26,4 +26,5 @@ __exportStar(require("./agent-stack.schema"), exports);
|
|
|
26
26
|
__exportStar(require("./agent-stack.loader"), exports);
|
|
27
27
|
__exportStar(require("./execution-plan"), exports);
|
|
28
28
|
__exportStar(require("./execution-plan.types"), exports);
|
|
29
|
+
__exportStar(require("./stack-matcher"), exports);
|
|
29
30
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface StackMatchInput {
|
|
2
|
+
name: string;
|
|
3
|
+
category: string;
|
|
4
|
+
tags: string[];
|
|
5
|
+
specialist_agents?: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface StackMatchResult {
|
|
8
|
+
stackName: string;
|
|
9
|
+
confidence: number;
|
|
10
|
+
matchedTags: string[];
|
|
11
|
+
stackBased: true;
|
|
12
|
+
}
|
|
13
|
+
export declare function matchStack(prompt: string, stacks: readonly StackMatchInput[]): StackMatchResult | null;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.matchStack = matchStack;
|
|
4
|
+
const DOMAIN_KEYWORDS = [
|
|
5
|
+
{ pattern: /\bREST\b/i, tags: ['rest', 'api'] },
|
|
6
|
+
{ pattern: /\bGraphQL\b/i, tags: ['graphql', 'api'] },
|
|
7
|
+
{ pattern: /\bAPI\b/i, tags: ['api'] },
|
|
8
|
+
{ pattern: /\bbackend\b/i, tags: ['backend'] },
|
|
9
|
+
{ pattern: /\bendpoint/i, tags: ['api', 'backend'] },
|
|
10
|
+
{ pattern: /\bcontroller/i, tags: ['api', 'backend'] },
|
|
11
|
+
{ pattern: /\bservice\s+layer/i, tags: ['backend'] },
|
|
12
|
+
{ pattern: /\broute/i, tags: ['api', 'backend'] },
|
|
13
|
+
{ pattern: /\bsecurity\b/i, tags: ['security'] },
|
|
14
|
+
{ pattern: /\baudit\b/i, tags: ['audit', 'security'] },
|
|
15
|
+
{ pattern: /\b(?:vulnerability|vulnerabilities)\b/i, tags: ['vulnerability', 'security'] },
|
|
16
|
+
{ pattern: /\bcompliance\b/i, tags: ['compliance', 'security'] },
|
|
17
|
+
{ pattern: /\bOAuth\b/i, tags: ['security'] },
|
|
18
|
+
{ pattern: /\bJWT\b/i, tags: ['security'] },
|
|
19
|
+
{ pattern: /\b(?:XSS|CSRF)\b/i, tags: ['security', 'vulnerability'] },
|
|
20
|
+
{ pattern: /\bauthenticat/i, tags: ['security'] },
|
|
21
|
+
{ pattern: /\bUI\b/i, tags: ['ui', 'frontend'] },
|
|
22
|
+
{ pattern: /\bUX\b/i, tags: ['ux', 'frontend'] },
|
|
23
|
+
{ pattern: /\baccessibility\b/i, tags: ['accessibility', 'frontend'] },
|
|
24
|
+
{ pattern: /\bSEO\b/i, tags: ['seo', 'frontend'] },
|
|
25
|
+
{ pattern: /\bfrontend\b/i, tags: ['frontend'] },
|
|
26
|
+
{ pattern: /\bETL\b/i, tags: ['etl', 'data'] },
|
|
27
|
+
{ pattern: /\bpipeline\b/i, tags: ['pipeline', 'data'] },
|
|
28
|
+
{ pattern: /\banalytics\b/i, tags: ['analytics', 'data'] },
|
|
29
|
+
{ pattern: /\bdata\s+(warehouse|lake|pipeline|ingestion)/i, tags: ['data', 'pipeline'] },
|
|
30
|
+
{ pattern: /\bmodel\s+(training|inference|deploy)/i, tags: ['model', 'ml'] },
|
|
31
|
+
{ pattern: /\bML\b/i, tags: ['ml'] },
|
|
32
|
+
{ pattern: /\bmachine\s*learning/i, tags: ['ml', 'ai'] },
|
|
33
|
+
{ pattern: /\binference\b/i, tags: ['inference', 'ml'] },
|
|
34
|
+
{ pattern: /\btraining\b/i, tags: ['training', 'ml'] },
|
|
35
|
+
{ pattern: /\bfull[- ]?stack\b/i, tags: ['fullstack'] },
|
|
36
|
+
{ pattern: /보안/i, tags: ['security'] },
|
|
37
|
+
{ pattern: /취약점/i, tags: ['vulnerability', 'security'] },
|
|
38
|
+
{ pattern: /감사/i, tags: ['audit', 'security'] },
|
|
39
|
+
{ pattern: /접근성/i, tags: ['accessibility', 'frontend'] },
|
|
40
|
+
{ pattern: /데이터\s*파이프라인/i, tags: ['data', 'pipeline'] },
|
|
41
|
+
{ pattern: /머신\s*러닝|기계\s*학습/i, tags: ['ml', 'ai'] },
|
|
42
|
+
];
|
|
43
|
+
const MIN_CONFIDENCE = 0.3;
|
|
44
|
+
function matchStack(prompt, stacks) {
|
|
45
|
+
if (!prompt || stacks.length === 0)
|
|
46
|
+
return null;
|
|
47
|
+
const detectedTags = new Set();
|
|
48
|
+
for (const { pattern, tags } of DOMAIN_KEYWORDS) {
|
|
49
|
+
if (pattern.test(prompt)) {
|
|
50
|
+
for (const tag of tags)
|
|
51
|
+
detectedTags.add(tag);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (detectedTags.size === 0)
|
|
55
|
+
return null;
|
|
56
|
+
let bestResult = null;
|
|
57
|
+
for (const stack of stacks) {
|
|
58
|
+
const matched = [];
|
|
59
|
+
for (const tag of stack.tags) {
|
|
60
|
+
if (detectedTags.has(tag))
|
|
61
|
+
matched.push(tag);
|
|
62
|
+
}
|
|
63
|
+
if (matched.length === 0)
|
|
64
|
+
continue;
|
|
65
|
+
const tagCoverage = matched.length / stack.tags.length;
|
|
66
|
+
const detectedCoverage = matched.length / detectedTags.size;
|
|
67
|
+
const confidence = Math.min((tagCoverage + detectedCoverage) / 2, 1.0);
|
|
68
|
+
if (confidence < MIN_CONFIDENCE)
|
|
69
|
+
continue;
|
|
70
|
+
if (!bestResult || confidence > bestResult.confidence) {
|
|
71
|
+
bestResult = {
|
|
72
|
+
stackName: stack.name,
|
|
73
|
+
confidence,
|
|
74
|
+
matchedTags: matched,
|
|
75
|
+
stackBased: true,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return bestResult;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=stack-matcher.js.map
|
|
@@ -3,5 +3,3 @@ export { STANCES, STANCE_ICONS, createAgentOpinion, createCrossReview, createDis
|
|
|
3
3
|
export { DiscussionEngine } from './discussion-engine';
|
|
4
4
|
export { formatOpinion, formatCrossReview, formatConsensus, formatDiscussionRound, } from './terminal-formatter';
|
|
5
5
|
export { mapSeverityToStance, convertSpecialistResult, convertSpecialistResults, type FindingSeverity, type SpecialistFinding, type SpecialistResult, } from './opinion-adapter';
|
|
6
|
-
export type { CouncilInput, CouncilSummary, Disagreement, DisagreementPosition, } from './council-summary.types';
|
|
7
|
-
export { generateCouncilSummary } from './council-summary.service';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.convertSpecialistResults = exports.convertSpecialistResult = exports.mapSeverityToStance = exports.formatDiscussionRound = exports.formatConsensus = exports.formatCrossReview = exports.formatOpinion = exports.DiscussionEngine = exports.calculateConsensus = exports.createDiscussionRound = exports.createCrossReview = exports.createAgentOpinion = exports.STANCE_ICONS = exports.STANCES = void 0;
|
|
4
4
|
var types_1 = require("./types");
|
|
5
5
|
Object.defineProperty(exports, "STANCES", { enumerable: true, get: function () { return types_1.STANCES; } });
|
|
6
6
|
Object.defineProperty(exports, "STANCE_ICONS", { enumerable: true, get: function () { return types_1.STANCE_ICONS; } });
|
|
@@ -19,6 +19,4 @@ var opinion_adapter_1 = require("./opinion-adapter");
|
|
|
19
19
|
Object.defineProperty(exports, "mapSeverityToStance", { enumerable: true, get: function () { return opinion_adapter_1.mapSeverityToStance; } });
|
|
20
20
|
Object.defineProperty(exports, "convertSpecialistResult", { enumerable: true, get: function () { return opinion_adapter_1.convertSpecialistResult; } });
|
|
21
21
|
Object.defineProperty(exports, "convertSpecialistResults", { enumerable: true, get: function () { return opinion_adapter_1.convertSpecialistResults; } });
|
|
22
|
-
var council_summary_service_1 = require("./council-summary.service");
|
|
23
|
-
Object.defineProperty(exports, "generateCouncilSummary", { enumerable: true, get: function () { return council_summary_service_1.generateCouncilSummary; } });
|
|
24
22
|
//# sourceMappingURL=index.js.map
|
|
@@ -16,6 +16,7 @@ const skill_module_1 = require("../skill/skill.module");
|
|
|
16
16
|
const skill_recommendation_service_1 = require("../skill/skill-recommendation.service");
|
|
17
17
|
const agent_module_1 = require("../agent/agent.module");
|
|
18
18
|
const agent_service_1 = require("../agent/agent.service");
|
|
19
|
+
const agent_stack_service_1 = require("../agent/agent-stack.service");
|
|
19
20
|
const agent_utils_1 = require("../shared/agent.utils");
|
|
20
21
|
const client_type_1 = require("../shared/client-type");
|
|
21
22
|
const keyword_service_1 = require("./keyword.service");
|
|
@@ -30,7 +31,7 @@ exports.KeywordModule = KeywordModule = __decorate([
|
|
|
30
31
|
providers: [
|
|
31
32
|
{
|
|
32
33
|
provide: exports.KEYWORD_SERVICE,
|
|
33
|
-
useFactory: (rulesService, configService, skillRecommendationService, agentService) => {
|
|
34
|
+
useFactory: (rulesService, configService, skillRecommendationService, agentService, agentStackService) => {
|
|
34
35
|
const logger = new common_1.Logger('KeywordModule');
|
|
35
36
|
const loadConfig = async () => {
|
|
36
37
|
const content = await rulesService.getRuleContent('keyword-modes.json');
|
|
@@ -157,6 +158,35 @@ exports.KeywordModule = KeywordModule = __decorate([
|
|
|
157
158
|
return null;
|
|
158
159
|
}
|
|
159
160
|
};
|
|
161
|
+
const loadStacks = async () => {
|
|
162
|
+
try {
|
|
163
|
+
const summaries = await agentStackService.listStacks();
|
|
164
|
+
const results = [];
|
|
165
|
+
for (const summary of summaries) {
|
|
166
|
+
try {
|
|
167
|
+
const full = await agentStackService.resolveStack(summary.name);
|
|
168
|
+
results.push({
|
|
169
|
+
name: full.name,
|
|
170
|
+
category: full.category,
|
|
171
|
+
tags: full.tags,
|
|
172
|
+
specialist_agents: full.specialist_agents,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
results.push({
|
|
177
|
+
name: summary.name,
|
|
178
|
+
category: summary.category,
|
|
179
|
+
tags: summary.tags ?? [],
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return results;
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
logger.debug(`Failed to load agent stacks: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
187
|
+
return [];
|
|
188
|
+
}
|
|
189
|
+
};
|
|
160
190
|
const options = {
|
|
161
191
|
primaryAgentResolver,
|
|
162
192
|
loadAutoConfigFn: loadAutoConfig,
|
|
@@ -165,10 +195,17 @@ exports.KeywordModule = KeywordModule = __decorate([
|
|
|
165
195
|
loadAgentSystemPromptFn: loadAgentSystemPrompt,
|
|
166
196
|
getMaxIncludedSkillsFn: getMaxIncludedSkills,
|
|
167
197
|
getClientTypeFn: () => (0, client_type_1.resolveClientType)(configService.getClientName()),
|
|
198
|
+
loadStacksFn: loadStacks,
|
|
168
199
|
};
|
|
169
200
|
return new keyword_service_1.KeywordService(loadConfig, loadRule, loadAgent, options);
|
|
170
201
|
},
|
|
171
|
-
inject: [
|
|
202
|
+
inject: [
|
|
203
|
+
rules_service_1.RulesService,
|
|
204
|
+
config_service_1.ConfigService,
|
|
205
|
+
skill_recommendation_service_1.SkillRecommendationService,
|
|
206
|
+
agent_service_1.AgentService,
|
|
207
|
+
agent_stack_service_1.AgentStackService,
|
|
208
|
+
],
|
|
172
209
|
},
|
|
173
210
|
],
|
|
174
211
|
exports: [exports.KEYWORD_SERVICE],
|
|
@@ -2,6 +2,7 @@ import { type Mode, type RuleContent, type ParseModeResult, type KeywordModesCon
|
|
|
2
2
|
import { type VerbosityLevel } from '../shared/verbosity.types';
|
|
3
3
|
import { PrimaryAgentResolver } from './primary-agent-resolver';
|
|
4
4
|
import { type ClientType } from '../shared/client-type';
|
|
5
|
+
import { type StackMatchInput } from '../agent/stack-matcher';
|
|
5
6
|
export interface ParseModeOptions {
|
|
6
7
|
recommendedActAgent?: string;
|
|
7
8
|
context?: ResolutionContext;
|
|
@@ -19,6 +20,7 @@ export interface KeywordServiceOptions {
|
|
|
19
20
|
getMaxIncludedSkillsFn?: () => Promise<number | null>;
|
|
20
21
|
getClientTypeFn?: () => ClientType;
|
|
21
22
|
trackRuleUsageFn?: (ruleNames: string[]) => void;
|
|
23
|
+
loadStacksFn?: () => Promise<StackMatchInput[]>;
|
|
22
24
|
}
|
|
23
25
|
export interface SkillRecommendationInfo {
|
|
24
26
|
skillName: string;
|
|
@@ -54,6 +56,7 @@ export declare class KeywordService {
|
|
|
54
56
|
private readonly getMaxIncludedSkillsFn?;
|
|
55
57
|
private readonly getClientTypeFn?;
|
|
56
58
|
private readonly trackRuleUsageFn?;
|
|
59
|
+
private readonly loadStacksFn?;
|
|
57
60
|
private static readonly CONTEXT_SPECIALIST_PATTERNS;
|
|
58
61
|
constructor(loadConfigFn: () => Promise<KeywordModesConfig>, loadRuleFn: (path: string) => Promise<string>, loadAgentInfoFn?: ((agentName: string) => Promise<unknown>) | undefined, options?: KeywordServiceOptions);
|
|
59
62
|
parseMode(prompt: string, options?: ParseModeOptions): Promise<ParseModeResult>;
|
|
@@ -73,6 +76,8 @@ export declare class KeywordService {
|
|
|
73
76
|
private addAutoConfigToResult;
|
|
74
77
|
private addComplexityToResult;
|
|
75
78
|
private addIncludedSkillsToResult;
|
|
79
|
+
private enforceRequiredAgentSkills;
|
|
80
|
+
private extractRequiredSkillNames;
|
|
76
81
|
private getMaxIncludedSkills;
|
|
77
82
|
private loadSkillsInParallel;
|
|
78
83
|
private addIncludedAgentToResult;
|
|
@@ -12,9 +12,12 @@ const rule_filter_1 = require("./rule-filter");
|
|
|
12
12
|
const skill_content_utils_1 = require("../skill/skill-content.utils");
|
|
13
13
|
const agent_summary_utils_1 = require("../agent/agent-summary.utils");
|
|
14
14
|
const rules_content_utils_1 = require("../rules/rules-content.utils");
|
|
15
|
+
const permission_forecast_1 = require("./permission-forecast");
|
|
15
16
|
const keyword_core_1 = require("../shared/keyword-core");
|
|
16
17
|
const taskmaestro_detector_1 = require("./taskmaestro-detector");
|
|
17
18
|
const diff_analyzer_1 = require("./diff-analyzer");
|
|
19
|
+
const stack_matcher_1 = require("../agent/stack-matcher");
|
|
20
|
+
const planning_contract_1 = require("../mcp/handlers/planning-contract");
|
|
18
21
|
const BASE_CONFIG = (0, keyword_core_1.getDefaultModeConfig)();
|
|
19
22
|
const DEFAULT_CONFIG = {
|
|
20
23
|
modes: {
|
|
@@ -109,6 +112,7 @@ class KeywordService {
|
|
|
109
112
|
this.getMaxIncludedSkillsFn = options?.getMaxIncludedSkillsFn;
|
|
110
113
|
this.getClientTypeFn = options?.getClientTypeFn;
|
|
111
114
|
this.trackRuleUsageFn = options?.trackRuleUsageFn;
|
|
115
|
+
this.loadStacksFn = options?.loadStacksFn;
|
|
112
116
|
this.cacheTTL = process.env.NODE_ENV === 'production' ? 3600000 : 300000;
|
|
113
117
|
}
|
|
114
118
|
async parseMode(prompt, options) {
|
|
@@ -187,13 +191,16 @@ class KeywordService {
|
|
|
187
191
|
}
|
|
188
192
|
const resolvedAgent = await this.resolvePrimaryAgent(mode, originalPrompt, modeConfig.delegates_to, options?.context, recommendedActAgent, diffAnalysis ?? undefined);
|
|
189
193
|
await this.addAgentInfoToResult(result, resolvedAgent);
|
|
190
|
-
this.addParallelAgentsToResult(result, mode, config, originalPrompt);
|
|
194
|
+
await this.addParallelAgentsToResult(result, mode, config, originalPrompt);
|
|
191
195
|
await this.addActRecommendationToResult(result, mode, originalPrompt);
|
|
192
196
|
this.addActivationMessageToResult(result, resolvedAgent);
|
|
193
197
|
this.addDisplayInstructionToResult(result, mode);
|
|
194
198
|
await this.addAutoConfigToResult(result, mode);
|
|
195
199
|
this.addComplexityToResult(result, mode, originalPrompt);
|
|
196
200
|
await this.addIncludedSkillsToResult(result, originalPrompt, options);
|
|
201
|
+
if (mode === 'PLAN' || mode === 'AUTO') {
|
|
202
|
+
await this.enforceRequiredAgentSkills(result, options);
|
|
203
|
+
}
|
|
197
204
|
await this.addIncludedAgentToResult(result, mode, options);
|
|
198
205
|
const taskmaestroInstalled = (0, taskmaestro_detector_1.isTaskmaestroAvailable)();
|
|
199
206
|
result.availableStrategies = taskmaestroInstalled ? ['subagent', 'taskmaestro'] : ['subagent'];
|
|
@@ -202,6 +209,7 @@ class KeywordService {
|
|
|
202
209
|
'TaskMaestro skill not found at ~/.claude/skills/taskmaestro/SKILL.md. To enable tmux-based parallel specialist execution, install the taskmaestro skill.';
|
|
203
210
|
}
|
|
204
211
|
this.addReleaseChecklistIfNeeded(result, mode, originalPrompt);
|
|
212
|
+
result.permissionForecast = (0, permission_forecast_1.generatePermissionForecast)(mode, originalPrompt);
|
|
205
213
|
return result;
|
|
206
214
|
}
|
|
207
215
|
addReleaseChecklistIfNeeded(result, mode, originalPrompt) {
|
|
@@ -241,8 +249,8 @@ class KeywordService {
|
|
|
241
249
|
result.delegate_agent_info = delegateAgentInfo;
|
|
242
250
|
}
|
|
243
251
|
}
|
|
244
|
-
addParallelAgentsToResult(result, mode, config, originalPrompt) {
|
|
245
|
-
const recommendation = this.getParallelAgentsRecommendation(mode, config, originalPrompt);
|
|
252
|
+
async addParallelAgentsToResult(result, mode, config, originalPrompt) {
|
|
253
|
+
const recommendation = await this.getParallelAgentsRecommendation(mode, config, originalPrompt);
|
|
246
254
|
if (recommendation) {
|
|
247
255
|
result.parallelAgentsRecommendation = recommendation;
|
|
248
256
|
}
|
|
@@ -335,6 +343,58 @@ class KeywordService {
|
|
|
335
343
|
this.logger.warn(`Failed to auto-include skills: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
336
344
|
}
|
|
337
345
|
}
|
|
346
|
+
async enforceRequiredAgentSkills(result, options) {
|
|
347
|
+
if (!this.loadAgentInfoFn || !this.loadSkillContentFn || !result.delegates_to)
|
|
348
|
+
return;
|
|
349
|
+
try {
|
|
350
|
+
const agentData = await this.loadAgentInfoFn(result.delegates_to);
|
|
351
|
+
const requiredSkillNames = this.extractRequiredSkillNames(agentData);
|
|
352
|
+
if (requiredSkillNames.length === 0)
|
|
353
|
+
return;
|
|
354
|
+
const verbosity = options?.verbosity ?? 'standard';
|
|
355
|
+
if (!result.included_skills) {
|
|
356
|
+
result.included_skills = [];
|
|
357
|
+
}
|
|
358
|
+
for (const skillName of requiredSkillNames) {
|
|
359
|
+
const existingIndex = result.included_skills.findIndex(s => s.name === skillName);
|
|
360
|
+
const content = await this.loadSkillContentFn(skillName);
|
|
361
|
+
if (!content)
|
|
362
|
+
continue;
|
|
363
|
+
const enforcedSkill = {
|
|
364
|
+
name: content.name,
|
|
365
|
+
description: content.description,
|
|
366
|
+
content: verbosity === 'minimal' ? '' : content.content,
|
|
367
|
+
reason: 'Required by planning agent',
|
|
368
|
+
};
|
|
369
|
+
if (existingIndex >= 0) {
|
|
370
|
+
result.included_skills[existingIndex] = enforcedSkill;
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
result.included_skills.push(enforcedSkill);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
result.requiredSkillsEnforced = true;
|
|
377
|
+
result.requiredSkillNames = requiredSkillNames;
|
|
378
|
+
}
|
|
379
|
+
catch (error) {
|
|
380
|
+
this.logger.warn(`Failed to enforce required agent skills: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
extractRequiredSkillNames(agentData) {
|
|
384
|
+
if (!agentData || typeof agentData !== 'object')
|
|
385
|
+
return [];
|
|
386
|
+
const agent = agentData;
|
|
387
|
+
const skills = agent.skills;
|
|
388
|
+
if (!skills || typeof skills !== 'object')
|
|
389
|
+
return [];
|
|
390
|
+
const required = skills.required;
|
|
391
|
+
if (!Array.isArray(required))
|
|
392
|
+
return [];
|
|
393
|
+
return required
|
|
394
|
+
.filter((s) => typeof s === 'object' && s !== null)
|
|
395
|
+
.map(s => s.name)
|
|
396
|
+
.filter((n) => typeof n === 'string');
|
|
397
|
+
}
|
|
338
398
|
async getMaxIncludedSkills() {
|
|
339
399
|
if (!this.getMaxIncludedSkillsFn)
|
|
340
400
|
return keyword_types_1.DEFAULT_MAX_INCLUDED_SKILLS;
|
|
@@ -407,15 +467,34 @@ class KeywordService {
|
|
|
407
467
|
expertise: summary.expertise,
|
|
408
468
|
};
|
|
409
469
|
}
|
|
470
|
+
const planningContract = (0, planning_contract_1.resolvePlanningContract)(mode, result.delegates_to);
|
|
471
|
+
if (planningContract) {
|
|
472
|
+
result.included_agent.planningContract = [...planningContract];
|
|
473
|
+
}
|
|
410
474
|
this.logger.log(`Auto-included agent: ${agentPrompt.displayName} (verbosity: ${verbosity})`);
|
|
411
475
|
}
|
|
412
476
|
}
|
|
413
477
|
getPrimaryAgentTier(agentName) {
|
|
414
478
|
return keyword_types_1.ALL_PRIMARY_AGENTS.includes(agentName) ? 'primary' : 'specialist';
|
|
415
479
|
}
|
|
416
|
-
getParallelAgentsRecommendation(mode, config, prompt) {
|
|
480
|
+
async getParallelAgentsRecommendation(mode, config, prompt) {
|
|
417
481
|
const modeConfig = config.modes[mode];
|
|
418
|
-
const
|
|
482
|
+
const defaultSpecialists = modeConfig?.defaultSpecialists ?? [];
|
|
483
|
+
let stackResult = null;
|
|
484
|
+
let stackSpecialists;
|
|
485
|
+
if (prompt && this.loadStacksFn) {
|
|
486
|
+
try {
|
|
487
|
+
const stacks = await this.loadStacksFn();
|
|
488
|
+
stackResult = (0, stack_matcher_1.matchStack)(prompt, stacks);
|
|
489
|
+
if (stackResult) {
|
|
490
|
+
const matched = stacks.find(s => s.name === stackResult.stackName);
|
|
491
|
+
stackSpecialists = matched?.specialist_agents;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
catch {
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
const baseSpecialists = stackSpecialists?.length ? stackSpecialists : defaultSpecialists;
|
|
419
498
|
const contextSpecialists = prompt ? this.getContextAwareSpecialists(prompt) : [];
|
|
420
499
|
const allSpecialists = [...new Set([...baseSpecialists, ...contextSpecialists])];
|
|
421
500
|
if (allSpecialists.length === 0) {
|
|
@@ -432,10 +511,15 @@ class KeywordService {
|
|
|
432
511
|
else {
|
|
433
512
|
hint = `Use Task tool with subagent_type="general-purpose" and run_in_background=true for each specialist. Call prepare_parallel_agents MCP tool to get ready-to-use prompts.`;
|
|
434
513
|
}
|
|
435
|
-
|
|
514
|
+
const result = {
|
|
436
515
|
specialists: allSpecialists,
|
|
437
516
|
hint,
|
|
438
517
|
};
|
|
518
|
+
if (stackResult) {
|
|
519
|
+
result.suggestedStack = stackResult.stackName;
|
|
520
|
+
result.stackBased = true;
|
|
521
|
+
}
|
|
522
|
+
return result;
|
|
439
523
|
}
|
|
440
524
|
getContextAwareSpecialists(prompt) {
|
|
441
525
|
const specialists = [];
|
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
import type { DiffAnalysisResult } from './diff-analyzer';
|
|
2
2
|
import type { CouncilPreset } from '../agent/council-preset.types';
|
|
3
|
-
import type { CouncilSummary } from '../collaboration/council-summary.types';
|
|
4
3
|
import type { ExecutionPlan } from '../agent/execution-plan.types';
|
|
5
4
|
import type { TeamsCapabilityStatus } from '../agent/teams-capability.types';
|
|
6
5
|
export declare const KEYWORDS: readonly ["PLAN", "ACT", "EVAL", "AUTO"];
|
|
7
6
|
export type Mode = (typeof KEYWORDS)[number];
|
|
7
|
+
export type PermissionClass = 'read-only' | 'repo-write' | 'network' | 'destructive' | 'external';
|
|
8
|
+
export interface ApprovalBundle {
|
|
9
|
+
name: string;
|
|
10
|
+
actions: string[];
|
|
11
|
+
permissionClass: PermissionClass;
|
|
12
|
+
reason: string;
|
|
13
|
+
}
|
|
14
|
+
export interface PermissionForecast {
|
|
15
|
+
permissionClasses: PermissionClass[];
|
|
16
|
+
approvalBundles: ApprovalBundle[];
|
|
17
|
+
permissionSummary: string;
|
|
18
|
+
}
|
|
8
19
|
export declare const MODE_AGENTS: readonly ["plan-mode", "act-mode", "eval-mode", "auto-mode"];
|
|
9
20
|
export declare const PLAN_PRIMARY_AGENTS: readonly ["solution-architect", "technical-planner"];
|
|
10
21
|
export declare const ACT_PRIMARY_AGENTS: readonly ["tooling-engineer", "platform-engineer", "data-engineer", "data-scientist", "ai-ml-engineer", "mobile-developer", "frontend-developer", "backend-developer", "devops-engineer", "agent-architect", "test-engineer", "security-engineer", "systems-developer", "software-engineer"];
|
|
@@ -45,6 +56,8 @@ export interface ParallelAgentRecommendation {
|
|
|
45
56
|
specialists: string[];
|
|
46
57
|
hint: string;
|
|
47
58
|
dispatch?: DispatchStrength;
|
|
59
|
+
suggestedStack?: string;
|
|
60
|
+
stackBased?: boolean;
|
|
48
61
|
}
|
|
49
62
|
export interface IncludedSkill {
|
|
50
63
|
name: string;
|
|
@@ -56,6 +69,7 @@ export interface IncludedAgent {
|
|
|
56
69
|
name: string;
|
|
57
70
|
systemPrompt: string;
|
|
58
71
|
expertise: string[];
|
|
72
|
+
planningContract?: string[];
|
|
59
73
|
}
|
|
60
74
|
export type PrimaryAgentSource = 'explicit' | 'explicit_patterns' | 'config' | 'intent' | 'context' | 'default';
|
|
61
75
|
export interface PrimaryAgentResolutionResult {
|
|
@@ -123,9 +137,11 @@ export interface ParseModeResult {
|
|
|
123
137
|
visual?: VisualData;
|
|
124
138
|
diffAnalysis?: DiffAnalysisResult;
|
|
125
139
|
councilPreset?: CouncilPreset;
|
|
126
|
-
|
|
140
|
+
requiredSkillsEnforced?: boolean;
|
|
141
|
+
requiredSkillNames?: string[];
|
|
127
142
|
executionPlan?: ExecutionPlan;
|
|
128
143
|
teamsCapability?: TeamsCapabilityStatus;
|
|
144
|
+
permissionForecast?: PermissionForecast;
|
|
129
145
|
}
|
|
130
146
|
export interface DispatchReadyParams {
|
|
131
147
|
subagent_type: 'general-purpose';
|
|
@@ -165,6 +181,12 @@ export interface VisualData {
|
|
|
165
181
|
collaboration: CollaborationConfig;
|
|
166
182
|
}
|
|
167
183
|
export type { DiffAnalysisResult, DiffAgentScore } from './diff-analyzer';
|
|
184
|
+
export interface ReviewContext {
|
|
185
|
+
detected: boolean;
|
|
186
|
+
pr_number: number;
|
|
187
|
+
issue_number?: number;
|
|
188
|
+
hint: string;
|
|
189
|
+
}
|
|
168
190
|
export interface ModeConfig {
|
|
169
191
|
description: string;
|
|
170
192
|
instructions: string;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generatePermissionForecast = generatePermissionForecast;
|
|
4
|
+
const SHIP_PATTERNS = /\b(ship|deploy|push|pr\b|pull\s*request|merge|release)\b/i;
|
|
5
|
+
const TEST_PATTERNS = /\b(tests?|lint|typecheck|format|check|verify|coverage)\b/i;
|
|
6
|
+
const INSTALL_PATTERNS = /\b(install|add\s+package|add\s+dependency|yarn\s+add|npm\s+install)\b/i;
|
|
7
|
+
const DELETE_PATTERNS = /\b(delete|remove|drop|reset|clean|destroy)\b/i;
|
|
8
|
+
const REVIEW_PATTERNS = /\b(review|comment|approve|feedback|pr\b|pull\s*request)\b/i;
|
|
9
|
+
const SHIP_BUNDLE = {
|
|
10
|
+
name: 'Ship changes',
|
|
11
|
+
actions: ['git add', 'git commit', 'git push', 'gh pr create'],
|
|
12
|
+
permissionClass: 'external',
|
|
13
|
+
reason: 'Committing, pushing, and creating a PR requires repo-write and GitHub API access',
|
|
14
|
+
};
|
|
15
|
+
const TEST_BUNDLE = {
|
|
16
|
+
name: 'Run checks',
|
|
17
|
+
actions: ['yarn test', 'yarn lint', 'yarn typecheck'],
|
|
18
|
+
permissionClass: 'read-only',
|
|
19
|
+
reason: 'Running tests and linters reads the codebase but does not modify it',
|
|
20
|
+
};
|
|
21
|
+
const INSTALL_BUNDLE = {
|
|
22
|
+
name: 'Install dependencies',
|
|
23
|
+
actions: ['yarn install', 'yarn add'],
|
|
24
|
+
permissionClass: 'network',
|
|
25
|
+
reason: 'Package installation fetches from external registries',
|
|
26
|
+
};
|
|
27
|
+
const REVIEW_BUNDLE = {
|
|
28
|
+
name: 'Review PR',
|
|
29
|
+
actions: ['gh pr review', 'gh pr comment'],
|
|
30
|
+
permissionClass: 'external',
|
|
31
|
+
reason: 'Reviewing or commenting on a PR uses the GitHub API',
|
|
32
|
+
};
|
|
33
|
+
const MODE_BASE_CLASSES = {
|
|
34
|
+
PLAN: ['read-only'],
|
|
35
|
+
ACT: ['read-only', 'repo-write'],
|
|
36
|
+
EVAL: ['read-only'],
|
|
37
|
+
AUTO: ['read-only', 'repo-write', 'external'],
|
|
38
|
+
};
|
|
39
|
+
function generatePermissionForecast(mode, prompt) {
|
|
40
|
+
const classes = new Set(MODE_BASE_CLASSES[mode]);
|
|
41
|
+
const bundles = [];
|
|
42
|
+
if (SHIP_PATTERNS.test(prompt)) {
|
|
43
|
+
classes.add('repo-write');
|
|
44
|
+
classes.add('external');
|
|
45
|
+
bundles.push(SHIP_BUNDLE);
|
|
46
|
+
}
|
|
47
|
+
if (TEST_PATTERNS.test(prompt)) {
|
|
48
|
+
bundles.push(TEST_BUNDLE);
|
|
49
|
+
}
|
|
50
|
+
if (INSTALL_PATTERNS.test(prompt)) {
|
|
51
|
+
classes.add('network');
|
|
52
|
+
bundles.push(INSTALL_BUNDLE);
|
|
53
|
+
}
|
|
54
|
+
if (DELETE_PATTERNS.test(prompt)) {
|
|
55
|
+
classes.add('destructive');
|
|
56
|
+
}
|
|
57
|
+
if (REVIEW_PATTERNS.test(prompt) && mode === 'EVAL') {
|
|
58
|
+
classes.add('external');
|
|
59
|
+
bundles.push(REVIEW_BUNDLE);
|
|
60
|
+
}
|
|
61
|
+
if (mode === 'ACT' && bundles.length === 0) {
|
|
62
|
+
bundles.push({
|
|
63
|
+
name: 'Code changes',
|
|
64
|
+
actions: ['file edit', 'git add', 'git commit'],
|
|
65
|
+
permissionClass: 'repo-write',
|
|
66
|
+
reason: 'Implementation involves editing files and creating commits',
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const permissionClasses = sortPermissionClasses([...classes]);
|
|
70
|
+
return {
|
|
71
|
+
permissionClasses,
|
|
72
|
+
approvalBundles: bundles,
|
|
73
|
+
permissionSummary: buildSummary(mode, permissionClasses, bundles),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const CLASS_ORDER = [
|
|
77
|
+
'read-only',
|
|
78
|
+
'repo-write',
|
|
79
|
+
'network',
|
|
80
|
+
'destructive',
|
|
81
|
+
'external',
|
|
82
|
+
];
|
|
83
|
+
function sortPermissionClasses(classes) {
|
|
84
|
+
return [...classes].sort((a, b) => CLASS_ORDER.indexOf(a) - CLASS_ORDER.indexOf(b));
|
|
85
|
+
}
|
|
86
|
+
function buildSummary(mode, classes, bundles) {
|
|
87
|
+
const highest = classes[classes.length - 1];
|
|
88
|
+
const bundleNames = bundles.map(b => b.name).join(', ');
|
|
89
|
+
if (bundles.length === 0) {
|
|
90
|
+
return `${mode} mode requires ${highest} permissions`;
|
|
91
|
+
}
|
|
92
|
+
return `${mode} mode requires ${highest} permissions — expected actions: ${bundleNames}`;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=permission-forecast.js.map
|
|
@@ -160,7 +160,7 @@ let AgentHandler = class AgentHandler extends abstract_handler_1.AbstractHandler
|
|
|
160
160
|
},
|
|
161
161
|
agentStack: {
|
|
162
162
|
type: 'string',
|
|
163
|
-
description: 'Agent stack name to resolve primary + specialists from a preset (e.g., "api-development"). Overrides primaryAgent and specialists when provided.',
|
|
163
|
+
description: 'Agent stack name to resolve primary + specialists from a preset (e.g., "api-development"). Overrides primaryAgent and specialists when provided. Tip: use the suggestedStack value from parse_mode response to auto-select the best stack for the current context.',
|
|
164
164
|
},
|
|
165
165
|
inlineAgents: {
|
|
166
166
|
type: 'object',
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare const DEFAULT_QUESTION_BUDGET = 3;
|
|
2
|
+
export declare const MIN_PROMPT_LENGTH = 20;
|
|
3
|
+
export interface ClarificationOptions {
|
|
4
|
+
questionBudget?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface ClarificationMetadata {
|
|
7
|
+
clarificationNeeded: boolean;
|
|
8
|
+
planReady: boolean;
|
|
9
|
+
questionBudget?: number;
|
|
10
|
+
nextQuestion?: string;
|
|
11
|
+
clarificationTopics?: string[];
|
|
12
|
+
assumptionNote?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function hasOverridePhrase(prompt: string): boolean;
|
|
15
|
+
export declare function hasVagueIntent(prompt: string): boolean;
|
|
16
|
+
export declare function hasTechnicalReference(prompt: string): boolean;
|
|
17
|
+
export declare const CLARIFICATION_TOPICS: {
|
|
18
|
+
readonly VAGUE_INTENT: "vague-intent";
|
|
19
|
+
readonly TARGET_ARTIFACT: "target-artifact";
|
|
20
|
+
readonly REQUEST_SCOPE: "request-scope";
|
|
21
|
+
};
|
|
22
|
+
export declare function evaluateClarification(prompt: string, options?: ClarificationOptions): ClarificationMetadata;
|