smart-context-mcp 1.1.0 → 1.3.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 +239 -20
- package/package.json +10 -7
- package/scripts/init-clients.js +56 -27
- package/scripts/report-metrics.js +5 -0
- package/scripts/report-workflow-metrics.js +255 -0
- package/src/analytics/adoption.js +197 -0
- package/src/decision-explainer.js +168 -0
- package/src/missed-opportunities.js +255 -0
- package/src/server.js +66 -0
- package/src/storage/sqlite.js +30 -1
- package/src/tools/smart-context.js +33 -1
- package/src/tools/smart-metrics.js +7 -0
- package/src/tools/smart-read-batch.js +9 -0
- package/src/tools/smart-read.js +56 -1
- package/src/tools/smart-search.js +31 -0
- package/src/tools/smart-shell.js +62 -9
- package/src/tools/smart-summary.js +46 -2
- package/src/tools/smart-turn.js +1 -0
- package/src/usage-feedback.js +179 -0
- package/src/workflow-tracker-stub.js +53 -0
- package/src/workflow-tracker.js +410 -0
package/src/tools/smart-shell.js
CHANGED
|
@@ -4,13 +4,26 @@ import { rgPath } from '@vscode/ripgrep';
|
|
|
4
4
|
import { buildMetrics, persistMetrics } from '../metrics.js';
|
|
5
5
|
import { projectRoot } from '../utils/paths.js';
|
|
6
6
|
import { pickRelevantLines, truncate, uniqueLines } from '../utils/text.js';
|
|
7
|
+
import { recordToolUsage } from '../usage-feedback.js';
|
|
8
|
+
import { recordDecision, DECISION_REASONS, EXPECTED_BENEFITS } from '../decision-explainer.js';
|
|
9
|
+
import { recordDevctxOperation } from '../missed-opportunities.js';
|
|
7
10
|
|
|
8
11
|
const execFile = promisify(execFileCallback);
|
|
9
|
-
const
|
|
12
|
+
const isShellDisabled = () => process.env.DEVCTX_SHELL_DISABLED === 'true';
|
|
13
|
+
const blockedPattern = /[|&;<>`\n\r$()]/;
|
|
10
14
|
const allowedCommands = new Set(['pwd', 'ls', 'find', 'rg', 'git', 'npm', 'pnpm', 'yarn', 'bun']);
|
|
11
|
-
const allowedGitSubcommands = new Set(['status', 'diff', 'show', 'log', 'branch', 'rev-parse']);
|
|
15
|
+
const allowedGitSubcommands = new Set(['status', 'diff', 'show', 'log', 'branch', 'rev-parse', 'blame']);
|
|
12
16
|
const allowedPackageManagerSubcommands = new Set(['test', 'run', 'lint', 'build', 'typecheck', 'check']);
|
|
13
|
-
const safeRunScriptPattern = /^(test|lint|build|typecheck|check|smoke|verify)(:|$)/;
|
|
17
|
+
const safeRunScriptPattern = /^(test|lint|build|typecheck|check|smoke|verify|eval)(:|$)/;
|
|
18
|
+
const dangerousPatterns = [
|
|
19
|
+
/rm\s+-rf/i,
|
|
20
|
+
/sudo/i,
|
|
21
|
+
/curl.*\|/i,
|
|
22
|
+
/wget.*\|/i,
|
|
23
|
+
/eval/i,
|
|
24
|
+
/exec/i,
|
|
25
|
+
];
|
|
26
|
+
const MAX_COMMAND_LENGTH = 500;
|
|
14
27
|
|
|
15
28
|
const tokenize = (command) => {
|
|
16
29
|
const tokens = [];
|
|
@@ -67,12 +80,26 @@ const tokenize = (command) => {
|
|
|
67
80
|
};
|
|
68
81
|
|
|
69
82
|
const validateCommand = (command, tokens) => {
|
|
83
|
+
if (isShellDisabled()) {
|
|
84
|
+
return 'Shell execution is disabled (DEVCTX_SHELL_DISABLED=true)';
|
|
85
|
+
}
|
|
86
|
+
|
|
70
87
|
if (!command.trim()) {
|
|
71
88
|
return 'Command is empty';
|
|
72
89
|
}
|
|
73
90
|
|
|
74
|
-
if (
|
|
75
|
-
return
|
|
91
|
+
if (command.length > MAX_COMMAND_LENGTH) {
|
|
92
|
+
return `Command too long (max ${MAX_COMMAND_LENGTH} chars)`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (blockedPattern.test(command)) {
|
|
96
|
+
return 'Shell operators are not allowed (|, &, ;, <, >, `, $, (, ))';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
for (const pattern of dangerousPatterns) {
|
|
100
|
+
if (pattern.test(command)) {
|
|
101
|
+
return `Dangerous pattern detected: ${pattern.source}`;
|
|
102
|
+
}
|
|
76
103
|
}
|
|
77
104
|
|
|
78
105
|
if (tokens.length === 0) {
|
|
@@ -82,11 +109,11 @@ const validateCommand = (command, tokens) => {
|
|
|
82
109
|
const [baseCommand, subcommand, thirdToken] = tokens;
|
|
83
110
|
|
|
84
111
|
if (!allowedCommands.has(baseCommand)) {
|
|
85
|
-
return `Command not allowed: ${baseCommand}`;
|
|
112
|
+
return `Command not allowed: ${baseCommand}. Allowed: ${[...allowedCommands].join(', ')}`;
|
|
86
113
|
}
|
|
87
114
|
|
|
88
115
|
if (baseCommand === 'git' && !allowedGitSubcommands.has(subcommand)) {
|
|
89
|
-
return `Git subcommand not allowed: ${subcommand ?? '(missing)'}`;
|
|
116
|
+
return `Git subcommand not allowed: ${subcommand ?? '(missing)'}. Allowed: ${[...allowedGitSubcommands].join(', ')}`;
|
|
90
117
|
}
|
|
91
118
|
|
|
92
119
|
if (baseCommand === 'find') {
|
|
@@ -99,11 +126,11 @@ const validateCommand = (command, tokens) => {
|
|
|
99
126
|
|
|
100
127
|
if (['npm', 'pnpm', 'yarn', 'bun'].includes(baseCommand)) {
|
|
101
128
|
if (!subcommand || !allowedPackageManagerSubcommands.has(subcommand)) {
|
|
102
|
-
return `Package manager subcommand not allowed: ${subcommand ?? '(missing)'}`;
|
|
129
|
+
return `Package manager subcommand not allowed: ${subcommand ?? '(missing)'}. Allowed: ${[...allowedPackageManagerSubcommands].join(', ')}`;
|
|
103
130
|
}
|
|
104
131
|
|
|
105
132
|
if (subcommand === 'run' && (!thirdToken || !safeRunScriptPattern.test(thirdToken))) {
|
|
106
|
-
return `Package manager script not allowed: ${thirdToken ?? '(missing)'}`;
|
|
133
|
+
return `Package manager script not allowed: ${thirdToken ?? '(missing)'}. Allowed pattern: ${safeRunScriptPattern.source}`;
|
|
107
134
|
}
|
|
108
135
|
}
|
|
109
136
|
|
|
@@ -197,6 +224,32 @@ export const smartShell = async ({ command }) => {
|
|
|
197
224
|
});
|
|
198
225
|
|
|
199
226
|
await persistMetrics(metrics);
|
|
227
|
+
|
|
228
|
+
// Record usage for feedback
|
|
229
|
+
recordToolUsage({
|
|
230
|
+
tool: 'smart_shell',
|
|
231
|
+
savedTokens: metrics.savedTokens,
|
|
232
|
+
target: command,
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Record devctx operation for missed opportunity detection
|
|
236
|
+
recordDevctxOperation();
|
|
237
|
+
|
|
238
|
+
// Record decision explanation
|
|
239
|
+
const outputLines = rawText.split('\n').length;
|
|
240
|
+
let reason = DECISION_REASONS.COMMAND_OUTPUT;
|
|
241
|
+
if (shouldPrioritizeRelevant && relevant) {
|
|
242
|
+
reason = DECISION_REASONS.RELEVANT_LINES;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
recordDecision({
|
|
246
|
+
tool: 'smart_shell',
|
|
247
|
+
action: `execute "${command}"`,
|
|
248
|
+
reason,
|
|
249
|
+
alternative: 'Shell (uncompressed output)',
|
|
250
|
+
expectedBenefit: EXPECTED_BENEFITS.TOKEN_SAVINGS(metrics.savedTokens),
|
|
251
|
+
context: `${outputLines} lines → ${compressedText.split('\n').length} lines (relevant only)`,
|
|
252
|
+
});
|
|
200
253
|
|
|
201
254
|
const result = {
|
|
202
255
|
command,
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { countTokens } from '../tokenCounter.js';
|
|
2
2
|
import { persistMetrics } from '../metrics.js';
|
|
3
3
|
import { enforceRepoSafety, getRepoSafety } from '../repo-safety.js';
|
|
4
|
+
import { recordToolUsage } from '../usage-feedback.js';
|
|
5
|
+
import { recordDecision, DECISION_REASONS, EXPECTED_BENEFITS } from '../decision-explainer.js';
|
|
6
|
+
import { recordDevctxOperation } from '../missed-opportunities.js';
|
|
4
7
|
import {
|
|
5
8
|
ACTIVE_SESSION_SCOPE,
|
|
6
9
|
SQLITE_SCHEMA_VERSION,
|
|
@@ -1212,6 +1215,23 @@ export const smartSummary = async ({
|
|
|
1212
1215
|
...summaryMetrics,
|
|
1213
1216
|
latencyMs: Date.now() - startTime,
|
|
1214
1217
|
});
|
|
1218
|
+
|
|
1219
|
+
recordToolUsage({
|
|
1220
|
+
tool: 'smart_summary',
|
|
1221
|
+
savedTokens: summaryMetrics.savedTokens || 0,
|
|
1222
|
+
target: targetSessionId,
|
|
1223
|
+
});
|
|
1224
|
+
|
|
1225
|
+
recordDevctxOperation();
|
|
1226
|
+
|
|
1227
|
+
recordDecision({
|
|
1228
|
+
tool: 'smart_summary',
|
|
1229
|
+
action: `get checkpoint "${targetSessionId}"`,
|
|
1230
|
+
reason: DECISION_REASONS.RESUME,
|
|
1231
|
+
alternative: 'Start from scratch (lose context)',
|
|
1232
|
+
expectedBenefit: EXPECTED_BENEFITS.SESSION_RECOVERY,
|
|
1233
|
+
context: `Recovered ${compressed.goal ? 'goal' : 'state'}, ${compressed.status || 'unknown'} status`,
|
|
1234
|
+
});
|
|
1215
1235
|
}
|
|
1216
1236
|
|
|
1217
1237
|
return addRepoSafety({
|
|
@@ -1356,14 +1376,21 @@ export const smartSummary = async ({
|
|
|
1356
1376
|
const { compressed, tokens, truncated, omitted, compressionLevel } = compressSummary(currentSession, maxTokens);
|
|
1357
1377
|
const rawTokens = countTokens(JSON.stringify(currentSession));
|
|
1358
1378
|
|
|
1379
|
+
const metrics = buildSummaryMetrics(rawTokens, tokens);
|
|
1359
1380
|
persistMetrics({
|
|
1360
1381
|
tool: 'smart_summary',
|
|
1361
1382
|
action,
|
|
1362
1383
|
sessionId: targetSessionId,
|
|
1363
|
-
...
|
|
1384
|
+
...metrics,
|
|
1364
1385
|
latencyMs: Date.now() - startTime,
|
|
1365
1386
|
skipped: true,
|
|
1366
1387
|
});
|
|
1388
|
+
|
|
1389
|
+
recordToolUsage({
|
|
1390
|
+
tool: 'smart_summary',
|
|
1391
|
+
savedTokens: metrics.savedTokens || 0,
|
|
1392
|
+
target: targetSessionId,
|
|
1393
|
+
});
|
|
1367
1394
|
|
|
1368
1395
|
return addRepoSafety({
|
|
1369
1396
|
action,
|
|
@@ -1386,15 +1413,24 @@ export const smartSummary = async ({
|
|
|
1386
1413
|
const { compressed, tokens, truncated, omitted, compressionLevel } = compressSummary(currentSession, maxTokens);
|
|
1387
1414
|
const rawTokens = countTokens(JSON.stringify(currentSession));
|
|
1388
1415
|
|
|
1416
|
+
const metrics2 = buildSummaryMetrics(rawTokens, tokens);
|
|
1389
1417
|
persistMetrics({
|
|
1390
1418
|
tool: 'smart_summary',
|
|
1391
1419
|
action,
|
|
1392
1420
|
sessionId: targetSessionId,
|
|
1393
|
-
...
|
|
1421
|
+
...metrics2,
|
|
1394
1422
|
latencyMs: Date.now() - startTime,
|
|
1395
1423
|
skipped: true,
|
|
1396
1424
|
checkpointEvent: checkpointDecision.event,
|
|
1397
1425
|
});
|
|
1426
|
+
|
|
1427
|
+
recordToolUsage({
|
|
1428
|
+
tool: 'smart_summary',
|
|
1429
|
+
savedTokens: metrics2.savedTokens || 0,
|
|
1430
|
+
target: targetSessionId,
|
|
1431
|
+
});
|
|
1432
|
+
|
|
1433
|
+
recordDevctxOperation();
|
|
1398
1434
|
|
|
1399
1435
|
return addRepoSafety({
|
|
1400
1436
|
action,
|
|
@@ -1455,6 +1491,14 @@ export const smartSummary = async ({
|
|
|
1455
1491
|
latencyMs: Date.now() - startTime,
|
|
1456
1492
|
...(action === 'checkpoint' ? { checkpointEvent: checkpointDecision.event } : {}),
|
|
1457
1493
|
});
|
|
1494
|
+
|
|
1495
|
+
recordToolUsage({
|
|
1496
|
+
tool: 'smart_summary',
|
|
1497
|
+
savedTokens: summaryMetrics.savedTokens || 0,
|
|
1498
|
+
target: targetSessionId,
|
|
1499
|
+
});
|
|
1500
|
+
|
|
1501
|
+
recordDevctxOperation();
|
|
1458
1502
|
|
|
1459
1503
|
return addRepoSafety({
|
|
1460
1504
|
action,
|
package/src/tools/smart-turn.js
CHANGED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage feedback system - tracks devctx tool usage in current session
|
|
3
|
+
* and provides visible feedback to users about what tools were used and tokens saved.
|
|
4
|
+
*
|
|
5
|
+
* Enable with environment variable: DEVCTX_SHOW_USAGE=true
|
|
6
|
+
*
|
|
7
|
+
* Auto-enabled for first 10 tool calls (onboarding mode), then auto-disables.
|
|
8
|
+
* User can explicitly enable/disable at any time.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const sessionUsage = {
|
|
12
|
+
tools: new Map(), // toolName -> { count, savedTokens }
|
|
13
|
+
totalSavedTokens: 0,
|
|
14
|
+
enabled: false,
|
|
15
|
+
totalToolCalls: 0,
|
|
16
|
+
onboardingMode: true,
|
|
17
|
+
ONBOARDING_THRESHOLD: 10, // Auto-disable after 10 tool calls
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check if usage feedback is enabled
|
|
22
|
+
*
|
|
23
|
+
* Priority:
|
|
24
|
+
* 1. Explicit env var (DEVCTX_SHOW_USAGE=true/false)
|
|
25
|
+
* 2. Onboarding mode (first 10 tool calls)
|
|
26
|
+
* 3. Default: disabled
|
|
27
|
+
*/
|
|
28
|
+
export const isFeedbackEnabled = () => {
|
|
29
|
+
const envValue = process.env.DEVCTX_SHOW_USAGE?.toLowerCase();
|
|
30
|
+
|
|
31
|
+
// Explicit enable
|
|
32
|
+
if (envValue === 'true' || envValue === '1' || envValue === 'yes') {
|
|
33
|
+
sessionUsage.enabled = true;
|
|
34
|
+
sessionUsage.onboardingMode = false;
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Explicit disable
|
|
39
|
+
if (envValue === 'false' || envValue === '0' || envValue === 'no') {
|
|
40
|
+
sessionUsage.enabled = false;
|
|
41
|
+
sessionUsage.onboardingMode = false;
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Onboarding mode: auto-enable for first N tool calls
|
|
46
|
+
if (sessionUsage.onboardingMode && sessionUsage.totalToolCalls < sessionUsage.ONBOARDING_THRESHOLD) {
|
|
47
|
+
sessionUsage.enabled = true;
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// After onboarding threshold, auto-disable
|
|
52
|
+
if (sessionUsage.onboardingMode && sessionUsage.totalToolCalls >= sessionUsage.ONBOARDING_THRESHOLD) {
|
|
53
|
+
sessionUsage.enabled = false;
|
|
54
|
+
sessionUsage.onboardingMode = false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return sessionUsage.enabled;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Record tool usage for feedback
|
|
62
|
+
*/
|
|
63
|
+
export const recordToolUsage = ({ tool, savedTokens = 0, target = null }) => {
|
|
64
|
+
// Increment total tool calls (for onboarding mode)
|
|
65
|
+
sessionUsage.totalToolCalls += 1;
|
|
66
|
+
|
|
67
|
+
if (!isFeedbackEnabled()) return;
|
|
68
|
+
|
|
69
|
+
const current = sessionUsage.tools.get(tool) || { count: 0, savedTokens: 0, targets: [] };
|
|
70
|
+
current.count += 1;
|
|
71
|
+
current.savedTokens += savedTokens;
|
|
72
|
+
if (target) current.targets.push(target);
|
|
73
|
+
|
|
74
|
+
sessionUsage.tools.set(tool, current);
|
|
75
|
+
sessionUsage.totalSavedTokens += savedTokens;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get current session usage stats
|
|
80
|
+
*/
|
|
81
|
+
export const getSessionUsage = () => {
|
|
82
|
+
return {
|
|
83
|
+
tools: Array.from(sessionUsage.tools.entries()).map(([tool, stats]) => ({
|
|
84
|
+
tool,
|
|
85
|
+
count: stats.count,
|
|
86
|
+
savedTokens: stats.savedTokens,
|
|
87
|
+
targets: stats.targets.slice(-3), // Last 3 targets only
|
|
88
|
+
})),
|
|
89
|
+
totalSavedTokens: sessionUsage.totalSavedTokens,
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Format usage feedback as markdown
|
|
95
|
+
*/
|
|
96
|
+
export const formatUsageFeedback = () => {
|
|
97
|
+
if (!isFeedbackEnabled()) return '';
|
|
98
|
+
|
|
99
|
+
const usage = getSessionUsage();
|
|
100
|
+
if (usage.tools.length === 0) return '';
|
|
101
|
+
|
|
102
|
+
const lines = [];
|
|
103
|
+
lines.push('');
|
|
104
|
+
lines.push('---');
|
|
105
|
+
lines.push('');
|
|
106
|
+
lines.push('📊 **devctx usage this session:**');
|
|
107
|
+
|
|
108
|
+
// Sort by count descending
|
|
109
|
+
const sorted = usage.tools.sort((a, b) => b.count - a.count);
|
|
110
|
+
|
|
111
|
+
for (const { tool, count, savedTokens, targets } of sorted) {
|
|
112
|
+
const countStr = count === 1 ? '1 call' : `${count} calls`;
|
|
113
|
+
const tokensStr = savedTokens > 0 ? ` | ~${formatTokens(savedTokens)} saved` : '';
|
|
114
|
+
|
|
115
|
+
if (targets.length > 0) {
|
|
116
|
+
const targetsPreview = targets.length === 1
|
|
117
|
+
? ` (${truncateTarget(targets[0])})`
|
|
118
|
+
: ` (${targets.length} files)`;
|
|
119
|
+
lines.push(`- **${tool}**: ${countStr}${tokensStr}${targetsPreview}`);
|
|
120
|
+
} else {
|
|
121
|
+
lines.push(`- **${tool}**: ${countStr}${tokensStr}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (usage.totalSavedTokens > 0) {
|
|
126
|
+
lines.push('');
|
|
127
|
+
lines.push(`**Total saved:** ~${formatTokens(usage.totalSavedTokens)}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
lines.push('');
|
|
131
|
+
|
|
132
|
+
// Show onboarding message if in onboarding mode
|
|
133
|
+
if (sessionUsage.onboardingMode && sessionUsage.totalToolCalls < sessionUsage.ONBOARDING_THRESHOLD) {
|
|
134
|
+
const remaining = sessionUsage.ONBOARDING_THRESHOLD - sessionUsage.totalToolCalls;
|
|
135
|
+
lines.push(`*Onboarding mode: showing for ${remaining} more tool calls. To keep: \`export DEVCTX_SHOW_USAGE=true\`*`);
|
|
136
|
+
} else {
|
|
137
|
+
lines.push('*To disable this message: `export DEVCTX_SHOW_USAGE=false`*');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return lines.join('\n');
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Reset session usage (for testing or manual reset)
|
|
145
|
+
*/
|
|
146
|
+
export const resetSessionUsage = () => {
|
|
147
|
+
sessionUsage.tools.clear();
|
|
148
|
+
sessionUsage.totalSavedTokens = 0;
|
|
149
|
+
sessionUsage.totalToolCalls = 0;
|
|
150
|
+
sessionUsage.onboardingMode = true;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Format token count for display
|
|
155
|
+
*/
|
|
156
|
+
const formatTokens = (tokens) => {
|
|
157
|
+
if (tokens >= 1000000) {
|
|
158
|
+
return `${(tokens / 1000000).toFixed(1)}M tokens`;
|
|
159
|
+
}
|
|
160
|
+
if (tokens >= 1000) {
|
|
161
|
+
return `${(tokens / 1000).toFixed(1)}K tokens`;
|
|
162
|
+
}
|
|
163
|
+
return `${tokens} tokens`;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Truncate target path for display
|
|
168
|
+
*/
|
|
169
|
+
const truncateTarget = (target) => {
|
|
170
|
+
if (!target) return '';
|
|
171
|
+
if (target.length <= 40) return target;
|
|
172
|
+
|
|
173
|
+
// Try to show filename
|
|
174
|
+
const parts = target.split('/');
|
|
175
|
+
const filename = parts[parts.length - 1];
|
|
176
|
+
if (filename.length <= 40) return `.../${filename}`;
|
|
177
|
+
|
|
178
|
+
return target.slice(0, 37) + '...';
|
|
179
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Stub for workflow tracking (to be implemented in future version)
|
|
2
|
+
// This avoids SQLite issues in tests while keeping the API available
|
|
3
|
+
|
|
4
|
+
export const detectWorkflowType = () => null;
|
|
5
|
+
export const getWorkflowBaseline = () => 0;
|
|
6
|
+
export const startWorkflow = () => null;
|
|
7
|
+
export const endWorkflow = () => null;
|
|
8
|
+
export const getWorkflowMetrics = () => [];
|
|
9
|
+
export const getWorkflowSummaryByType = () => [];
|
|
10
|
+
export const autoTrackWorkflow = () => null;
|
|
11
|
+
|
|
12
|
+
export const WORKFLOW_DEFINITIONS = {
|
|
13
|
+
debugging: {
|
|
14
|
+
name: 'Debugging',
|
|
15
|
+
description: 'Error-first, symbol-focused debugging workflow',
|
|
16
|
+
typicalTools: ['smart_turn', 'smart_search', 'smart_read', 'smart_shell'],
|
|
17
|
+
minTools: 3,
|
|
18
|
+
baselineTokens: 150000,
|
|
19
|
+
pattern: /debug|error|bug|fix|fail/i,
|
|
20
|
+
},
|
|
21
|
+
'code-review': {
|
|
22
|
+
name: 'Code Review',
|
|
23
|
+
description: 'Diff-aware, API-focused code review workflow',
|
|
24
|
+
typicalTools: ['smart_turn', 'smart_context', 'smart_read', 'git_blame', 'smart_shell'],
|
|
25
|
+
minTools: 3,
|
|
26
|
+
baselineTokens: 200000,
|
|
27
|
+
pattern: /review|pr|pull.?request|approve/i,
|
|
28
|
+
},
|
|
29
|
+
refactoring: {
|
|
30
|
+
name: 'Refactoring',
|
|
31
|
+
description: 'Graph-aware, test-verified refactoring workflow',
|
|
32
|
+
typicalTools: ['smart_turn', 'smart_context', 'smart_read', 'git_blame', 'smart_shell'],
|
|
33
|
+
minTools: 3,
|
|
34
|
+
baselineTokens: 180000,
|
|
35
|
+
pattern: /refactor|extract|rename|move|restructure/i,
|
|
36
|
+
},
|
|
37
|
+
testing: {
|
|
38
|
+
name: 'Testing',
|
|
39
|
+
description: 'Coverage-aware, TDD-friendly testing workflow',
|
|
40
|
+
typicalTools: ['smart_turn', 'smart_search', 'smart_read', 'smart_context', 'smart_shell'],
|
|
41
|
+
minTools: 3,
|
|
42
|
+
baselineTokens: 120000,
|
|
43
|
+
pattern: /test|spec|coverage|tdd/i,
|
|
44
|
+
},
|
|
45
|
+
architecture: {
|
|
46
|
+
name: 'Architecture Exploration',
|
|
47
|
+
description: 'Index-first, minimal-detail architecture exploration',
|
|
48
|
+
typicalTools: ['smart_turn', 'smart_context', 'smart_search', 'smart_read', 'cross_project'],
|
|
49
|
+
minTools: 3,
|
|
50
|
+
baselineTokens: 300000,
|
|
51
|
+
pattern: /architect|explore|understand|structure|design/i,
|
|
52
|
+
},
|
|
53
|
+
};
|