dino-spec 13.5.0 → 13.6.1

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.
Files changed (99) hide show
  1. package/README.md +2 -47
  2. package/bin/dino-hud.js +0 -0
  3. package/bin/dino.js +0 -0
  4. package/dist/commands/hud.d.ts +8 -1
  5. package/dist/commands/hud.d.ts.map +1 -1
  6. package/dist/commands/hud.js +18 -4
  7. package/dist/commands/hud.js.map +1 -1
  8. package/dist/core/config/feature-flags.d.ts +0 -15
  9. package/dist/core/config/feature-flags.d.ts.map +1 -1
  10. package/dist/core/config/feature-flags.js +0 -3
  11. package/dist/core/config/feature-flags.js.map +1 -1
  12. package/dist/core/context/context-health.d.ts +2 -27
  13. package/dist/core/context/context-health.d.ts.map +1 -1
  14. package/dist/core/context/context-health.js +12 -98
  15. package/dist/core/context/context-health.js.map +1 -1
  16. package/dist/core/context/index.d.ts +2 -3
  17. package/dist/core/context/index.d.ts.map +1 -1
  18. package/dist/core/context/index.js +2 -18
  19. package/dist/core/context/index.js.map +1 -1
  20. package/dist/core/context/lazy-loader.d.ts +1 -44
  21. package/dist/core/context/lazy-loader.d.ts.map +1 -1
  22. package/dist/core/context/lazy-loader.js +1 -59
  23. package/dist/core/context/lazy-loader.js.map +1 -1
  24. package/dist/core/generator/claude-md.js +1 -1
  25. package/dist/core/provider/storage.d.ts.map +1 -1
  26. package/dist/core/provider/storage.js +2 -1
  27. package/dist/core/provider/storage.js.map +1 -1
  28. package/dist/hooks/post-edit.js +0 -73
  29. package/dist/hooks/post-edit.js.map +1 -1
  30. package/dist/hooks/session-start.js +0 -115
  31. package/dist/hooks/session-start.js.map +1 -1
  32. package/dist/hooks/types.js +1 -1
  33. package/dist/hooks/user-prompt-submit.js +0 -100
  34. package/dist/hooks/user-prompt-submit.js.map +1 -1
  35. package/dist/hud/config-tui.d.ts +25 -0
  36. package/dist/hud/config-tui.d.ts.map +1 -0
  37. package/dist/hud/config-tui.js +199 -0
  38. package/dist/hud/config-tui.js.map +1 -0
  39. package/dist/hud/config.d.ts +28 -3
  40. package/dist/hud/config.d.ts.map +1 -1
  41. package/dist/hud/config.js +60 -8
  42. package/dist/hud/config.js.map +1 -1
  43. package/dist/hud/index.d.ts.map +1 -1
  44. package/dist/hud/index.js +1 -0
  45. package/dist/hud/index.js.map +1 -1
  46. package/dist/hud/models.d.ts +58 -0
  47. package/dist/hud/models.d.ts.map +1 -0
  48. package/dist/hud/models.js +124 -0
  49. package/dist/hud/models.js.map +1 -0
  50. package/dist/hud/render/budget-bar.d.ts +2 -0
  51. package/dist/hud/render/budget-bar.d.ts.map +1 -1
  52. package/dist/hud/render/budget-bar.js +8 -5
  53. package/dist/hud/render/budget-bar.js.map +1 -1
  54. package/dist/hud/stdin.d.ts +3 -0
  55. package/dist/hud/stdin.d.ts.map +1 -1
  56. package/dist/hud/stdin.js +29 -2
  57. package/dist/hud/stdin.js.map +1 -1
  58. package/dist/hud/token-estimator.d.ts +79 -0
  59. package/dist/hud/token-estimator.d.ts.map +1 -0
  60. package/dist/hud/token-estimator.js +126 -0
  61. package/dist/hud/token-estimator.js.map +1 -0
  62. package/dist/hud/types.d.ts +2 -0
  63. package/dist/hud/types.d.ts.map +1 -1
  64. package/dist/mcp/server.d.ts +1 -2
  65. package/dist/mcp/server.d.ts.map +1 -1
  66. package/dist/mcp/server.js +3 -12
  67. package/dist/mcp/server.js.map +1 -1
  68. package/dist/mcp/tools/index.d.ts +2 -6
  69. package/dist/mcp/tools/index.d.ts.map +1 -1
  70. package/dist/mcp/tools/index.js +2 -17
  71. package/dist/mcp/tools/index.js.map +1 -1
  72. package/dist/mcp-server.d.ts.map +1 -1
  73. package/dist/mcp-server.js +5 -9
  74. package/dist/mcp-server.js.map +1 -1
  75. package/dist/rules/index.js +2 -2
  76. package/dist/utils/gitignore.d.ts.map +1 -1
  77. package/dist/utils/gitignore.js +0 -5
  78. package/dist/utils/gitignore.js.map +1 -1
  79. package/package.json +2 -1
  80. package/dist/core/context/focus-resource-loader.d.ts +0 -143
  81. package/dist/core/context/focus-resource-loader.d.ts.map +0 -1
  82. package/dist/core/context/focus-resource-loader.js +0 -305
  83. package/dist/core/context/focus-resource-loader.js.map +0 -1
  84. package/dist/mcp/focus-filter.d.ts +0 -74
  85. package/dist/mcp/focus-filter.d.ts.map +0 -1
  86. package/dist/mcp/focus-filter.js +0 -229
  87. package/dist/mcp/focus-filter.js.map +0 -1
  88. package/dist/mcp/tools/auto-inject.d.ts +0 -36
  89. package/dist/mcp/tools/auto-inject.d.ts.map +0 -1
  90. package/dist/mcp/tools/auto-inject.js +0 -143
  91. package/dist/mcp/tools/auto-inject.js.map +0 -1
  92. package/dist/mcp/tools/auto-unload.d.ts +0 -29
  93. package/dist/mcp/tools/auto-unload.d.ts.map +0 -1
  94. package/dist/mcp/tools/auto-unload.js +0 -151
  95. package/dist/mcp/tools/auto-unload.js.map +0 -1
  96. package/dist/mcp/tools/health.d.ts +0 -29
  97. package/dist/mcp/tools/health.d.ts.map +0 -1
  98. package/dist/mcp/tools/health.js +0 -171
  99. package/dist/mcp/tools/health.js.map +0 -1
@@ -1,143 +0,0 @@
1
- /**
2
- * Focus-Aware Resource Loader - v13.4.0
3
- *
4
- * Determines if files should be deferred based on focus proximity.
5
- * Implements the "Moderate" aggressiveness strategy:
6
- * - In-focus files: Default threshold (500 tokens)
7
- * - Out-of-focus files: Lower threshold (300 tokens)
8
- *
9
- * Focus distance is calculated based on path hierarchy:
10
- * - Same directory: in-focus
11
- * - Parent/child directory: near-focus
12
- * - Different top-level: out-of-focus
13
- *
14
- * Usage:
15
- * ```typescript
16
- * const config = getFocusAwareDeferConfig('src/mcp/', 'src/core/auth.ts');
17
- * if (config.shouldDefer(tokenCount)) {
18
- * // Defer this file
19
- * }
20
- * ```
21
- */
22
- /**
23
- * Focus proximity levels
24
- */
25
- export type FocusProximity = 'in-focus' | 'near-focus' | 'out-of-focus';
26
- /**
27
- * Focus-aware defer configuration
28
- */
29
- export interface FocusAwareDeferConfig {
30
- /** Current focus area */
31
- focusArea: string;
32
- /** File being evaluated */
33
- filePath: string;
34
- /** Calculated focus proximity */
35
- proximity: FocusProximity;
36
- /** Token threshold for this file */
37
- threshold: number;
38
- /** Whether auto-defer is recommended */
39
- shouldDefer: (tokenCount: number) => boolean;
40
- }
41
- /**
42
- * Focus-aware defer thresholds
43
- */
44
- export interface FocusDeferThresholds {
45
- /** Threshold for in-focus files (default: 500) */
46
- inFocus: number;
47
- /** Threshold for near-focus files (default: 400) */
48
- nearFocus: number;
49
- /** Threshold for out-of-focus files (default: 300) */
50
- outOfFocus: number;
51
- }
52
- /**
53
- * Default thresholds for focus-aware deferring
54
- * "Moderate" aggressiveness - balances context savings with availability
55
- */
56
- export declare const DEFAULT_FOCUS_DEFER_THRESHOLDS: FocusDeferThresholds;
57
- /**
58
- * Get focus-aware thresholds from environment or defaults
59
- */
60
- export declare function getFocusDeferThresholds(): FocusDeferThresholds;
61
- /**
62
- * Calculate focus proximity between focus area and file path
63
- *
64
- * Proximity levels:
65
- * - in-focus: File is within the focus directory or focus directory is parent
66
- * - near-focus: File shares a common ancestor (1-2 levels up)
67
- * - out-of-focus: File is in a completely different area
68
- *
69
- * @param focusArea - Current focus area (e.g., 'src/mcp/')
70
- * @param filePath - File path to evaluate (e.g., 'src/core/auth.ts')
71
- * @returns Focus proximity level
72
- */
73
- export declare function calculateFocusProximity(focusArea: string, filePath: string): FocusProximity;
74
- /**
75
- * Get the token threshold for a given proximity level
76
- */
77
- export declare function getThresholdForProximity(proximity: FocusProximity, thresholds?: FocusDeferThresholds): number;
78
- /**
79
- * Get focus-aware defer configuration for a file
80
- *
81
- * @param focusArea - Current focus area (e.g., 'src/mcp/')
82
- * @param filePath - File path to evaluate
83
- * @param thresholds - Optional custom thresholds
84
- * @returns Configuration object with threshold and shouldDefer function
85
- */
86
- export declare function getFocusAwareDeferConfig(focusArea: string, filePath: string, thresholds?: FocusDeferThresholds): FocusAwareDeferConfig;
87
- /**
88
- * Check if focus-aware deferring is enabled
89
- * Default: enabled (true)
90
- * Opt-out: DINO_FOCUS_DEFER=false
91
- */
92
- export declare function isFocusAwareDeferEnabled(): boolean;
93
- /**
94
- * Classify multiple files by focus proximity
95
- *
96
- * @param focusArea - Current focus area
97
- * @param files - Array of file paths
98
- * @returns Files grouped by proximity
99
- */
100
- export declare function classifyFilesByFocus(focusArea: string, files: string[]): {
101
- inFocus: string[];
102
- nearFocus: string[];
103
- outOfFocus: string[];
104
- };
105
- /**
106
- * Get defer recommendations for a batch of files
107
- *
108
- * @param focusArea - Current focus area
109
- * @param files - Array of file paths with token estimates
110
- * @returns Files that should be deferred
111
- */
112
- export declare function getDeferRecommendations(focusArea: string, files: Array<{
113
- path: string;
114
- tokenEstimate: number;
115
- }>): {
116
- shouldDefer: Array<{
117
- path: string;
118
- tokenEstimate: number;
119
- proximity: FocusProximity;
120
- threshold: number;
121
- }>;
122
- shouldLoad: Array<{
123
- path: string;
124
- tokenEstimate: number;
125
- proximity: FocusProximity;
126
- }>;
127
- stats: {
128
- totalFiles: number;
129
- deferredCount: number;
130
- loadedCount: number;
131
- tokensSaved: number;
132
- tokensLoaded: number;
133
- };
134
- };
135
- /**
136
- * Format focus-aware defer stats for display
137
- */
138
- export declare function formatFocusDeferStats(stats: ReturnType<typeof getDeferRecommendations>['stats'], focusArea?: string): string;
139
- /**
140
- * Format threshold information for display
141
- */
142
- export declare function formatThresholdInfo(thresholds?: FocusDeferThresholds): string;
143
- //# sourceMappingURL=focus-resource-loader.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"focus-resource-loader.d.ts","sourceRoot":"","sources":["../../../src/core/context/focus-resource-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAQH;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,YAAY,GAAG,cAAc,CAAC;AAExE;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,SAAS,EAAE,cAAc,CAAC;IAC1B,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,WAAW,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;CAC9C;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,UAAU,EAAE,MAAM,CAAC;CACpB;AAMD;;;GAGG;AACH,eAAO,MAAM,8BAA8B,EAAE,oBAI5C,CAAC;AAEF;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,oBAAoB,CAU9D;AAsBD;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,cAAc,CAwFhB;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,cAAc,EACzB,UAAU,CAAC,EAAE,oBAAoB,GAChC,MAAM,CAWR;AAMD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,oBAAoB,GAChC,qBAAqB,CAWvB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAMD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EAAE,GACd;IACD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,CAcA;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,GACpD;IACD,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,cAAc,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1G,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,cAAc,CAAA;KAAE,CAAC,CAAC;IACtF,KAAK,EAAE;QACL,UAAU,EAAE,MAAM,CAAC;QACnB,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH,CAsCA;AAMD;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC,OAAO,CAAC,EAC1D,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAgBR;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAc7E"}
@@ -1,305 +0,0 @@
1
- /**
2
- * Focus-Aware Resource Loader - v13.4.0
3
- *
4
- * Determines if files should be deferred based on focus proximity.
5
- * Implements the "Moderate" aggressiveness strategy:
6
- * - In-focus files: Default threshold (500 tokens)
7
- * - Out-of-focus files: Lower threshold (300 tokens)
8
- *
9
- * Focus distance is calculated based on path hierarchy:
10
- * - Same directory: in-focus
11
- * - Parent/child directory: near-focus
12
- * - Different top-level: out-of-focus
13
- *
14
- * Usage:
15
- * ```typescript
16
- * const config = getFocusAwareDeferConfig('src/mcp/', 'src/core/auth.ts');
17
- * if (config.shouldDefer(tokenCount)) {
18
- * // Defer this file
19
- * }
20
- * ```
21
- */
22
- import { normalize } from 'path';
23
- // =============================================================================
24
- // Constants
25
- // =============================================================================
26
- /**
27
- * Default thresholds for focus-aware deferring
28
- * "Moderate" aggressiveness - balances context savings with availability
29
- */
30
- export const DEFAULT_FOCUS_DEFER_THRESHOLDS = {
31
- inFocus: 500, // Same as current default
32
- nearFocus: 400, // Slightly more aggressive
33
- outOfFocus: 300, // Most aggressive (user's choice)
34
- };
35
- /**
36
- * Get focus-aware thresholds from environment or defaults
37
- */
38
- export function getFocusDeferThresholds() {
39
- const inFocus = parseInt(process.env.DINO_DEFER_IN_FOCUS || '', 10);
40
- const nearFocus = parseInt(process.env.DINO_DEFER_NEAR_FOCUS || '', 10);
41
- const outOfFocus = parseInt(process.env.DINO_DEFER_OUT_FOCUS || '', 10);
42
- return {
43
- inFocus: !isNaN(inFocus) && inFocus > 0 ? inFocus : DEFAULT_FOCUS_DEFER_THRESHOLDS.inFocus,
44
- nearFocus: !isNaN(nearFocus) && nearFocus > 0 ? nearFocus : DEFAULT_FOCUS_DEFER_THRESHOLDS.nearFocus,
45
- outOfFocus: !isNaN(outOfFocus) && outOfFocus > 0 ? outOfFocus : DEFAULT_FOCUS_DEFER_THRESHOLDS.outOfFocus,
46
- };
47
- }
48
- // =============================================================================
49
- // Focus Proximity Calculation
50
- // =============================================================================
51
- /**
52
- * Normalize a path for comparison (handles both / and \)
53
- */
54
- function normalizePath(path) {
55
- return normalize(path).replace(/\\/g, '/').toLowerCase();
56
- }
57
- /**
58
- * Get path segments for comparison
59
- */
60
- function getPathSegments(path) {
61
- const normalized = normalizePath(path);
62
- // Remove leading slash and trailing slash, then split
63
- return normalized.replace(/^\/+|\/+$/g, '').split('/').filter(Boolean);
64
- }
65
- /**
66
- * Calculate focus proximity between focus area and file path
67
- *
68
- * Proximity levels:
69
- * - in-focus: File is within the focus directory or focus directory is parent
70
- * - near-focus: File shares a common ancestor (1-2 levels up)
71
- * - out-of-focus: File is in a completely different area
72
- *
73
- * @param focusArea - Current focus area (e.g., 'src/mcp/')
74
- * @param filePath - File path to evaluate (e.g., 'src/core/auth.ts')
75
- * @returns Focus proximity level
76
- */
77
- export function calculateFocusProximity(focusArea, filePath) {
78
- // If no focus area, everything is out-of-focus
79
- if (!focusArea || focusArea.trim() === '') {
80
- return 'out-of-focus';
81
- }
82
- const focusSegments = getPathSegments(focusArea);
83
- const fileSegments = getPathSegments(filePath);
84
- // Empty segments means root or invalid path
85
- if (focusSegments.length === 0 || fileSegments.length === 0) {
86
- return 'out-of-focus';
87
- }
88
- // Check if file is within focus directory
89
- // e.g., focus='src/mcp/', file='src/mcp/server.ts' -> in-focus
90
- if (fileSegments.length >= focusSegments.length) {
91
- let matchCount = 0;
92
- for (let i = 0; i < focusSegments.length; i++) {
93
- if (focusSegments[i] === fileSegments[i]) {
94
- matchCount++;
95
- }
96
- else {
97
- break;
98
- }
99
- }
100
- // All focus segments match -> file is in or under focus
101
- if (matchCount === focusSegments.length) {
102
- return 'in-focus';
103
- }
104
- }
105
- // Check if focus is within file's directory (parent-child)
106
- // e.g., focus='src/mcp/tools/', file='src/mcp/' -> in-focus (file is parent)
107
- if (focusSegments.length > fileSegments.length) {
108
- let matchCount = 0;
109
- for (let i = 0; i < fileSegments.length; i++) {
110
- if (focusSegments[i] === fileSegments[i]) {
111
- matchCount++;
112
- }
113
- else {
114
- break;
115
- }
116
- }
117
- // All file segments match -> focus is under file
118
- if (matchCount === fileSegments.length) {
119
- return 'in-focus';
120
- }
121
- }
122
- // Check for common ancestor (near-focus)
123
- // Count matching segments from the start
124
- let commonSegments = 0;
125
- const minLength = Math.min(focusSegments.length, fileSegments.length);
126
- for (let i = 0; i < minLength; i++) {
127
- if (focusSegments[i] === fileSegments[i]) {
128
- commonSegments++;
129
- }
130
- else {
131
- break;
132
- }
133
- }
134
- // Share at least 1-2 segments -> near-focus
135
- // e.g., focus='src/mcp/', file='src/core/' -> common='src/' -> near-focus
136
- if (commonSegments >= 1) {
137
- // If they share the first 2+ segments, it's near-focus
138
- // e.g., src/core/ and src/mcp/ share 'src' -> near-focus
139
- if (commonSegments >= 2) {
140
- return 'near-focus';
141
- }
142
- // If they only share 1 segment but it's a meaningful one (not 'src'), near-focus
143
- // Otherwise, if only sharing 'src' or similar, check depth
144
- const sharedSegment = focusSegments[0];
145
- if (sharedSegment !== 'src' && sharedSegment !== 'lib' && sharedSegment !== '.') {
146
- return 'near-focus';
147
- }
148
- // They share 'src' or similar - consider near-focus only if depths are similar
149
- const depthDiff = Math.abs(focusSegments.length - fileSegments.length);
150
- if (depthDiff <= 1) {
151
- return 'near-focus';
152
- }
153
- }
154
- // No significant common ancestor -> out-of-focus
155
- return 'out-of-focus';
156
- }
157
- /**
158
- * Get the token threshold for a given proximity level
159
- */
160
- export function getThresholdForProximity(proximity, thresholds) {
161
- const t = thresholds || getFocusDeferThresholds();
162
- switch (proximity) {
163
- case 'in-focus':
164
- return t.inFocus;
165
- case 'near-focus':
166
- return t.nearFocus;
167
- case 'out-of-focus':
168
- return t.outOfFocus;
169
- }
170
- }
171
- // =============================================================================
172
- // Focus-Aware Defer Configuration
173
- // =============================================================================
174
- /**
175
- * Get focus-aware defer configuration for a file
176
- *
177
- * @param focusArea - Current focus area (e.g., 'src/mcp/')
178
- * @param filePath - File path to evaluate
179
- * @param thresholds - Optional custom thresholds
180
- * @returns Configuration object with threshold and shouldDefer function
181
- */
182
- export function getFocusAwareDeferConfig(focusArea, filePath, thresholds) {
183
- const proximity = calculateFocusProximity(focusArea, filePath);
184
- const threshold = getThresholdForProximity(proximity, thresholds);
185
- return {
186
- focusArea,
187
- filePath,
188
- proximity,
189
- threshold,
190
- shouldDefer: (tokenCount) => tokenCount > threshold,
191
- };
192
- }
193
- /**
194
- * Check if focus-aware deferring is enabled
195
- * Default: enabled (true)
196
- * Opt-out: DINO_FOCUS_DEFER=false
197
- */
198
- export function isFocusAwareDeferEnabled() {
199
- return process.env.DINO_FOCUS_DEFER !== 'false';
200
- }
201
- // =============================================================================
202
- // Batch Processing
203
- // =============================================================================
204
- /**
205
- * Classify multiple files by focus proximity
206
- *
207
- * @param focusArea - Current focus area
208
- * @param files - Array of file paths
209
- * @returns Files grouped by proximity
210
- */
211
- export function classifyFilesByFocus(focusArea, files) {
212
- const result = {
213
- inFocus: [],
214
- nearFocus: [],
215
- outOfFocus: [],
216
- };
217
- for (const file of files) {
218
- const proximity = calculateFocusProximity(focusArea, file);
219
- result[proximity === 'in-focus' ? 'inFocus' :
220
- proximity === 'near-focus' ? 'nearFocus' : 'outOfFocus'].push(file);
221
- }
222
- return result;
223
- }
224
- /**
225
- * Get defer recommendations for a batch of files
226
- *
227
- * @param focusArea - Current focus area
228
- * @param files - Array of file paths with token estimates
229
- * @returns Files that should be deferred
230
- */
231
- export function getDeferRecommendations(focusArea, files) {
232
- const shouldDefer = [];
233
- const shouldLoad = [];
234
- let tokensSaved = 0;
235
- let tokensLoaded = 0;
236
- for (const file of files) {
237
- const config = getFocusAwareDeferConfig(focusArea, file.path);
238
- if (config.shouldDefer(file.tokenEstimate)) {
239
- shouldDefer.push({
240
- path: file.path,
241
- tokenEstimate: file.tokenEstimate,
242
- proximity: config.proximity,
243
- threshold: config.threshold,
244
- });
245
- tokensSaved += file.tokenEstimate;
246
- }
247
- else {
248
- shouldLoad.push({
249
- path: file.path,
250
- tokenEstimate: file.tokenEstimate,
251
- proximity: config.proximity,
252
- });
253
- tokensLoaded += file.tokenEstimate;
254
- }
255
- }
256
- return {
257
- shouldDefer,
258
- shouldLoad,
259
- stats: {
260
- totalFiles: files.length,
261
- deferredCount: shouldDefer.length,
262
- loadedCount: shouldLoad.length,
263
- tokensSaved,
264
- tokensLoaded,
265
- },
266
- };
267
- }
268
- // =============================================================================
269
- // Formatting
270
- // =============================================================================
271
- /**
272
- * Format focus-aware defer stats for display
273
- */
274
- export function formatFocusDeferStats(stats, focusArea) {
275
- const lines = [
276
- '## Focus-Aware Deferring',
277
- '',
278
- focusArea ? `**Focus:** ${focusArea}` : '**Focus:** none',
279
- `**Total Files:** ${stats.totalFiles}`,
280
- `**Deferred:** ${stats.deferredCount} (~${stats.tokensSaved} tokens saved)`,
281
- `**Loaded:** ${stats.loadedCount} (~${stats.tokensLoaded} tokens)`,
282
- ];
283
- if (stats.totalFiles > 0) {
284
- const deferPercent = Math.round((stats.deferredCount / stats.totalFiles) * 100);
285
- lines.push(`**Defer Rate:** ${deferPercent}%`);
286
- }
287
- return lines.join('\n');
288
- }
289
- /**
290
- * Format threshold information for display
291
- */
292
- export function formatThresholdInfo(thresholds) {
293
- const t = thresholds || getFocusDeferThresholds();
294
- const lines = [
295
- '## Focus-Aware Thresholds',
296
- '',
297
- `- **In-focus:** ${t.inFocus} tokens`,
298
- `- **Near-focus:** ${t.nearFocus} tokens`,
299
- `- **Out-of-focus:** ${t.outOfFocus} tokens`,
300
- '',
301
- 'Files exceeding their threshold are deferred for lazy loading.',
302
- ];
303
- return lines.join('\n');
304
- }
305
- //# sourceMappingURL=focus-resource-loader.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"focus-resource-loader.js","sourceRoot":"","sources":["../../../src/core/context/focus-resource-loader.ts"],"names":[],"mappings":"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"}
@@ -1,74 +0,0 @@
1
- /**
2
- * Focus-Based Tool Filtering - v13.4.0
3
- *
4
- * Reduces context overhead by filtering tools based on current focus area.
5
- * Beyond phase-based filtering, tools are further filtered by focus relevance.
6
- *
7
- * Key features:
8
- * - Wildcard tag system: tools tagged with ['*'] always load
9
- * - Focus-aware mapping: tools tagged with focus areas only load when relevant
10
- * - Backward compatible: falls back to phase-only filtering if focus unavailable
11
- * - Feature-flagged: behind DINO_FOCUS_FILTERING environment variable
12
- *
13
- * Focus tags examples:
14
- * - ['*']: Always load (e.g., dino_status)
15
- * - ['mcp']: Load when focus is in src/mcp/ or .claude/
16
- * - ['core']: Load when focus is in src/core/
17
- * - ['commands']: Load when focus is in src/commands/
18
- * - ['test']: Load when focus is in test/ or .test/.spec
19
- *
20
- * Usage:
21
- * ```typescript
22
- * const filtered = filterToolsByFocus(tools, focusArea, phase);
23
- * ```
24
- */
25
- /**
26
- * Tool focus tag definition
27
- */
28
- export type ToolFocusTag = '*' | 'core' | 'mcp' | 'commands' | 'memory' | 'ralph' | 'agents' | 'analysis' | 'test' | 'rules' | 'skills';
29
- /**
30
- * Tool focus tag mapping
31
- * Maps tool names to focus tags that determine when they should be loaded
32
- */
33
- export declare const TOOL_FOCUS_TAGS: Record<string, ToolFocusTag[]>;
34
- /**
35
- * Map focus area to tool focus tags
36
- * Examples:
37
- * - 'src/mcp/' -> ['mcp']
38
- * - 'src/core/context/' -> ['core', 'memory']
39
- * - 'src/commands/' -> ['commands']
40
- * - 'test/' -> ['test']
41
- */
42
- export declare function extractFocusTags(focusArea: string): ToolFocusTag[];
43
- /**
44
- * Check if a tool should be loaded given the current focus
45
- */
46
- export declare function shouldLoadToolForFocus(toolName: string, focusTags: ToolFocusTag[]): boolean;
47
- /**
48
- * Filter tools by focus area
49
- * Only keeps tools that should be loaded for the current focus
50
- */
51
- export declare function filterToolsByFocus<T extends {
52
- name: string;
53
- }>(tools: T[], focusArea?: string): T[];
54
- /**
55
- * Check if focus-based filtering is enabled
56
- * Default: enabled (true)
57
- * Opt-out: DINO_FOCUS_FILTERING=false
58
- */
59
- export declare function isFocusFilteringEnabled(): boolean;
60
- /**
61
- * Get statistics about tool filtering
62
- */
63
- export declare function getFilterStats(allTools: string[], focusArea?: string): {
64
- total: number;
65
- filtered: number;
66
- reduction: number;
67
- percentageRemoved: number;
68
- focusTags: ToolFocusTag[];
69
- };
70
- /**
71
- * Format focus filter stats for display
72
- */
73
- export declare function formatFocusFilterStats(stats: ReturnType<typeof getFilterStats>): string;
74
- //# sourceMappingURL=focus-filter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"focus-filter.d.ts","sourceRoot":"","sources":["../../src/mcp/focus-filter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,GAAG,GAAG,MAAM,GAAG,KAAK,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;AAExI;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,CAqF1D,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,EAAE,CAoClE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,OAAO,CAe3F;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAC3D,KAAK,EAAE,CAAC,EAAE,EACV,SAAS,CAAC,EAAE,MAAM,GACjB,CAAC,EAAE,CAeL;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,CAEjD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAAE,EAClB,SAAS,CAAC,EAAE,MAAM,GACjB;IACD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B,CAmBA;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,GACvC,MAAM,CAWR"}