@haoyiyin/workflow 0.2.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/README.md +168 -0
- package/SETUP.md +71 -0
- package/SKILL.md +68 -0
- package/USAGE.md +152 -0
- package/dist/bin/yi-workflow.d.ts +3 -0
- package/dist/bin/yi-workflow.d.ts.map +1 -0
- package/dist/bin/yi-workflow.js +39 -0
- package/dist/bin/yi-workflow.js.map +1 -0
- package/dist/src/agents/contracts.d.ts +120 -0
- package/dist/src/agents/contracts.d.ts.map +1 -0
- package/dist/src/agents/contracts.js +431 -0
- package/dist/src/agents/contracts.js.map +1 -0
- package/dist/src/agents/dispatcher-enhanced.d.ts +68 -0
- package/dist/src/agents/dispatcher-enhanced.d.ts.map +1 -0
- package/dist/src/agents/dispatcher-enhanced.js +290 -0
- package/dist/src/agents/dispatcher-enhanced.js.map +1 -0
- package/dist/src/agents/dispatcher.d.ts +107 -0
- package/dist/src/agents/dispatcher.d.ts.map +1 -0
- package/dist/src/agents/dispatcher.js +454 -0
- package/dist/src/agents/dispatcher.js.map +1 -0
- package/dist/src/agents/index.d.ts +11 -0
- package/dist/src/agents/index.d.ts.map +1 -0
- package/dist/src/agents/index.js +10 -0
- package/dist/src/agents/index.js.map +1 -0
- package/dist/src/agents/resilience.d.ts +86 -0
- package/dist/src/agents/resilience.d.ts.map +1 -0
- package/dist/src/agents/resilience.js +183 -0
- package/dist/src/agents/resilience.js.map +1 -0
- package/dist/src/agents/token-budget.d.ts +47 -0
- package/dist/src/agents/token-budget.d.ts.map +1 -0
- package/dist/src/agents/token-budget.js +63 -0
- package/dist/src/agents/token-budget.js.map +1 -0
- package/dist/src/agents/types.d.ts +59 -0
- package/dist/src/agents/types.d.ts.map +1 -0
- package/dist/src/agents/types.js +5 -0
- package/dist/src/agents/types.js.map +1 -0
- package/dist/src/guard/main-agent.d.ts +72 -0
- package/dist/src/guard/main-agent.d.ts.map +1 -0
- package/dist/src/guard/main-agent.js +184 -0
- package/dist/src/guard/main-agent.js.map +1 -0
- package/dist/src/hooks/builtin/index.d.ts +9 -0
- package/dist/src/hooks/builtin/index.d.ts.map +1 -0
- package/dist/src/hooks/builtin/index.js +9 -0
- package/dist/src/hooks/builtin/index.js.map +1 -0
- package/dist/src/hooks/builtin/on-error.d.ts +7 -0
- package/dist/src/hooks/builtin/on-error.d.ts.map +1 -0
- package/dist/src/hooks/builtin/on-error.js +15 -0
- package/dist/src/hooks/builtin/on-error.js.map +1 -0
- package/dist/src/hooks/builtin/post-execute.d.ts +7 -0
- package/dist/src/hooks/builtin/post-execute.d.ts.map +1 -0
- package/dist/src/hooks/builtin/post-execute.js +30 -0
- package/dist/src/hooks/builtin/post-execute.js.map +1 -0
- package/dist/src/hooks/builtin/post-plan.d.ts +7 -0
- package/dist/src/hooks/builtin/post-plan.d.ts.map +1 -0
- package/dist/src/hooks/builtin/post-plan.js +15 -0
- package/dist/src/hooks/builtin/post-plan.js.map +1 -0
- package/dist/src/hooks/builtin/pre-execute.d.ts +7 -0
- package/dist/src/hooks/builtin/pre-execute.d.ts.map +1 -0
- package/dist/src/hooks/builtin/pre-execute.js +22 -0
- package/dist/src/hooks/builtin/pre-execute.js.map +1 -0
- package/dist/src/hooks/builtin/pre-plan.d.ts +7 -0
- package/dist/src/hooks/builtin/pre-plan.d.ts.map +1 -0
- package/dist/src/hooks/builtin/pre-plan.js +19 -0
- package/dist/src/hooks/builtin/pre-plan.js.map +1 -0
- package/dist/src/hooks/index.d.ts +8 -0
- package/dist/src/hooks/index.d.ts.map +1 -0
- package/dist/src/hooks/index.js +4 -0
- package/dist/src/hooks/index.js.map +1 -0
- package/dist/src/hooks/loader.d.ts +16 -0
- package/dist/src/hooks/loader.d.ts.map +1 -0
- package/dist/src/hooks/loader.js +77 -0
- package/dist/src/hooks/loader.js.map +1 -0
- package/dist/src/hooks/manager.d.ts +20 -0
- package/dist/src/hooks/manager.d.ts.map +1 -0
- package/dist/src/hooks/manager.js +76 -0
- package/dist/src/hooks/manager.js.map +1 -0
- package/dist/src/hooks/types-enhanced.d.ts +30 -0
- package/dist/src/hooks/types-enhanced.d.ts.map +1 -0
- package/dist/src/hooks/types-enhanced.js +22 -0
- package/dist/src/hooks/types-enhanced.js.map +1 -0
- package/dist/src/hooks/types.d.ts +27 -0
- package/dist/src/hooks/types.d.ts.map +1 -0
- package/dist/src/hooks/types.js +2 -0
- package/dist/src/hooks/types.js.map +1 -0
- package/dist/src/index.d.ts +43 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +41 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/persistence/index.d.ts +7 -0
- package/dist/src/persistence/index.d.ts.map +1 -0
- package/dist/src/persistence/index.js +6 -0
- package/dist/src/persistence/index.js.map +1 -0
- package/dist/src/persistence/plan-md.d.ts +11 -0
- package/dist/src/persistence/plan-md.d.ts.map +1 -0
- package/dist/src/persistence/plan-md.js +125 -0
- package/dist/src/persistence/plan-md.js.map +1 -0
- package/dist/src/persistence/state-md.d.ts +17 -0
- package/dist/src/persistence/state-md.d.ts.map +1 -0
- package/dist/src/persistence/state-md.js +143 -0
- package/dist/src/persistence/state-md.js.map +1 -0
- package/dist/src/persistence/types.d.ts +85 -0
- package/dist/src/persistence/types.d.ts.map +1 -0
- package/dist/src/persistence/types.js +5 -0
- package/dist/src/persistence/types.js.map +1 -0
- package/dist/src/router/classifier.d.ts +108 -0
- package/dist/src/router/classifier.d.ts.map +1 -0
- package/dist/src/router/classifier.js +476 -0
- package/dist/src/router/classifier.js.map +1 -0
- package/dist/src/router/guard.d.ts +128 -0
- package/dist/src/router/guard.d.ts.map +1 -0
- package/dist/src/router/guard.js +370 -0
- package/dist/src/router/guard.js.map +1 -0
- package/dist/src/router/index.d.ts +10 -0
- package/dist/src/router/index.d.ts.map +1 -0
- package/dist/src/router/index.js +8 -0
- package/dist/src/router/index.js.map +1 -0
- package/dist/src/router/router.d.ts +58 -0
- package/dist/src/router/router.d.ts.map +1 -0
- package/dist/src/router/router.js +78 -0
- package/dist/src/router/router.js.map +1 -0
- package/dist/src/router/types.d.ts +100 -0
- package/dist/src/router/types.d.ts.map +1 -0
- package/dist/src/router/types.js +24 -0
- package/dist/src/router/types.js.map +1 -0
- package/dist/src/skills/agents-md/index.d.ts +9 -0
- package/dist/src/skills/agents-md/index.d.ts.map +1 -0
- package/dist/src/skills/agents-md/index.js +28 -0
- package/dist/src/skills/agents-md/index.js.map +1 -0
- package/dist/src/skills/execute-plan/index.d.ts +141 -0
- package/dist/src/skills/execute-plan/index.d.ts.map +1 -0
- package/dist/src/skills/execute-plan/index.js +784 -0
- package/dist/src/skills/execute-plan/index.js.map +1 -0
- package/dist/src/skills/index.d.ts +14 -0
- package/dist/src/skills/index.d.ts.map +1 -0
- package/dist/src/skills/index.js +10 -0
- package/dist/src/skills/index.js.map +1 -0
- package/dist/src/skills/quick-task/index.d.ts +75 -0
- package/dist/src/skills/quick-task/index.d.ts.map +1 -0
- package/dist/src/skills/quick-task/index.js +284 -0
- package/dist/src/skills/quick-task/index.js.map +1 -0
- package/dist/src/skills/registry.d.ts +15 -0
- package/dist/src/skills/registry.d.ts.map +1 -0
- package/dist/src/skills/registry.js +44 -0
- package/dist/src/skills/registry.js.map +1 -0
- package/dist/src/skills/review-diff/index.d.ts +96 -0
- package/dist/src/skills/review-diff/index.d.ts.map +1 -0
- package/dist/src/skills/review-diff/index.js +316 -0
- package/dist/src/skills/review-diff/index.js.map +1 -0
- package/dist/src/skills/skill.d.ts +24 -0
- package/dist/src/skills/skill.d.ts.map +1 -0
- package/dist/src/skills/skill.js +39 -0
- package/dist/src/skills/skill.js.map +1 -0
- package/dist/src/skills/systematic-debugging/index.d.ts +90 -0
- package/dist/src/skills/systematic-debugging/index.d.ts.map +1 -0
- package/dist/src/skills/systematic-debugging/index.js +305 -0
- package/dist/src/skills/systematic-debugging/index.js.map +1 -0
- package/dist/src/skills/tdd/index.d.ts +103 -0
- package/dist/src/skills/tdd/index.d.ts.map +1 -0
- package/dist/src/skills/tdd/index.js +338 -0
- package/dist/src/skills/tdd/index.js.map +1 -0
- package/dist/src/skills/to-plan/index-enhanced.d.ts +100 -0
- package/dist/src/skills/to-plan/index-enhanced.d.ts.map +1 -0
- package/dist/src/skills/to-plan/index-enhanced.js +452 -0
- package/dist/src/skills/to-plan/index-enhanced.js.map +1 -0
- package/dist/src/skills/to-plan/index.d.ts +131 -0
- package/dist/src/skills/to-plan/index.d.ts.map +1 -0
- package/dist/src/skills/to-plan/index.js +460 -0
- package/dist/src/skills/to-plan/index.js.map +1 -0
- package/dist/src/skills/types.d.ts +44 -0
- package/dist/src/skills/types.d.ts.map +1 -0
- package/dist/src/skills/types.js +2 -0
- package/dist/src/skills/types.js.map +1 -0
- package/dist/src/state/cleanup.d.ts +22 -0
- package/dist/src/state/cleanup.d.ts.map +1 -0
- package/dist/src/state/cleanup.js +87 -0
- package/dist/src/state/cleanup.js.map +1 -0
- package/dist/src/state/index.d.ts +9 -0
- package/dist/src/state/index.d.ts.map +1 -0
- package/dist/src/state/index.js +5 -0
- package/dist/src/state/index.js.map +1 -0
- package/dist/src/state/manager.d.ts +15 -0
- package/dist/src/state/manager.d.ts.map +1 -0
- package/dist/src/state/manager.js +73 -0
- package/dist/src/state/manager.js.map +1 -0
- package/dist/src/state/persistence.d.ts +13 -0
- package/dist/src/state/persistence.d.ts.map +1 -0
- package/dist/src/state/persistence.js +68 -0
- package/dist/src/state/persistence.js.map +1 -0
- package/dist/src/state/types.d.ts +26 -0
- package/dist/src/state/types.d.ts.map +1 -0
- package/dist/src/state/types.js +2 -0
- package/dist/src/state/types.js.map +1 -0
- package/dist/src/state/validator.d.ts +12 -0
- package/dist/src/state/validator.d.ts.map +1 -0
- package/dist/src/state/validator.js +56 -0
- package/dist/src/state/validator.js.map +1 -0
- package/dist/src/types.d.ts +83 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +5 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/compress.d.ts +37 -0
- package/dist/src/utils/compress.d.ts.map +1 -0
- package/dist/src/utils/compress.js +298 -0
- package/dist/src/utils/compress.js.map +1 -0
- package/dist/src/utils/git.d.ts +9 -0
- package/dist/src/utils/git.d.ts.map +1 -0
- package/dist/src/utils/git.js +81 -0
- package/dist/src/utils/git.js.map +1 -0
- package/dist/src/utils/index.d.ts +7 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/index.js +7 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/logger.d.ts +6 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/logger.js +19 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/dist/src/utils/paths.d.ts +12 -0
- package/dist/src/utils/paths.d.ts.map +1 -0
- package/dist/src/utils/paths.js +44 -0
- package/dist/src/utils/paths.js.map +1 -0
- package/package.json +76 -0
- package/scripts/postinstall.js +69 -0
- package/yi-workflow.js +17 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main Agent Guard - enforces that the main agent NEVER does substantive work.
|
|
3
|
+
*
|
|
4
|
+
* The guard is the enforcement mechanism for the "thin dispatcher" pattern.
|
|
5
|
+
* When embargo is active, the main agent is blocked from everything except
|
|
6
|
+
* meta-operations (reading plan files, state files, and dispatching subagents).
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const guard = MainAgentGuard.create({
|
|
11
|
+
* defaultModel: 'haiku',
|
|
12
|
+
* planningThreshold: 0.6,
|
|
13
|
+
* maxMainAgentTokens: 10000,
|
|
14
|
+
* autoRoute: true,
|
|
15
|
+
* })
|
|
16
|
+
*
|
|
17
|
+
* const check = guard.checkOperation('read-source', { path: 'src/main.ts' })
|
|
18
|
+
* if (!check.allowed) {
|
|
19
|
+
* throw new Error(check.reason)
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import { MAIN_AGENT_PROHIBITED } from './types.js';
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Helpers
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
const META_OPERATIONS = new Set([
|
|
28
|
+
'dispatch-subagent',
|
|
29
|
+
'relay-results',
|
|
30
|
+
'read-meta-file',
|
|
31
|
+
'read-plan',
|
|
32
|
+
'read-state',
|
|
33
|
+
'list-plans',
|
|
34
|
+
'check-state',
|
|
35
|
+
'read-config',
|
|
36
|
+
]);
|
|
37
|
+
const ALWAYS_ALLOWED_PATHS = [
|
|
38
|
+
'.pi/plans/**',
|
|
39
|
+
'.pi/yi-workflow/state/**',
|
|
40
|
+
'SKILL.md',
|
|
41
|
+
'AGENTS.md',
|
|
42
|
+
'CLAUDE.md',
|
|
43
|
+
'package.json',
|
|
44
|
+
'.claude/**',
|
|
45
|
+
];
|
|
46
|
+
const ALWAYS_FORBIDDEN_PATHS = [
|
|
47
|
+
'src/**',
|
|
48
|
+
'lib/**',
|
|
49
|
+
'app/**',
|
|
50
|
+
'dist/**',
|
|
51
|
+
'node_modules/**',
|
|
52
|
+
'**/*.test.ts',
|
|
53
|
+
'**/*.spec.ts',
|
|
54
|
+
'**/*.test.tsx',
|
|
55
|
+
'**/*.spec.tsx',
|
|
56
|
+
];
|
|
57
|
+
/**
|
|
58
|
+
* Parses a simple glob pattern into a regex for matching.
|
|
59
|
+
* Supports ** for recursive matching and * for single-segment.
|
|
60
|
+
*/
|
|
61
|
+
function globToRegex(pattern) {
|
|
62
|
+
const escaped = pattern
|
|
63
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
64
|
+
.replace(/\*\*/g, '___DOUBLESTAR___')
|
|
65
|
+
.replace(/\*/g, '[^/]*')
|
|
66
|
+
.replace(/___DOUBLESTAR___/g, '.*');
|
|
67
|
+
return new RegExp(`^${escaped}$`);
|
|
68
|
+
}
|
|
69
|
+
/** Check whether a path matches any of the given glob patterns. */
|
|
70
|
+
function matchesAnyGlob(filePath, patterns) {
|
|
71
|
+
const normalized = filePath.replace(/^\.\//, '');
|
|
72
|
+
for (const pattern of patterns) {
|
|
73
|
+
const regex = globToRegex(pattern);
|
|
74
|
+
if (regex.test(normalized)) {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// MainAgentGuard
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
/**
|
|
84
|
+
* Enforces the "main agent as thin dispatcher" constraint.
|
|
85
|
+
*
|
|
86
|
+
* When embargoActive is true, the main agent is FORBIDDEN from doing
|
|
87
|
+
* ANY substantive work. It can only read meta-files and dispatch subagents.
|
|
88
|
+
*/
|
|
89
|
+
export class MainAgentGuard {
|
|
90
|
+
config;
|
|
91
|
+
violations;
|
|
92
|
+
pendingSubagents;
|
|
93
|
+
embargoActive;
|
|
94
|
+
tokensUsed;
|
|
95
|
+
constructor(config) {
|
|
96
|
+
this.config = Object.freeze({ ...config });
|
|
97
|
+
this.violations = [];
|
|
98
|
+
this.pendingSubagents = new Set();
|
|
99
|
+
this.embargoActive = false;
|
|
100
|
+
this.tokensUsed = 0;
|
|
101
|
+
}
|
|
102
|
+
// -----------------------------------------------------------------------
|
|
103
|
+
// Factory methods
|
|
104
|
+
// -----------------------------------------------------------------------
|
|
105
|
+
/** Create a guard with embargo active (strictest mode). */
|
|
106
|
+
static createEmbargoAll(config) {
|
|
107
|
+
const guard = new MainAgentGuard(config);
|
|
108
|
+
guard.activateEmbargo();
|
|
109
|
+
return guard;
|
|
110
|
+
}
|
|
111
|
+
/** Create a guard with embargo lifted (use with extreme caution). */
|
|
112
|
+
static createDisabled(config) {
|
|
113
|
+
return new MainAgentGuard(config);
|
|
114
|
+
}
|
|
115
|
+
/** Convenience: create with default config. */
|
|
116
|
+
static create(config) {
|
|
117
|
+
return new MainAgentGuard(config);
|
|
118
|
+
}
|
|
119
|
+
// -----------------------------------------------------------------------
|
|
120
|
+
// Operation checks
|
|
121
|
+
// -----------------------------------------------------------------------
|
|
122
|
+
/**
|
|
123
|
+
* Check whether an operation is permitted for the main agent.
|
|
124
|
+
*
|
|
125
|
+
* @param operation - The operation being attempted
|
|
126
|
+
* @returns GuardCheckResult with allowed flag and reason
|
|
127
|
+
*/
|
|
128
|
+
checkOperation(operation) {
|
|
129
|
+
// If embargo is inactive, everything is permitted
|
|
130
|
+
if (!this.embargoActive) {
|
|
131
|
+
return {
|
|
132
|
+
allowed: true,
|
|
133
|
+
reason: 'Embargo is inactive - main agent may operate',
|
|
134
|
+
rule: 'embargo-off',
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
// Meta-operations are always allowed (they ARE the main agent's job)
|
|
138
|
+
if (META_OPERATIONS.has(operation)) {
|
|
139
|
+
return {
|
|
140
|
+
allowed: true,
|
|
141
|
+
reason: 'Meta-operation permitted for orchestration',
|
|
142
|
+
rule: 'meta-operation',
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
// Check against prohibited operations
|
|
146
|
+
const prohibitionMap = {
|
|
147
|
+
'read-source': MAIN_AGENT_PROHIBITED.readSourceFiles,
|
|
148
|
+
'search-codebase': MAIN_AGENT_PROHIBITED.searchCodebase,
|
|
149
|
+
'write-files': MAIN_AGENT_PROHIBITED.writeFiles,
|
|
150
|
+
'edit-files': MAIN_AGENT_PROHIBITED.writeFiles,
|
|
151
|
+
'run-build': MAIN_AGENT_PROHIBITED.runBuildCommands,
|
|
152
|
+
'run-tests': MAIN_AGENT_PROHIBITED.runTests,
|
|
153
|
+
'git-commit': MAIN_AGENT_PROHIBITED.writeFiles,
|
|
154
|
+
'git-push': MAIN_AGENT_PROHIBITED.writeFiles,
|
|
155
|
+
'read-diffs': MAIN_AGENT_PROHIBITED.readSourceFiles,
|
|
156
|
+
'long-running-task': MAIN_AGENT_PROHIBITED.longRunningTasks,
|
|
157
|
+
};
|
|
158
|
+
if (prohibitionMap[operation]) {
|
|
159
|
+
return {
|
|
160
|
+
allowed: false,
|
|
161
|
+
reason: `Operation "${operation}" is prohibited for the main agent`,
|
|
162
|
+
rule: 'prohibited-operation',
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
// Unknown operations under embargo: deny by default
|
|
166
|
+
return {
|
|
167
|
+
allowed: false,
|
|
168
|
+
reason: `Operation "${operation}" is not recognized and embargo is active`,
|
|
169
|
+
rule: 'unknown-operation-deny',
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Check whether a file path is permitted to be read by the main agent.
|
|
174
|
+
*/
|
|
175
|
+
checkReadPath(filePath) {
|
|
176
|
+
if (!this.embargoActive) {
|
|
177
|
+
return { allowed: true, reason: 'Embargo is inactive', rule: 'embargo-off' };
|
|
178
|
+
}
|
|
179
|
+
const normalized = filePath.replace(/^\.\//, '');
|
|
180
|
+
// Explicitly forbidden paths take precedence
|
|
181
|
+
if (matchesAnyGlob(normalized, ALWAYS_FORBIDDEN_PATHS)) {
|
|
182
|
+
return {
|
|
183
|
+
allowed: false,
|
|
184
|
+
reason: `Path "${filePath}" is forbidden under embargo`,
|
|
185
|
+
rule: 'forbidden-path',
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
// Check if path is in the allowed list
|
|
189
|
+
if (matchesAnyGlob(normalized, ALWAYS_ALLOWED_PATHS)) {
|
|
190
|
+
return { allowed: true, reason: 'Path is in the allowed list', rule: 'allowed-path' };
|
|
191
|
+
}
|
|
192
|
+
// Default: deny
|
|
193
|
+
return {
|
|
194
|
+
allowed: false,
|
|
195
|
+
reason: `Path "${filePath}" is not in the allowed list and embargo is active`,
|
|
196
|
+
rule: 'default-deny-path',
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Comprehensive check combining operation and optional file path/context.
|
|
201
|
+
*/
|
|
202
|
+
check(context) {
|
|
203
|
+
// Check the operation
|
|
204
|
+
const opCheck = this.checkOperation(context.operation);
|
|
205
|
+
if (!opCheck.allowed) {
|
|
206
|
+
return opCheck;
|
|
207
|
+
}
|
|
208
|
+
// If a path is provided, check read access
|
|
209
|
+
if (context.path) {
|
|
210
|
+
const pathCheck = this.checkReadPath(context.path);
|
|
211
|
+
if (!pathCheck.allowed) {
|
|
212
|
+
return pathCheck;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Check token budget
|
|
216
|
+
if (this.tokensUsed > this.config.maxMainAgentTokens) {
|
|
217
|
+
return {
|
|
218
|
+
allowed: false,
|
|
219
|
+
reason: `Token budget exceeded: ${this.tokensUsed}/${this.config.maxMainAgentTokens}`,
|
|
220
|
+
rule: 'token-budget-exceeded',
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
return { allowed: true, reason: 'All checks passed' };
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Assert an operation is allowed. Throws if violated.
|
|
227
|
+
*/
|
|
228
|
+
assertAllowed(context) {
|
|
229
|
+
const result = this.check(context);
|
|
230
|
+
if (!result.allowed) {
|
|
231
|
+
const error = new Error(`GUARD VIOLATION: ${result.reason}\n` +
|
|
232
|
+
`Operation: ${context.operation}\n` +
|
|
233
|
+
`${context.path ? `Path: ${context.path}\n` : ''}` +
|
|
234
|
+
`Rule: ${result.rule}`);
|
|
235
|
+
this.violations.push({
|
|
236
|
+
operation: context.operation,
|
|
237
|
+
path: context.path,
|
|
238
|
+
timestamp: new Date(),
|
|
239
|
+
reason: result.reason,
|
|
240
|
+
});
|
|
241
|
+
throw error;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Record a violation without throwing (for audit trail).
|
|
246
|
+
*/
|
|
247
|
+
recordViolation(context) {
|
|
248
|
+
const result = this.check(context);
|
|
249
|
+
this.violations.push({
|
|
250
|
+
operation: context.operation,
|
|
251
|
+
path: context.path,
|
|
252
|
+
timestamp: new Date(),
|
|
253
|
+
reason: result.reason,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
// -----------------------------------------------------------------------
|
|
257
|
+
// Embargo control
|
|
258
|
+
// -----------------------------------------------------------------------
|
|
259
|
+
/** Activate embargo mode - main agent must delegate everything. */
|
|
260
|
+
activateEmbargo() {
|
|
261
|
+
this.embargoActive = true;
|
|
262
|
+
}
|
|
263
|
+
/** Deactivate embargo mode - main agent regains limited capabilities. */
|
|
264
|
+
deactivateEmbargo() {
|
|
265
|
+
this.embargoActive = false;
|
|
266
|
+
}
|
|
267
|
+
/** Check if embargo is currently active. */
|
|
268
|
+
isEmbargoActive() {
|
|
269
|
+
return this.embargoActive;
|
|
270
|
+
}
|
|
271
|
+
// -----------------------------------------------------------------------
|
|
272
|
+
// Subagent tracking
|
|
273
|
+
// -----------------------------------------------------------------------
|
|
274
|
+
/** Register a dispatched subagent. */
|
|
275
|
+
registerSubagent(id) {
|
|
276
|
+
this.pendingSubagents.add(id);
|
|
277
|
+
}
|
|
278
|
+
/** Mark a subagent as completed. */
|
|
279
|
+
completeSubagent(id) {
|
|
280
|
+
this.pendingSubagents.delete(id);
|
|
281
|
+
}
|
|
282
|
+
/** Check if there are any subagents still pending. */
|
|
283
|
+
hasPendingSubagents() {
|
|
284
|
+
return this.pendingSubagents.size > 0;
|
|
285
|
+
}
|
|
286
|
+
// -----------------------------------------------------------------------
|
|
287
|
+
// Token tracking
|
|
288
|
+
// -----------------------------------------------------------------------
|
|
289
|
+
/** Track token usage by the main agent. */
|
|
290
|
+
trackTokens(count) {
|
|
291
|
+
this.tokensUsed += count;
|
|
292
|
+
}
|
|
293
|
+
/** Get current token usage. */
|
|
294
|
+
getTokensUsed() {
|
|
295
|
+
return this.tokensUsed;
|
|
296
|
+
}
|
|
297
|
+
/** Percentage of token budget consumed (0-1). */
|
|
298
|
+
tokenBudgetUtilization() {
|
|
299
|
+
return this.tokensUsed / this.config.maxMainAgentTokens;
|
|
300
|
+
}
|
|
301
|
+
// -----------------------------------------------------------------------
|
|
302
|
+
// Status and reporting
|
|
303
|
+
// -----------------------------------------------------------------------
|
|
304
|
+
/** Current guard status snapshot. */
|
|
305
|
+
getStatus() {
|
|
306
|
+
return {
|
|
307
|
+
embargoActive: this.embargoActive,
|
|
308
|
+
pendingSubagents: [...this.pendingSubagents],
|
|
309
|
+
violations: [...this.violations],
|
|
310
|
+
prohibitedOperations: Object.entries(MAIN_AGENT_PROHIBITED)
|
|
311
|
+
.filter(([, prohibited]) => prohibited)
|
|
312
|
+
.map(([key]) => key),
|
|
313
|
+
allowedPaths: [...ALWAYS_ALLOWED_PATHS],
|
|
314
|
+
forbiddenPaths: [...ALWAYS_FORBIDDEN_PATHS],
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Generate the system prompt fragment that enforces guard rules.
|
|
319
|
+
* Injected into the main agent's system prompt.
|
|
320
|
+
*/
|
|
321
|
+
generateSystemPromptFragment() {
|
|
322
|
+
if (!this.embargoActive) {
|
|
323
|
+
return `
|
|
324
|
+
## Main Agent Guard: INACTIVE
|
|
325
|
+
|
|
326
|
+
The guard is currently disabled. You may operate normally,
|
|
327
|
+
but prefer delegation to subagents for substantive work where possible.
|
|
328
|
+
`;
|
|
329
|
+
}
|
|
330
|
+
const prohibited = Object.entries(MAIN_AGENT_PROHIBITED)
|
|
331
|
+
.filter(([, v]) => v)
|
|
332
|
+
.map(([k]) => `- ❌ ${k}`)
|
|
333
|
+
.join('\n');
|
|
334
|
+
const allowed = [...ALWAYS_ALLOWED_PATHS].map((p) => `- ${p}`).join('\n');
|
|
335
|
+
const pendingCount = this.pendingSubagents.size;
|
|
336
|
+
const tokenPct = Math.round(this.tokenBudgetUtilization() * 100);
|
|
337
|
+
return `
|
|
338
|
+
## CRITICAL: Main Agent Guard — EMBARGO ACTIVE
|
|
339
|
+
|
|
340
|
+
You are a **thin dispatcher**, NOT an executor. Your only job:
|
|
341
|
+
1. Classify the user's request
|
|
342
|
+
2. Dispatch subagents to do the actual work
|
|
343
|
+
3. Relay subagent results back to the user
|
|
344
|
+
|
|
345
|
+
### Prohibited (NEVER do these):
|
|
346
|
+
${prohibited}
|
|
347
|
+
|
|
348
|
+
### Allowed to read ONLY:
|
|
349
|
+
${allowed}
|
|
350
|
+
|
|
351
|
+
### Status:
|
|
352
|
+
- Token budget: ${tokenPct}% used (${this.tokensUsed}/${this.config.maxMainAgentTokens})
|
|
353
|
+
- Pending subagents: ${pendingCount}
|
|
354
|
+
- Violations recorded: ${this.violations.length}
|
|
355
|
+
|
|
356
|
+
### Routing rules:
|
|
357
|
+
- Trivial typo/whitespace → handle directly (1-2 char fix)
|
|
358
|
+
- Small scoped change → dispatch quick-task agent
|
|
359
|
+
- New feature / complex change → dispatch to-plan → then execute-plan
|
|
360
|
+
- Bug/debugging → dispatch systematic-debugging agent
|
|
361
|
+
- Code review → dispatch review-diff agent
|
|
362
|
+
- Research/exploration → dispatch explorer agent
|
|
363
|
+
- TDD work → dispatch tdd agent
|
|
364
|
+
- Everything else → dispatch general subagent
|
|
365
|
+
|
|
366
|
+
### NEVER execute any task yourself. ALWAYS use the Agent tool.
|
|
367
|
+
`;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
//# sourceMappingURL=guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../../../src/router/guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router module index
|
|
3
|
+
*
|
|
4
|
+
* The router ensures ALL user requests go through subagents.
|
|
5
|
+
* Main Agent is a "thin dispatcher" — it NEVER executes tasks itself.
|
|
6
|
+
*/
|
|
7
|
+
export type { IntentClassification, IntentType, RouterConfig, RoutingDecision, SubagentContract, PermissionSet, RouterInput, RouterOutput, MAIN_AGENT_PROHIBITED, ROUTE_KEYWORDS, } from './types.js';
|
|
8
|
+
export { createRouter } from './router.js';
|
|
9
|
+
export type { Router } from './router.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/router/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EACV,oBAAoB,EACpB,UAAU,EACV,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,YAAY,EACZ,qBAAqB,EACrB,cAAc,GACf,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/router/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAeH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router - wires up classification and guard into a single dispatch pipeline.
|
|
3
|
+
*
|
|
4
|
+
* The createRouter factory produces an object that:
|
|
5
|
+
* 1. Classifies user requests
|
|
6
|
+
* 2. Validates against main-agent guard rules
|
|
7
|
+
* 3. Produces a routing decision (what subagent to dispatch)
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { createRouter } from './router/router.js'
|
|
12
|
+
* import type { RouterConfig } from './router/types.js'
|
|
13
|
+
*
|
|
14
|
+
* const config: RouterConfig = {
|
|
15
|
+
* defaultModel: 'haiku',
|
|
16
|
+
* planningThreshold: 0.6,
|
|
17
|
+
* maxMainAgentTokens: 10000,
|
|
18
|
+
* autoRoute: true,
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* const router = createRouter(config)
|
|
22
|
+
* const output = router.route({
|
|
23
|
+
* request: "Fix the typo in src/utils.ts",
|
|
24
|
+
* planFileExists: false,
|
|
25
|
+
* isExecutingPlan: false,
|
|
26
|
+
* hasUncommittedChanges: true,
|
|
27
|
+
* mentionedFiles: ['src/utils.ts'],
|
|
28
|
+
* })
|
|
29
|
+
* // output.classification.type === 'quick-task'
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
import type { RouterConfig, RouterInput, RouterOutput } from './types.js';
|
|
33
|
+
import { RequestClassifier } from './classifier.js';
|
|
34
|
+
import { MainAgentGuard } from './guard.js';
|
|
35
|
+
/**
|
|
36
|
+
* High-level router interface.
|
|
37
|
+
*/
|
|
38
|
+
export interface Router {
|
|
39
|
+
/** Classify a request and produce a routing decision */
|
|
40
|
+
route: (input: RouterInput) => RouterOutput;
|
|
41
|
+
/** Get the underlying classifier */
|
|
42
|
+
classifier: RequestClassifier;
|
|
43
|
+
/** Get the underlying guard */
|
|
44
|
+
guard: MainAgentGuard;
|
|
45
|
+
/** Generate the system prompt fragment for the main agent */
|
|
46
|
+
generateSystemPrompt: () => string;
|
|
47
|
+
/** Check if an operation is allowed under current guard state */
|
|
48
|
+
isOperationAllowed: (operation: string) => boolean;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Create a router with the given configuration.
|
|
52
|
+
*
|
|
53
|
+
* Wires together:
|
|
54
|
+
* - RequestClassifier: analyzes user input, determines intent
|
|
55
|
+
* - MainAgentGuard: enforces thin-dispatcher constraints
|
|
56
|
+
*/
|
|
57
|
+
export declare function createRouter(config: RouterConfig): Router;
|
|
58
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../../src/router/router.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAEnD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE3C;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,wDAAwD;IACxD,KAAK,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,YAAY,CAAA;IAE3C,oCAAoC;IACpC,UAAU,EAAE,iBAAiB,CAAA;IAE7B,+BAA+B;IAC/B,KAAK,EAAE,cAAc,CAAA;IAErB,6DAA6D;IAC7D,oBAAoB,EAAE,MAAM,MAAM,CAAA;IAElC,iEAAiE;IACjE,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAA;CACnD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CA2CzD"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router - wires up classification and guard into a single dispatch pipeline.
|
|
3
|
+
*
|
|
4
|
+
* The createRouter factory produces an object that:
|
|
5
|
+
* 1. Classifies user requests
|
|
6
|
+
* 2. Validates against main-agent guard rules
|
|
7
|
+
* 3. Produces a routing decision (what subagent to dispatch)
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { createRouter } from './router/router.js'
|
|
12
|
+
* import type { RouterConfig } from './router/types.js'
|
|
13
|
+
*
|
|
14
|
+
* const config: RouterConfig = {
|
|
15
|
+
* defaultModel: 'haiku',
|
|
16
|
+
* planningThreshold: 0.6,
|
|
17
|
+
* maxMainAgentTokens: 10000,
|
|
18
|
+
* autoRoute: true,
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* const router = createRouter(config)
|
|
22
|
+
* const output = router.route({
|
|
23
|
+
* request: "Fix the typo in src/utils.ts",
|
|
24
|
+
* planFileExists: false,
|
|
25
|
+
* isExecutingPlan: false,
|
|
26
|
+
* hasUncommittedChanges: true,
|
|
27
|
+
* mentionedFiles: ['src/utils.ts'],
|
|
28
|
+
* })
|
|
29
|
+
* // output.classification.type === 'quick-task'
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
import { RequestClassifier } from './classifier.js';
|
|
33
|
+
import { MainAgentGuard } from './guard.js';
|
|
34
|
+
/**
|
|
35
|
+
* Create a router with the given configuration.
|
|
36
|
+
*
|
|
37
|
+
* Wires together:
|
|
38
|
+
* - RequestClassifier: analyzes user input, determines intent
|
|
39
|
+
* - MainAgentGuard: enforces thin-dispatcher constraints
|
|
40
|
+
*/
|
|
41
|
+
export function createRouter(config) {
|
|
42
|
+
const classifier = new RequestClassifier(config);
|
|
43
|
+
const guard = new MainAgentGuard(config);
|
|
44
|
+
function route(input) {
|
|
45
|
+
const context = {
|
|
46
|
+
planFileExists: input.planFileExists,
|
|
47
|
+
isExecutingPlan: input.isExecutingPlan,
|
|
48
|
+
hasUncommittedChanges: input.hasUncommittedChanges,
|
|
49
|
+
currentBranch: input.currentBranch,
|
|
50
|
+
mentionedFiles: input.mentionedFiles,
|
|
51
|
+
};
|
|
52
|
+
const result = classifier.classify(input.request, context);
|
|
53
|
+
// Activate embargo after routing (unless trivial edit)
|
|
54
|
+
if (result.classification.type !== 'quick-task') {
|
|
55
|
+
guard.activateEmbargo();
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
classification: result.classification,
|
|
59
|
+
routing: result.routing,
|
|
60
|
+
confidence: result.confidence,
|
|
61
|
+
matchedRule: result.matchedRule,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function generateSystemPrompt() {
|
|
65
|
+
return guard.generateSystemPromptFragment();
|
|
66
|
+
}
|
|
67
|
+
function isOperationAllowed(operation) {
|
|
68
|
+
return guard.checkOperation(operation).allowed;
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
route,
|
|
72
|
+
classifier,
|
|
73
|
+
guard,
|
|
74
|
+
generateSystemPrompt,
|
|
75
|
+
isOperationAllowed,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../../src/router/router.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAEnD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAsB3C;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,MAAoB;IAC/C,MAAM,UAAU,GAAG,IAAI,iBAAiB,CAAC,MAAM,CAAC,CAAA;IAChD,MAAM,KAAK,GAAG,IAAI,cAAc,CAAC,MAAM,CAAC,CAAA;IAExC,SAAS,KAAK,CAAC,KAAkB;QAC/B,MAAM,OAAO,GAA0B;YACrC,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,eAAe,EAAE,KAAK,CAAC,eAAe;YACtC,qBAAqB,EAAE,KAAK,CAAC,qBAAqB;YAClD,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,cAAc,EAAE,KAAK,CAAC,cAAc;SACrC,CAAA;QAED,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAE1D,uDAAuD;QACvD,IAAI,MAAM,CAAC,cAAc,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAChD,KAAK,CAAC,eAAe,EAAE,CAAA;QACzB,CAAC;QAED,OAAO;YACL,cAAc,EAAE,MAAM,CAAC,cAAc;YACrC,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,WAAW,EAAE,MAAM,CAAC,WAAW;SAChC,CAAA;IACH,CAAC;IAED,SAAS,oBAAoB;QAC3B,OAAO,KAAK,CAAC,4BAA4B,EAAE,CAAA;IAC7C,CAAC;IAED,SAAS,kBAAkB,CAAC,SAAiB;QAC3C,OAAO,KAAK,CAAC,cAAc,CAAC,SAAuD,CAAC,CAAC,OAAO,CAAA;IAC9F,CAAC;IAED,OAAO;QACL,KAAK;QACL,UAAU;QACV,KAAK;QACL,oBAAoB;QACpB,kBAAkB;KACnB,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router system types - Controls all user input routing
|
|
3
|
+
*/
|
|
4
|
+
import type { SubagentConfig, SubagentResult } from '../agents/types.js';
|
|
5
|
+
/** Classification of user intent */
|
|
6
|
+
export type IntentType = 'plan' | 'quick-task' | 'execute' | 'review' | 'debug' | 'tdd' | 'general';
|
|
7
|
+
export interface IntentClassification {
|
|
8
|
+
type: IntentType;
|
|
9
|
+
confidence: number;
|
|
10
|
+
reasoning: string;
|
|
11
|
+
suggestedAgent: string;
|
|
12
|
+
}
|
|
13
|
+
export interface RouterConfig {
|
|
14
|
+
/** Default model for subagents */
|
|
15
|
+
defaultModel: string;
|
|
16
|
+
/** Threshold for routing to quick-task vs to-plan */
|
|
17
|
+
planningThreshold: number;
|
|
18
|
+
/** Max tokens before forcing subagent dispatch */
|
|
19
|
+
maxMainAgentTokens: number;
|
|
20
|
+
/** Whether to auto-route based on keywords */
|
|
21
|
+
autoRoute: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface RoutingDecision {
|
|
24
|
+
/** The subagent to dispatch */
|
|
25
|
+
subagent: SubagentConfig;
|
|
26
|
+
/** Contract/prompt for the subagent */
|
|
27
|
+
contract: SubagentContract;
|
|
28
|
+
/** Whether to wait for result or stream */
|
|
29
|
+
async: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface SubagentContract {
|
|
32
|
+
/** What this subagent is allowed to do */
|
|
33
|
+
permissions: PermissionSet;
|
|
34
|
+
/** Exact prompt to send */
|
|
35
|
+
prompt: string;
|
|
36
|
+
/** Required output format */
|
|
37
|
+
outputSchema?: Record<string, unknown>;
|
|
38
|
+
/** Files this subagent owns */
|
|
39
|
+
owns: string[];
|
|
40
|
+
/** Files this subagent may read */
|
|
41
|
+
reads: string[];
|
|
42
|
+
}
|
|
43
|
+
export interface PermissionSet {
|
|
44
|
+
readFiles: boolean;
|
|
45
|
+
searchCode: boolean;
|
|
46
|
+
runCommands: boolean;
|
|
47
|
+
writeFiles: boolean;
|
|
48
|
+
gitOperations: boolean;
|
|
49
|
+
}
|
|
50
|
+
export interface RouterResult {
|
|
51
|
+
decision: RoutingDecision;
|
|
52
|
+
/** Estimated token usage */
|
|
53
|
+
estimatedTokens: number;
|
|
54
|
+
/** Fallback if subagent fails */
|
|
55
|
+
fallbackStrategy: 'retry' | 'escalate' | 'abort';
|
|
56
|
+
}
|
|
57
|
+
export interface ExecutionResult {
|
|
58
|
+
success: boolean;
|
|
59
|
+
result?: SubagentResult;
|
|
60
|
+
error?: string;
|
|
61
|
+
/** Tokens used by entire routing chain */
|
|
62
|
+
totalTokens: number;
|
|
63
|
+
/** Time taken */
|
|
64
|
+
duration: number;
|
|
65
|
+
}
|
|
66
|
+
/** Input to the router: raw request + classification context. */
|
|
67
|
+
export interface RouterInput {
|
|
68
|
+
/** Raw user request text */
|
|
69
|
+
request: string;
|
|
70
|
+
/** Whether a plan file already exists */
|
|
71
|
+
planFileExists: boolean;
|
|
72
|
+
/** Whether mid-execution of a plan */
|
|
73
|
+
isExecutingPlan: boolean;
|
|
74
|
+
/** Whether there are uncommitted changes */
|
|
75
|
+
hasUncommittedChanges: boolean;
|
|
76
|
+
/** Current git branch */
|
|
77
|
+
currentBranch?: string;
|
|
78
|
+
/** Files mentioned by the user */
|
|
79
|
+
mentionedFiles: string[];
|
|
80
|
+
}
|
|
81
|
+
/** Output from the router: classification + full routing decision. */
|
|
82
|
+
export interface RouterOutput {
|
|
83
|
+
classification: IntentClassification;
|
|
84
|
+
routing: RoutingDecision;
|
|
85
|
+
confidence: number;
|
|
86
|
+
matchedRule: string;
|
|
87
|
+
}
|
|
88
|
+
/** Main Agent is NEVER allowed to do these */
|
|
89
|
+
export declare const MAIN_AGENT_PROHIBITED: {
|
|
90
|
+
readSourceFiles: boolean;
|
|
91
|
+
searchCodebase: boolean;
|
|
92
|
+
writeFiles: boolean;
|
|
93
|
+
runBuildCommands: boolean;
|
|
94
|
+
runTests: boolean;
|
|
95
|
+
editLargeFiles: boolean;
|
|
96
|
+
longRunningTasks: boolean;
|
|
97
|
+
};
|
|
98
|
+
/** Keywords that trigger specific routes */
|
|
99
|
+
export declare const ROUTE_KEYWORDS: Record<IntentType, string[]>;
|
|
100
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/router/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAExE,oCAAoC;AACpC,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,YAAY,GACZ,SAAS,GACT,QAAQ,GACR,OAAO,GACP,KAAK,GACL,SAAS,CAAA;AAEb,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,UAAU,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,YAAY,EAAE,MAAM,CAAA;IACpB,qDAAqD;IACrD,iBAAiB,EAAE,MAAM,CAAA;IACzB,kDAAkD;IAClD,kBAAkB,EAAE,MAAM,CAAA;IAC1B,8CAA8C;IAC9C,SAAS,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,+BAA+B;IAC/B,QAAQ,EAAE,cAAc,CAAA;IACxB,uCAAuC;IACvC,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,2CAA2C;IAC3C,KAAK,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,0CAA0C;IAC1C,WAAW,EAAE,aAAa,CAAA;IAC1B,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,6BAA6B;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACtC,+BAA+B;IAC/B,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,mCAAmC;IACnC,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,OAAO,CAAA;IAClB,UAAU,EAAE,OAAO,CAAA;IACnB,WAAW,EAAE,OAAO,CAAA;IACpB,UAAU,EAAE,OAAO,CAAA;IACnB,aAAa,EAAE,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,eAAe,CAAA;IACzB,4BAA4B;IAC5B,eAAe,EAAE,MAAM,CAAA;IACvB,iCAAiC;IACjC,gBAAgB,EAAE,OAAO,GAAG,UAAU,GAAG,OAAO,CAAA;CACjD;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,CAAC,EAAE,cAAc,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB;IACjB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,iEAAiE;AACjE,MAAM,WAAW,WAAW;IAC1B,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,yCAAyC;IACzC,cAAc,EAAE,OAAO,CAAA;IACvB,sCAAsC;IACtC,eAAe,EAAE,OAAO,CAAA;IACxB,4CAA4C;IAC5C,qBAAqB,EAAE,OAAO,CAAA;IAC9B,yBAAyB;IACzB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,kCAAkC;IAClC,cAAc,EAAE,MAAM,EAAE,CAAA;CACzB;AAED,sEAAsE;AACtE,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,oBAAoB,CAAA;IACpC,OAAO,EAAE,eAAe,CAAA;IACxB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,8CAA8C;AAC9C,eAAO,MAAM,qBAAqB;;;;;;;;CAQjC,CAAA;AAED,4CAA4C;AAC5C,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,CAQvD,CAAA"}
|