-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Expand file tree
/
Copy pathcheck-file-sizes.mjs
More file actions
181 lines (171 loc) · 7.16 KB
/
check-file-sizes.mjs
File metadata and controls
181 lines (171 loc) · 7.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
import { readFileSync, readdirSync } from "node:fs";
import { join, relative } from "node:path";
const DEFAULT_LIMIT = 500;
// Add narrowly scoped exceptions here with justification
const EXCEPTIONS = {
"src/features/sidebar/ui/SidebarProjectsSection.tsx": {
limit: 570,
justification:
"Drag-and-drop handlers for session-to-project moves and project reorder, plus activeProjectId highlight.",
},
"src/features/chat/ui/ChatView.tsx": {
limit: 570,
justification:
"ACP prewarm guards, project-aware working dir selection, working context sync, chat bootstrapping, context-ring compaction wiring, and gated [perf:chatview] logging via perfLog (dev-only by default).",
},
"src/features/chat/hooks/useChat.ts": {
limit: 510,
justification:
"Session preparation, provider/model handoff, persona-aware sends, cancellation, and compaction replay still live in one chat lifecycle hook.",
},
"src/shared/api/acpNotificationHandler.ts": {
limit: 550,
justification:
"ACP replay/live update handling, pending session buffering, model/config propagation, and streaming perf tracking still share one notification entrypoint.",
},
"src/features/chat/ui/__tests__/ContextPanel.test.tsx": {
limit: 550,
justification:
"Workspace widget integration tests cover branch switching, worktree creation, dirty-state dialogs, and picker interactions.",
},
"src/features/settings/ui/ModelProviderRow.tsx": {
limit: 515,
justification:
"Multi-line i18n calls for error messages (fieldsMissing interpolation, exhaustive useCallback deps) push marginally past 500. Splitting would create a thin wrapper with no structural benefit.",
},
"src/features/sidebar/ui/Sidebar.tsx": {
limit: 580,
justification:
"Search-as-you-type filtering and draft-aware sidebar highlight logic.",
},
"src/app/AppShell.tsx": {
limit: 780,
justification:
"Shell still coordinates ACP session loading, replay-buffer cleanup on load failure, project reassignment, home-session restoration, app-level chat routing, restored project-draft reuse, and app-level compaction settings deep links. Includes gated [perf:load]/[perf:newtab] logging via perfLog (dev-only by default).",
},
"src/features/chat/hooks/useChatSessionController.ts": {
limit: 840,
justification:
"Controller now centralizes home-to-chat pending state transfer, workspace/project preparation, provider/model/persona handoff, Goose cross-provider model selection sequencing with rollback, context-usage readiness resets, queued-target compaction gating, and auto-compaction-aware send orchestration pending a later decomposition pass.",
},
"src/features/chat/hooks/__tests__/useChatSessionController.test.ts": {
limit: 520,
justification:
"Controller regression coverage now spans model/provider rollback, stale usage resets, compact-before-send, and queued-persona auto-compaction support checks in one hook suite.",
},
"src/features/chat/stores/chatStore.ts": {
limit: 520,
justification:
"Chat runtime state, queued-message persistence, replay loading flags, and usage snapshot tracking still live together in one Zustand store.",
},
"src/features/chat/ui/AgentModelPicker.tsx": {
limit: 570,
justification:
"Agent-first picker currently keeps the full trigger, recommended-model view, searchable full-model view, and ACP/goose-specific labeling logic in one component pending later extraction.",
},
"src/features/chat/stores/__tests__/chatSessionStore.test.ts": {
limit: 540,
justification:
"ACP session overlay regressions currently need one broad integration-style store suite.",
},
"src/features/chat/stores/chatSessionStore.ts": {
limit: 640,
justification:
"ACP-backed session overlay persistence, draft migration, and sidebar-facing session merge logic live together for now.",
},
"src/features/chat/ui/ChatInput.tsx": {
limit: 510,
justification:
"Voice dictation send/stop guards, attachment handling, and mention/picker coordination still share one chat composer component.",
},
"src/features/chat/ui/MessageBubble.tsx": {
limit: 520,
justification:
"Bubble rendering still owns assistant identity, grouped tool output, attachments, and the inline actions tray pending a later extraction pass.",
},
"src/features/skills/ui/SkillsView.tsx": {
limit: 620,
justification:
"SkillsView currently centralizes list/detail state, project-aware skill hydration, category/source filtering, import/export flows, and detail-page action wiring pending a later decomposition.",
},
"src/features/chat/ui/__tests__/ChatInput.test.tsx": {
limit: 570,
justification:
"Composer regression coverage spans personas, queueing, attachments, voice-input edge cases, and the compaction popover/settings ingress in one interaction-heavy suite.",
},
"src-tauri/src/commands/projects.rs": {
limit: 520,
justification:
"Project CRUD plus reorder_projects command for sidebar drag-and-drop ordering.",
},
"src-tauri/src/commands/system.rs": {
limit: 640,
justification:
"Desktop system commands still centralize file mentions, attachment inspection, platform-aware path dedupe, guarded image loading, and export helpers in one Tauri command surface.",
},
};
// Directories excluded from size checks (imported library code)
const EXCLUDED_DIRS = [
"src/shared/ui",
"src/components/ai-elements",
"src/hooks",
];
const DIRS_TO_CHECK = [
{ dir: "src/app", glob: /\.[jt]sx?$/ },
{ dir: "src/features", glob: /\.[jt]sx?$/ },
{ dir: "src/shared", glob: /\.[jt]sx?$/ },
{ dir: "src/components", glob: /\.[jt]sx?$/ },
{ dir: "src/hooks", glob: /\.[jt]sx?$/ },
{ dir: "src-tauri/src", glob: /\.rs$/ },
];
function countLines(filePath) {
const content = readFileSync(filePath, "utf8");
return content.split("\n").length;
}
function isExcluded(filePath) {
const rel = relative(".", filePath);
return EXCLUDED_DIRS.some((dir) => rel.startsWith(dir));
}
function walkDir(dir, pattern) {
const results = [];
let entries;
try {
entries = readdirSync(dir, { withFileTypes: true });
} catch {
return results;
}
for (const entry of entries) {
const fullPath = join(dir, entry.name);
if (entry.isDirectory()) {
results.push(...walkDir(fullPath, pattern));
} else if (pattern.test(entry.name)) {
results.push(fullPath);
}
}
return results;
}
const violations = [];
for (const { dir, glob } of DIRS_TO_CHECK) {
const files = walkDir(dir, glob);
for (const file of files) {
if (isExcluded(file)) continue;
const rel = relative(".", file);
const limit = EXCEPTIONS[rel]?.limit ?? DEFAULT_LIMIT;
const lines = countLines(file);
if (lines > limit) {
violations.push({ file: rel, lines, limit });
}
}
}
if (violations.length > 0) {
console.error("Desktop file size check failed:");
for (const v of violations) {
console.error(` - ${v.file}: ${v.lines} lines (limit ${v.limit})`);
}
console.error(
"\nSplit the file or add a narrowly scoped exception in `scripts/check-file-sizes.mjs`.",
);
process.exit(1);
} else {
console.log("File size check passed.");
}