tangled
alpha
login
or
join now
dunkirk.sh
/
filter-college-spam
1
fork
atom
this repo has no description
1
fork
atom
overview
issues
pulls
pipelines
chore: feat
dunkirk.sh
3 months ago
1a4b8da6
2df1b30f
verified
This commit was signed with the committer's
known signature
.
dunkirk.sh
SSH Key Fingerprint:
SHA256:DqcG0RXYExE26KiWo3VxJnsxswN1QNfTBvB+bdSpk80=
+1180
-259
8 changed files
expand all
collapse all
unified
split
README.md
bun.lock
package.json
src
apps-script
Code.ts
appsscript.json
build-gas.ts
generate-gscript.ts
tsconfig.apps-script.json
+98
-63
README.md
···
13
13
# Run tests
14
14
bun test
15
15
16
16
-
# Evaluate classifier
17
17
-
bun run evaluate
16
16
+
# Build Google Apps Script
17
17
+
bun run gas build
18
18
19
19
-
# Generate GScript for Gmail
20
20
-
bun run generate-gscript
21
21
-
# → Creates build/filter-hybrid.gs
19
19
+
# Copy build/Code.gs and paste into Apps Script editor
20
20
+
# https://script.google.com
22
21
```
23
22
24
23
## What Gets Filtered vs Kept
···
43
42
44
43
## How It Works
45
44
46
46
-
1. **TypeScript Classifier** (`src/classifier.ts`) - Source of truth, rule-based patterns
47
47
-
2. **GScript Generator** (`src/generate-gscript.ts`) - Converts TS to Apps Script
48
48
-
3. **Gmail Automation** (`build/filter-hybrid.gs`) - Runs in Gmail every 10 minutes
49
49
-
50
50
-
### Architecture
45
45
+
**TypeScript → Google Apps Script Pipeline**
51
46
52
47
```
53
53
-
TypeScript Classifier (100% accurate patterns)
48
48
+
src/apps-script/Code.ts (TypeScript with type safety)
54
49
↓
55
55
-
GScript Generator
50
50
+
↓ bun run gas build (compile)
51
51
+
↓
52
52
+
build/Code.gs (Google Apps Script)
56
53
↓
57
57
-
Google Apps Script (build/filter-hybrid.gs)
54
54
+
↓ Manual copy/paste
58
55
↓
59
59
-
Gmail Auto-Filtering
56
56
+
Google Apps Script → Gmail Auto-Filtering
60
57
```
61
58
62
62
-
## Workflow for Improving the Classifier
59
59
+
## Gmail Deployment
60
60
+
61
61
+
```bash
62
62
+
# 1. Build
63
63
+
bun run gas build
64
64
+
65
65
+
# 2. Copy build/Code.gs contents
66
66
+
67
67
+
# 3. Paste into Google Apps Script
68
68
+
# https://script.google.com
69
69
+
70
70
+
# 4. Also paste scripts/export-from-label.gs
71
71
+
```
72
72
+
73
73
+
Once deployed:
74
74
+
1. Set `DRY_RUN = false` in the Apps Script editor
75
75
+
2. Run `setupTriggers()` to enable auto-filtering every 10 minutes
76
76
+
3. Run `ensureLabels()` to create required labels
77
77
+
78
78
+
## Development Workflow
79
79
+
80
80
+
### Improving the Classifier
63
81
64
82
See [docs/WORKFLOW.md](docs/WORKFLOW.md) for detailed instructions.
65
83
66
84
```bash
67
67
-
# 1. Export emails from Gmail (run in Apps Script console)
68
68
-
exportEmailsToDrive()
85
85
+
# 1. Export emails from Gmail
86
86
+
# Run exportEmailsToDrive() in Apps Script console
69
87
70
88
# 2. Label them interactively
71
89
bun run label new-emails.json
···
73
91
# 3. Import and evaluate
74
92
bun run import new-emails-labeled.json
75
93
76
76
-
# 4. If failures, update src/classifier.ts
94
94
+
# 4. Update patterns in src/apps-script/Code.ts
77
95
78
78
-
# 5. Test and deploy
96
96
+
# 5. Test locally
79
97
bun test
80
80
-
bun run generate-gscript
81
81
-
# Copy build/filter-hybrid.gs to Apps Script
98
98
+
99
99
+
# 6. Build and deploy
100
100
+
bun run gas build
101
101
+
# Copy build/Code.gs to Apps Script editor
82
102
```
103
103
+
104
104
+
### Adding New Patterns
105
105
+
106
106
+
1. Edit `src/apps-script/Code.ts` with type-safe TypeScript
107
107
+
2. Add tests in `src/classifier.test.ts`
108
108
+
3. Run `bun test` to verify
109
109
+
4. Build and deploy: `bun run gas build` then copy to Apps Script
110
110
+
111
111
+
**Note**: Keep `src/classifier.ts` (local testing) and `src/apps-script/Code.ts` (deployed) in sync manually.
83
112
84
113
## Project Structure
85
114
86
115
```
87
116
src/
88
88
-
classifier.ts - Main classifier logic (TypeScript)
117
117
+
apps-script/
118
118
+
Code.ts - Apps Script source (TypeScript)
119
119
+
appsscript.json - Apps Script manifest
120
120
+
classifier.ts - Core classifier (for local testing)
89
121
classifier.test.ts - Unit tests
90
90
-
types.ts - TypeScript types
91
91
-
evaluate.ts - Evaluation tool
92
92
-
generate-gscript.ts - TS → GScript generator
93
93
-
label.ts - Interactive labeling CLI
94
94
-
import-labeled.ts - Import labeled emails
122
122
+
types.ts - TypeScript types
123
123
+
evaluate.ts - Evaluation tool
124
124
+
label.ts - Interactive labeling CLI
125
125
+
import-labeled.ts - Import labeled emails
126
126
+
build-gas.ts - Build/deploy script
95
127
96
128
scripts/
97
97
-
export-from-label.gs - Export emails from Gmail
129
129
+
export-from-label.gs - Export emails from Gmail
98
130
99
99
-
build/ - Generated files (gitignored)
100
100
-
filter-hybrid.gs - Generated Gmail automation script
131
131
+
build/ - Generated (gitignored)
132
132
+
Code.gs - Compiled Apps Script
133
133
+
compiled/ - Intermediate JavaScript
101
134
102
135
data/
103
103
-
labeled-emails.json - Main labeled dataset (58 emails)
104
104
-
example-export.json - Example unlabeled export
136
136
+
labeled-emails.json - Main dataset (58 emails)
137
137
+
example-export.json - Example export
105
138
106
106
-
docs/
107
107
-
WORKFLOW.md - Detailed workflow guide
139
139
+
tsconfig.apps-script.json - TypeScript config for Apps Script
108
140
```
109
141
110
110
-
## Development
111
111
-
112
112
-
### Running Tests
142
142
+
## Commands
113
143
114
144
```bash
115
115
-
# Unit tests
116
116
-
bun test
145
145
+
# Testing & Evaluation
146
146
+
bun test - Run unit tests
147
147
+
bun run evaluate - Evaluate on labeled dataset
117
148
118
118
-
# Full evaluation on labeled dataset
119
119
-
bun run evaluate
149
149
+
# Apps Script Deployment
150
150
+
bun run gas build - Compile TypeScript → .gs
151
151
+
152
152
+
# Labeling Workflow
153
153
+
bun run label <file> - Label emails interactively
154
154
+
bun run import <file> - Import labeled emails to dataset
120
155
```
121
156
122
122
-
### Adding New Patterns
157
157
+
## TypeScript Compilation
123
158
124
124
-
1. Update `src/classifier.ts`
125
125
-
2. Add tests in `src/classifier.test.ts`
126
126
-
3. Run `bun test` to verify
127
127
-
4. Run `bun run generate-gscript` to update GScript
128
128
-
5. Deploy `build/filter-hybrid.gs` to Gmail Apps Script
159
159
+
Following [Google's official TypeScript guide](https://developers.google.com/apps-script/guides/typescript):
129
160
130
130
-
### Metrics
161
161
+
- **Type safety**: Full `@types/google-apps-script` support
162
162
+
- **Modern syntax**: ES6+ features (arrow functions, classes, etc.)
163
163
+
- **Local development**: Edit with VS Code autocomplete
164
164
+
- **Manual deployment**: Build locally, copy/paste to Apps Script
165
165
+
- **No bundler overhead**: Simple TypeScript → JavaScript compilation
131
166
132
132
-
- **Accuracy**: 100% (58/58 emails)
133
133
-
- **Precision**: 100% (no false positives)
134
134
-
- **Recall**: 100% (no false negatives)
135
135
-
- **F1 Score**: 100%
167
167
+
Configuration:
168
168
+
- `tsconfig.apps-script.json` - Targets ES2015, no modules
169
169
+
- `src/build-gas.ts` - Build script
136
170
137
137
-
## Gmail Deployment
171
171
+
## Metrics
138
172
139
139
-
1. Run `bun run generate-gscript`
140
140
-
2. Open [Google Apps Script](https://script.google.com)
141
141
-
3. Create new project
142
142
-
4. Copy contents of `build/filter-hybrid.gs`
143
143
-
5. Copy contents of `scripts/export-from-label.gs` (for exporting emails)
144
144
-
6. Set `DRY_RUN = false` when ready
145
145
-
7. Run `setupTriggers()` to enable auto-filtering
146
146
-
8. Run `ensureLabels()` to create required labels
173
173
+
- **Accuracy**: 100% (58/58 emails correctly classified)
174
174
+
- **Precision**: 100% (no false positives - no spam in inbox)
175
175
+
- **Recall**: 100% (no false negatives - all important emails reach inbox)
176
176
+
- **F1 Score**: 100%
147
177
148
178
## Requirements
149
179
150
150
-
- [Bun](https://bun.sh) runtime
180
180
+
- [Bun](https://bun.sh) - JavaScript runtime
151
181
- Gmail account
152
152
-
- Google Apps Script (for Gmail automation)
182
182
+
- Google account for Apps Script
153
183
154
184
## License
155
185
156
186
MIT
187
187
+
188
188
+
## References
189
189
+
190
190
+
- [Google Apps Script TypeScript Guide](https://developers.google.com/apps-script/guides/typescript)
191
191
+
- [@types/google-apps-script](https://www.npmjs.com/package/@types/google-apps-script)
+559
bun.lock
···
1
1
+
{
2
2
+
"lockfileVersion": 1,
3
3
+
"configVersion": 1,
4
4
+
"workspaces": {
5
5
+
"": {
6
6
+
"name": "filter-college-spam",
7
7
+
"dependencies": {
8
8
+
"@types/bun": "latest",
9
9
+
},
10
10
+
"devDependencies": {
11
11
+
"@google/clasp": "^3.1.3",
12
12
+
"@types/google-apps-script": "^2.0.8",
13
13
+
"ts2gas": "^4.2.0",
14
14
+
"typescript": "^5.9.3",
15
15
+
},
16
16
+
},
17
17
+
},
18
18
+
"packages": {
19
19
+
"@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
20
20
+
21
21
+
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
22
22
+
23
23
+
"@formatjs/ecma402-abstract": ["@formatjs/ecma402-abstract@2.3.6", "", { "dependencies": { "@formatjs/fast-memoize": "2.2.7", "@formatjs/intl-localematcher": "0.6.2", "decimal.js": "^10.4.3", "tslib": "^2.8.0" } }, "sha512-HJnTFeRM2kVFVr5gr5kH1XP6K0JcJtE7Lzvtr3FS/so5f1kpsqqqxy5JF+FRaO6H2qmcMfAUIox7AJteieRtVw=="],
24
24
+
25
25
+
"@formatjs/fast-memoize": ["@formatjs/fast-memoize@2.2.7", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ=="],
26
26
+
27
27
+
"@formatjs/icu-messageformat-parser": ["@formatjs/icu-messageformat-parser@2.11.4", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.6", "@formatjs/icu-skeleton-parser": "1.8.16", "tslib": "^2.8.0" } }, "sha512-7kR78cRrPNB4fjGFZg3Rmj5aah8rQj9KPzuLsmcSn4ipLXQvC04keycTI1F7kJYDwIXtT2+7IDEto842CfZBtw=="],
28
28
+
29
29
+
"@formatjs/icu-skeleton-parser": ["@formatjs/icu-skeleton-parser@1.8.16", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.6", "tslib": "^2.8.0" } }, "sha512-H13E9Xl+PxBd8D5/6TVUluSpxGNvFSlN/b3coUp0e0JpuWXXnQDiavIpY3NnvSp4xhEMoXyyBvVfdFX8jglOHQ=="],
30
30
+
31
31
+
"@formatjs/intl": ["@formatjs/intl@3.1.8", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.6", "@formatjs/fast-memoize": "2.2.7", "@formatjs/icu-messageformat-parser": "2.11.4", "intl-messageformat": "10.7.18", "tslib": "^2.8.0" }, "peerDependencies": { "typescript": "^5.6.0" }, "optionalPeers": ["typescript"] }, "sha512-LWXgwI5zTMatvR8w8kCNh/priDTOF/ZssokMBHJ7ZWXFoYLVOYo0EJERD9Eajv+xsfQO1QkuAt77KWQ1OI4mOQ=="],
32
32
+
33
33
+
"@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.6.2", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA=="],
34
34
+
35
35
+
"@google/clasp": ["@google/clasp@3.1.3", "", { "dependencies": { "@formatjs/intl": "^3.1.6", "@modelcontextprotocol/sdk": "^1.12.1", "chalk": "^5.4.1", "chokidar": "^4.0.3", "cli-truncate": "^4.0.0", "commander": "^13.1.0", "debug": "^4.4.0", "fdir": "^6.4.4", "find-up": "^7.0.0", "fuzzy": "^0.1.3", "google-auth-library": "^9.15.1", "googleapis": "^148.0.0", "googleapis-common": "7.2.0", "inflection": "^3.0.2", "inquirer": "^12.6.0", "inquirer-autocomplete-standalone": "^0.8.1", "loud-rejection": "^2.2.0", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "open": "^10.1.2", "ora": "^8.1.1", "p-map": "^7.0.3", "picomatch": "^4.0.2", "read-package-up": "^11.0.0", "server-destroy": "^1.0.1", "split-lines": "^3.0.0", "strip-bom": "^5.0.0", "zod": "^3.25.36" }, "bin": { "clasp": "build/src/index.js" } }, "sha512-+X4BaNlP4l3LvuuTHUKiKHJclZNmJuBRycZFZw/Z9FVZJqYmDCZKBm1hdVPPkvfP4Q6xtijKGC+4YZGwt97bJQ=="],
36
36
+
37
37
+
"@inquirer/ansi": ["@inquirer/ansi@1.0.2", "", {}, "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ=="],
38
38
+
39
39
+
"@inquirer/checkbox": ["@inquirer/checkbox@4.3.2", "", { "dependencies": { "@inquirer/ansi": "^1.0.2", "@inquirer/core": "^10.3.2", "@inquirer/figures": "^1.0.15", "@inquirer/type": "^3.0.10", "yoctocolors-cjs": "^2.1.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA=="],
40
40
+
41
41
+
"@inquirer/confirm": ["@inquirer/confirm@5.1.21", "", { "dependencies": { "@inquirer/core": "^10.3.2", "@inquirer/type": "^3.0.10" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ=="],
42
42
+
43
43
+
"@inquirer/core": ["@inquirer/core@10.3.2", "", { "dependencies": { "@inquirer/ansi": "^1.0.2", "@inquirer/figures": "^1.0.15", "@inquirer/type": "^3.0.10", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", "wrap-ansi": "^6.2.0", "yoctocolors-cjs": "^2.1.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A=="],
44
44
+
45
45
+
"@inquirer/editor": ["@inquirer/editor@4.2.23", "", { "dependencies": { "@inquirer/core": "^10.3.2", "@inquirer/external-editor": "^1.0.3", "@inquirer/type": "^3.0.10" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ=="],
46
46
+
47
47
+
"@inquirer/expand": ["@inquirer/expand@4.0.23", "", { "dependencies": { "@inquirer/core": "^10.3.2", "@inquirer/type": "^3.0.10", "yoctocolors-cjs": "^2.1.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew=="],
48
48
+
49
49
+
"@inquirer/external-editor": ["@inquirer/external-editor@1.0.3", "", { "dependencies": { "chardet": "^2.1.1", "iconv-lite": "^0.7.0" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA=="],
50
50
+
51
51
+
"@inquirer/figures": ["@inquirer/figures@1.0.15", "", {}, "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g=="],
52
52
+
53
53
+
"@inquirer/input": ["@inquirer/input@4.3.1", "", { "dependencies": { "@inquirer/core": "^10.3.2", "@inquirer/type": "^3.0.10" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g=="],
54
54
+
55
55
+
"@inquirer/number": ["@inquirer/number@3.0.23", "", { "dependencies": { "@inquirer/core": "^10.3.2", "@inquirer/type": "^3.0.10" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg=="],
56
56
+
57
57
+
"@inquirer/password": ["@inquirer/password@4.0.23", "", { "dependencies": { "@inquirer/ansi": "^1.0.2", "@inquirer/core": "^10.3.2", "@inquirer/type": "^3.0.10" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA=="],
58
58
+
59
59
+
"@inquirer/prompts": ["@inquirer/prompts@7.10.1", "", { "dependencies": { "@inquirer/checkbox": "^4.3.2", "@inquirer/confirm": "^5.1.21", "@inquirer/editor": "^4.2.23", "@inquirer/expand": "^4.0.23", "@inquirer/input": "^4.3.1", "@inquirer/number": "^3.0.23", "@inquirer/password": "^4.0.23", "@inquirer/rawlist": "^4.1.11", "@inquirer/search": "^3.2.2", "@inquirer/select": "^4.4.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg=="],
60
60
+
61
61
+
"@inquirer/rawlist": ["@inquirer/rawlist@4.1.11", "", { "dependencies": { "@inquirer/core": "^10.3.2", "@inquirer/type": "^3.0.10", "yoctocolors-cjs": "^2.1.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw=="],
62
62
+
63
63
+
"@inquirer/search": ["@inquirer/search@3.2.2", "", { "dependencies": { "@inquirer/core": "^10.3.2", "@inquirer/figures": "^1.0.15", "@inquirer/type": "^3.0.10", "yoctocolors-cjs": "^2.1.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA=="],
64
64
+
65
65
+
"@inquirer/select": ["@inquirer/select@4.4.2", "", { "dependencies": { "@inquirer/ansi": "^1.0.2", "@inquirer/core": "^10.3.2", "@inquirer/figures": "^1.0.15", "@inquirer/type": "^3.0.10", "yoctocolors-cjs": "^2.1.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w=="],
66
66
+
67
67
+
"@inquirer/type": ["@inquirer/type@3.0.10", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA=="],
68
68
+
69
69
+
"@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.24.3", "", { "dependencies": { "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "jose": "^6.1.1", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.0" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-YgSHW29fuzKKAHTGe9zjNoo+yF8KaQPzDC2W9Pv41E7/57IfY+AMGJ/aDFlgTLcVVELoggKE4syABCE75u3NCw=="],
70
70
+
71
71
+
"@types/bun": ["@types/bun@1.3.3", "", { "dependencies": { "bun-types": "1.3.3" } }, "sha512-ogrKbJ2X5N0kWLLFKeytG0eHDleBYtngtlbu9cyBKFtNL3cnpDZkNdQj8flVf6WTZUX5ulI9AY1oa7ljhSrp+g=="],
72
72
+
73
73
+
"@types/google-apps-script": ["@types/google-apps-script@2.0.8", "", {}, "sha512-mGPmzzdgBu1DlwrjOhFQ8u0se6AF/z4OpaTzOGwNKxwXZjE7J+IssfE3oL24j/S/p6aFiSTIptHZvbyqeZD8vA=="],
74
74
+
75
75
+
"@types/mute-stream": ["@types/mute-stream@0.0.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-0yQLzYhCqGz7CQPE3iDmYjhb7KMBFOP+tBkyw+/Y2YyDI5wpS7itXXxneN1zSsUwWx3Ji6YiVYrhAnpQGS/vkw=="],
76
76
+
77
77
+
"@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="],
78
78
+
79
79
+
"@types/normalize-package-data": ["@types/normalize-package-data@2.4.4", "", {}, "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="],
80
80
+
81
81
+
"@types/wrap-ansi": ["@types/wrap-ansi@3.0.0", "", {}, "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g=="],
82
82
+
83
83
+
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
84
84
+
85
85
+
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
86
86
+
87
87
+
"ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
88
88
+
89
89
+
"ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="],
90
90
+
91
91
+
"ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="],
92
92
+
93
93
+
"ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
94
94
+
95
95
+
"ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
96
96
+
97
97
+
"array-find-index": ["array-find-index@1.0.2", "", {}, "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw=="],
98
98
+
99
99
+
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
100
100
+
101
101
+
"bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="],
102
102
+
103
103
+
"body-parser": ["body-parser@2.2.1", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw=="],
104
104
+
105
105
+
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
106
106
+
107
107
+
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
108
108
+
109
109
+
"bun-types": ["bun-types@1.3.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-z3Xwlg7j2l9JY27x5Qn3Wlyos8YAp0kKRlrePAOjgjMGS5IG6E7Jnlx736vH9UVI4wUICwwhC9anYL++XeOgTQ=="],
110
110
+
111
111
+
"bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="],
112
112
+
113
113
+
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
114
114
+
115
115
+
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
116
116
+
117
117
+
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
118
118
+
119
119
+
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
120
120
+
121
121
+
"chardet": ["chardet@2.1.1", "", {}, "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ=="],
122
122
+
123
123
+
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
124
124
+
125
125
+
"cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="],
126
126
+
127
127
+
"cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="],
128
128
+
129
129
+
"cli-truncate": ["cli-truncate@4.0.0", "", { "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^7.0.0" } }, "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA=="],
130
130
+
131
131
+
"cli-width": ["cli-width@4.1.0", "", {}, "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ=="],
132
132
+
133
133
+
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
134
134
+
135
135
+
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
136
136
+
137
137
+
"commander": ["commander@13.1.0", "", {}, "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw=="],
138
138
+
139
139
+
"content-disposition": ["content-disposition@1.0.1", "", {}, "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q=="],
140
140
+
141
141
+
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
142
142
+
143
143
+
"cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
144
144
+
145
145
+
"cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
146
146
+
147
147
+
"cors": ["cors@2.8.5", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="],
148
148
+
149
149
+
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
150
150
+
151
151
+
"currently-unhandled": ["currently-unhandled@0.4.1", "", { "dependencies": { "array-find-index": "^1.0.1" } }, "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng=="],
152
152
+
153
153
+
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
154
154
+
155
155
+
"decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="],
156
156
+
157
157
+
"default-browser": ["default-browser@5.4.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg=="],
158
158
+
159
159
+
"default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="],
160
160
+
161
161
+
"define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="],
162
162
+
163
163
+
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
164
164
+
165
165
+
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
166
166
+
167
167
+
"ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
168
168
+
169
169
+
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
170
170
+
171
171
+
"emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
172
172
+
173
173
+
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
174
174
+
175
175
+
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
176
176
+
177
177
+
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
178
178
+
179
179
+
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
180
180
+
181
181
+
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
182
182
+
183
183
+
"escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
184
184
+
185
185
+
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
186
186
+
187
187
+
"eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="],
188
188
+
189
189
+
"eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="],
190
190
+
191
191
+
"express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="],
192
192
+
193
193
+
"express-rate-limit": ["express-rate-limit@7.5.1", "", { "peerDependencies": { "express": ">= 4.11" } }, "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw=="],
194
194
+
195
195
+
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
196
196
+
197
197
+
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
198
198
+
199
199
+
"fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="],
200
200
+
201
201
+
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
202
202
+
203
203
+
"figures": ["figures@5.0.0", "", { "dependencies": { "escape-string-regexp": "^5.0.0", "is-unicode-supported": "^1.2.0" } }, "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg=="],
204
204
+
205
205
+
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
206
206
+
207
207
+
"finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="],
208
208
+
209
209
+
"find-up": ["find-up@7.0.0", "", { "dependencies": { "locate-path": "^7.2.0", "path-exists": "^5.0.0", "unicorn-magic": "^0.1.0" } }, "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g=="],
210
210
+
211
211
+
"find-up-simple": ["find-up-simple@1.0.1", "", {}, "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ=="],
212
212
+
213
213
+
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
214
214
+
215
215
+
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
216
216
+
217
217
+
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
218
218
+
219
219
+
"fuzzy": ["fuzzy@0.1.3", "", {}, "sha512-/gZffu4ykarLrCiP3Ygsa86UAo1E5vEVlvTrpkKywXSbP9Xhln3oSp9QSV57gEq3JFFpGJ4GZ+5zdEp3FcUh4w=="],
220
220
+
221
221
+
"gaxios": ["gaxios@6.7.1", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", "node-fetch": "^2.6.9", "uuid": "^9.0.1" } }, "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ=="],
222
222
+
223
223
+
"gcp-metadata": ["gcp-metadata@6.1.1", "", { "dependencies": { "gaxios": "^6.1.1", "google-logging-utils": "^0.0.2", "json-bigint": "^1.0.0" } }, "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A=="],
224
224
+
225
225
+
"get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="],
226
226
+
227
227
+
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
228
228
+
229
229
+
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
230
230
+
231
231
+
"google-auth-library": ["google-auth-library@9.15.1", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^6.1.1", "gcp-metadata": "^6.1.0", "gtoken": "^7.0.0", "jws": "^4.0.0" } }, "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng=="],
232
232
+
233
233
+
"google-logging-utils": ["google-logging-utils@0.0.2", "", {}, "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ=="],
234
234
+
235
235
+
"googleapis": ["googleapis@148.0.0", "", { "dependencies": { "google-auth-library": "^9.0.0", "googleapis-common": "^7.0.0" } }, "sha512-8PDG5VItm6E1TdZWDqtRrUJSlBcNwz0/MwCa6AL81y/RxPGXJRUwKqGZfCoVX1ZBbfr3I4NkDxBmeTyOAZSWqw=="],
236
236
+
237
237
+
"googleapis-common": ["googleapis-common@7.2.0", "", { "dependencies": { "extend": "^3.0.2", "gaxios": "^6.0.3", "google-auth-library": "^9.7.0", "qs": "^6.7.0", "url-template": "^2.0.8", "uuid": "^9.0.0" } }, "sha512-/fhDZEJZvOV3X5jmD+fKxMqma5q2Q9nZNSF3kn1F18tpxmA86BcTxAGBQdM0N89Z3bEaIs+HVznSmFJEAmMTjA=="],
238
238
+
239
239
+
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
240
240
+
241
241
+
"gtoken": ["gtoken@7.1.0", "", { "dependencies": { "gaxios": "^6.0.0", "jws": "^4.0.0" } }, "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw=="],
242
242
+
243
243
+
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
244
244
+
245
245
+
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
246
246
+
247
247
+
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
248
248
+
249
249
+
"hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="],
250
250
+
251
251
+
"http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="],
252
252
+
253
253
+
"https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
254
254
+
255
255
+
"iconv-lite": ["iconv-lite@0.7.0", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ=="],
256
256
+
257
257
+
"index-to-position": ["index-to-position@1.2.0", "", {}, "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw=="],
258
258
+
259
259
+
"inflection": ["inflection@3.0.2", "", {}, "sha512-+Bg3+kg+J6JUWn8J6bzFmOWkTQ6L/NHfDRSYU+EVvuKHDxUDHAXgqixHfVlzuBQaPOTac8hn43aPhMNk6rMe3g=="],
260
260
+
261
261
+
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
262
262
+
263
263
+
"inquirer": ["inquirer@12.11.1", "", { "dependencies": { "@inquirer/ansi": "^1.0.2", "@inquirer/core": "^10.3.2", "@inquirer/prompts": "^7.10.1", "@inquirer/type": "^3.0.10", "mute-stream": "^2.0.0", "run-async": "^4.0.6", "rxjs": "^7.8.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-9VF7mrY+3OmsAfjH3yKz/pLbJ5z22E23hENKw3/LNSaA/sAt3v49bDRY+Ygct1xwuKT+U+cBfTzjCPySna69Qw=="],
264
264
+
265
265
+
"inquirer-autocomplete-standalone": ["inquirer-autocomplete-standalone@0.8.1", "", { "dependencies": { "@inquirer/core": "^3.1.1", "@inquirer/type": "^1.1.2", "figures": "^5.0.0", "picocolors": "^1.0.0" } }, "sha512-mlzwCTiXDX1Cw4yJL5PCq32k23XYLTK8K6BDFoL1a76iJeFB5ul6IoMU9spgdDagl2SM7P6ZaCNjj8VNXRDPOQ=="],
266
266
+
267
267
+
"intl-messageformat": ["intl-messageformat@10.7.18", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.6", "@formatjs/fast-memoize": "2.2.7", "@formatjs/icu-messageformat-parser": "2.11.4", "tslib": "^2.8.0" } }, "sha512-m3Ofv/X/tV8Y3tHXLohcuVuhWKo7BBq62cqY15etqmLxg2DZ34AGGgQDeR+SCta2+zICb1NX83af0GJmbQ1++g=="],
268
268
+
269
269
+
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
270
270
+
271
271
+
"is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="],
272
272
+
273
273
+
"is-fullwidth-code-point": ["is-fullwidth-code-point@4.0.0", "", {}, "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ=="],
274
274
+
275
275
+
"is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="],
276
276
+
277
277
+
"is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="],
278
278
+
279
279
+
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
280
280
+
281
281
+
"is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
282
282
+
283
283
+
"is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
284
284
+
285
285
+
"is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="],
286
286
+
287
287
+
"is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="],
288
288
+
289
289
+
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
290
290
+
291
291
+
"jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="],
292
292
+
293
293
+
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
294
294
+
295
295
+
"json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="],
296
296
+
297
297
+
"json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
298
298
+
299
299
+
"jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="],
300
300
+
301
301
+
"jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="],
302
302
+
303
303
+
"locate-path": ["locate-path@7.2.0", "", { "dependencies": { "p-locate": "^6.0.0" } }, "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA=="],
304
304
+
305
305
+
"log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="],
306
306
+
307
307
+
"loud-rejection": ["loud-rejection@2.2.0", "", { "dependencies": { "currently-unhandled": "^0.4.1", "signal-exit": "^3.0.2" } }, "sha512-S0FayMXku80toa5sZ6Ro4C+s+EtFDCsyJNG/AzFMfX3AxD5Si4dZsgzm/kKnbOxHl5Cv8jBlno8+3XYIh2pNjQ=="],
308
308
+
309
309
+
"lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
310
310
+
311
311
+
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
312
312
+
313
313
+
"media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
314
314
+
315
315
+
"merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
316
316
+
317
317
+
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
318
318
+
319
319
+
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
320
320
+
321
321
+
"mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="],
322
322
+
323
323
+
"mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
324
324
+
325
325
+
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
326
326
+
327
327
+
"mute-stream": ["mute-stream@2.0.0", "", {}, "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA=="],
328
328
+
329
329
+
"negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
330
330
+
331
331
+
"node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
332
332
+
333
333
+
"normalize-package-data": ["normalize-package-data@6.0.2", "", { "dependencies": { "hosted-git-info": "^7.0.0", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4" } }, "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g=="],
334
334
+
335
335
+
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
336
336
+
337
337
+
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
338
338
+
339
339
+
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
340
340
+
341
341
+
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
342
342
+
343
343
+
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
344
344
+
345
345
+
"onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
346
346
+
347
347
+
"open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="],
348
348
+
349
349
+
"ora": ["ora@8.2.0", "", { "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^5.0.0", "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.0.0", "log-symbols": "^6.0.0", "stdin-discarder": "^0.2.2", "string-width": "^7.2.0", "strip-ansi": "^7.1.0" } }, "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw=="],
350
350
+
351
351
+
"p-limit": ["p-limit@4.0.0", "", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ=="],
352
352
+
353
353
+
"p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="],
354
354
+
355
355
+
"p-map": ["p-map@7.0.4", "", {}, "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ=="],
356
356
+
357
357
+
"parse-json": ["parse-json@8.3.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "index-to-position": "^1.1.0", "type-fest": "^4.39.1" } }, "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ=="],
358
358
+
359
359
+
"parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
360
360
+
361
361
+
"path-exists": ["path-exists@5.0.0", "", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="],
362
362
+
363
363
+
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
364
364
+
365
365
+
"path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="],
366
366
+
367
367
+
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
368
368
+
369
369
+
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
370
370
+
371
371
+
"pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="],
372
372
+
373
373
+
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
374
374
+
375
375
+
"qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="],
376
376
+
377
377
+
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
378
378
+
379
379
+
"raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="],
380
380
+
381
381
+
"read-package-up": ["read-package-up@11.0.0", "", { "dependencies": { "find-up-simple": "^1.0.0", "read-pkg": "^9.0.0", "type-fest": "^4.6.0" } }, "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ=="],
382
382
+
383
383
+
"read-pkg": ["read-pkg@9.0.1", "", { "dependencies": { "@types/normalize-package-data": "^2.4.3", "normalize-package-data": "^6.0.0", "parse-json": "^8.0.0", "type-fest": "^4.6.0", "unicorn-magic": "^0.1.0" } }, "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA=="],
384
384
+
385
385
+
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
386
386
+
387
387
+
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
388
388
+
389
389
+
"restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="],
390
390
+
391
391
+
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
392
392
+
393
393
+
"run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="],
394
394
+
395
395
+
"run-async": ["run-async@4.0.6", "", {}, "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ=="],
396
396
+
397
397
+
"rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="],
398
398
+
399
399
+
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
400
400
+
401
401
+
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
402
402
+
403
403
+
"semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
404
404
+
405
405
+
"send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="],
406
406
+
407
407
+
"serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="],
408
408
+
409
409
+
"server-destroy": ["server-destroy@1.0.1", "", {}, "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ=="],
410
410
+
411
411
+
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
412
412
+
413
413
+
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
414
414
+
415
415
+
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
416
416
+
417
417
+
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
418
418
+
419
419
+
"side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
420
420
+
421
421
+
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
422
422
+
423
423
+
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
424
424
+
425
425
+
"signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
426
426
+
427
427
+
"slice-ansi": ["slice-ansi@5.0.0", "", { "dependencies": { "ansi-styles": "^6.0.0", "is-fullwidth-code-point": "^4.0.0" } }, "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ=="],
428
428
+
429
429
+
"spdx-correct": ["spdx-correct@3.2.0", "", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA=="],
430
430
+
431
431
+
"spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="],
432
432
+
433
433
+
"spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="],
434
434
+
435
435
+
"spdx-license-ids": ["spdx-license-ids@3.0.22", "", {}, "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ=="],
436
436
+
437
437
+
"split-lines": ["split-lines@3.0.0", "", {}, "sha512-d0TpRBL/VfKDXsk8JxPF7zgF5pCUDdBMSlEL36xBgVeaX448t+yGXcJaikUyzkoKOJ0l6KpMfygzJU9naIuivw=="],
438
438
+
439
439
+
"statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
440
440
+
441
441
+
"stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="],
442
442
+
443
443
+
"string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
444
444
+
445
445
+
"strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
446
446
+
447
447
+
"strip-bom": ["strip-bom@5.0.0", "", {}, "sha512-p+byADHF7SzEcVnLvc/r3uognM1hUhObuHXxJcgLCfD194XAkaLbjq3Wzb0N5G2tgIjH0dgT708Z51QxMeu60A=="],
448
448
+
449
449
+
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
450
450
+
451
451
+
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
452
452
+
453
453
+
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
454
454
+
455
455
+
"tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
456
456
+
457
457
+
"ts2gas": ["ts2gas@4.2.0", "", { "dependencies": { "type-fest": "^2.1.0", "typescript": "^4.4.2" } }, "sha512-5xZugaeM3wKQPj/vrWnrtYjNh4xnIz6cGSW/smCe9OTmkh1+KvHpm7M7HLq/OnBaljf4+yKctC4AYimBi4T1/Q=="],
458
458
+
459
459
+
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
460
460
+
461
461
+
"type-fest": ["type-fest@2.19.0", "", {}, "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="],
462
462
+
463
463
+
"type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
464
464
+
465
465
+
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
466
466
+
467
467
+
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
468
468
+
469
469
+
"unicorn-magic": ["unicorn-magic@0.1.0", "", {}, "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ=="],
470
470
+
471
471
+
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
472
472
+
473
473
+
"url-template": ["url-template@2.0.8", "", {}, "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw=="],
474
474
+
475
475
+
"uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
476
476
+
477
477
+
"validate-npm-package-license": ["validate-npm-package-license@3.0.4", "", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="],
478
478
+
479
479
+
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
480
480
+
481
481
+
"webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
482
482
+
483
483
+
"whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
484
484
+
485
485
+
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
486
486
+
487
487
+
"wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="],
488
488
+
489
489
+
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
490
490
+
491
491
+
"wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="],
492
492
+
493
493
+
"yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="],
494
494
+
495
495
+
"yoctocolors-cjs": ["yoctocolors-cjs@2.1.3", "", {}, "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw=="],
496
496
+
497
497
+
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
498
498
+
499
499
+
"zod-to-json-schema": ["zod-to-json-schema@3.25.0", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ=="],
500
500
+
501
501
+
"@inquirer/core/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
502
502
+
503
503
+
"ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="],
504
504
+
505
505
+
"figures/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="],
506
506
+
507
507
+
"inquirer-autocomplete-standalone/@inquirer/core": ["@inquirer/core@3.1.2", "", { "dependencies": { "@inquirer/type": "^1.1.2", "@types/mute-stream": "^0.0.1", "@types/node": "^20.4.8", "@types/wrap-ansi": "^3.0.0", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", "cli-spinners": "^2.9.0", "cli-width": "^4.1.0", "figures": "^3.2.0", "mute-stream": "^1.0.0", "run-async": "^3.0.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^6.2.0" } }, "sha512-lR2GaqBkp42Ew9BOAOqf2pSp+ymVES1qN8OC90WWh45yeoYLl0Ty1GyCxmkKqBJtq/+Ea1MF12AdFcZcpRNFsw=="],
508
508
+
509
509
+
"inquirer-autocomplete-standalone/@inquirer/type": ["@inquirer/type@1.5.5", "", { "dependencies": { "mute-stream": "^1.0.0" } }, "sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA=="],
510
510
+
511
511
+
"log-symbols/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="],
512
512
+
513
513
+
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
514
514
+
515
515
+
"parse-json/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
516
516
+
517
517
+
"read-package-up/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
518
518
+
519
519
+
"read-pkg/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
520
520
+
521
521
+
"restore-cursor/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
522
522
+
523
523
+
"ts2gas/typescript": ["typescript@4.9.5", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g=="],
524
524
+
525
525
+
"wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
526
526
+
527
527
+
"wrap-ansi/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
528
528
+
529
529
+
"wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
530
530
+
531
531
+
"inquirer-autocomplete-standalone/@inquirer/core/@types/node": ["@types/node@20.19.25", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ=="],
532
532
+
533
533
+
"inquirer-autocomplete-standalone/@inquirer/core/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
534
534
+
535
535
+
"inquirer-autocomplete-standalone/@inquirer/core/figures": ["figures@3.2.0", "", { "dependencies": { "escape-string-regexp": "^1.0.5" } }, "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg=="],
536
536
+
537
537
+
"inquirer-autocomplete-standalone/@inquirer/core/mute-stream": ["mute-stream@1.0.0", "", {}, "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA=="],
538
538
+
539
539
+
"inquirer-autocomplete-standalone/@inquirer/core/run-async": ["run-async@3.0.0", "", {}, "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q=="],
540
540
+
541
541
+
"inquirer-autocomplete-standalone/@inquirer/core/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
542
542
+
543
543
+
"inquirer-autocomplete-standalone/@inquirer/type/mute-stream": ["mute-stream@1.0.0", "", {}, "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA=="],
544
544
+
545
545
+
"wrap-ansi/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
546
546
+
547
547
+
"wrap-ansi/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
548
548
+
549
549
+
"wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
550
550
+
551
551
+
"inquirer-autocomplete-standalone/@inquirer/core/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
552
552
+
553
553
+
"inquirer-autocomplete-standalone/@inquirer/core/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
554
554
+
555
555
+
"inquirer-autocomplete-standalone/@inquirer/core/figures/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
556
556
+
557
557
+
"inquirer-autocomplete-standalone/@inquirer/core/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
558
558
+
}
559
559
+
}
+7
-1
package.json
···
6
6
"scripts": {
7
7
"test": "bun test src/classifier.test.ts",
8
8
"evaluate": "bun src/evaluate.ts data/labeled-emails.json",
9
9
-
"generate-gscript": "bun src/generate-gscript.ts",
9
9
+
"gas": "bun src/build-gas.ts",
10
10
"label": "bun src/label.ts",
11
11
"import": "bun src/import-labeled.ts"
12
12
},
13
13
"dependencies": {
14
14
"@types/bun": "latest"
15
15
+
},
16
16
+
"devDependencies": {
17
17
+
"@google/clasp": "^3.1.3",
18
18
+
"@types/google-apps-script": "^2.0.8",
19
19
+
"ts2gas": "^4.2.0",
20
20
+
"typescript": "^5.9.3"
15
21
}
16
22
}
+441
src/apps-script/Code.ts
···
1
1
+
// Apps Script classifier - compiled from TypeScript
2
2
+
// This file is the source of truth for Gmail filtering logic
3
3
+
4
4
+
// Configuration
5
5
+
const AUTO_LABEL_NAME = "College/Auto";
6
6
+
const FILTERED_LABEL_NAME = "College/Filtered";
7
7
+
const APPROVED_LABEL_NAME = "College";
8
8
+
const DRY_RUN = true;
9
9
+
10
10
+
const AI_BASE_URL = "https://ai.hackclub.com/proxy/v1/chat/completions";
11
11
+
const AI_MODEL = "deepseek/deepseek-r1-distill-qwen-32b";
12
12
+
13
13
+
const MAX_THREADS_PER_RUN = 75;
14
14
+
const MAX_EXECUTION_TIME_MS = 4.5 * 60 * 1000;
15
15
+
const GMAIL_BATCH_SIZE = 20;
16
16
+
const AI_CONFIDENCE_THRESHOLD = 0.5;
17
17
+
18
18
+
// Main entry points
19
19
+
function ensureLabels(): void {
20
20
+
getOrCreateLabel(AUTO_LABEL_NAME);
21
21
+
getOrCreateLabel(FILTERED_LABEL_NAME);
22
22
+
getOrCreateLabel(APPROVED_LABEL_NAME);
23
23
+
Logger.log(`Labels ensured: ${AUTO_LABEL_NAME}, ${FILTERED_LABEL_NAME}, ${APPROVED_LABEL_NAME}`);
24
24
+
}
25
25
+
26
26
+
function runTriage(): void {
27
27
+
const startTime = Date.now();
28
28
+
const autoLabel = getOrCreateLabel(AUTO_LABEL_NAME);
29
29
+
const filteredLabel = getOrCreateLabel(FILTERED_LABEL_NAME);
30
30
+
const approvedLabel = getOrCreateLabel(APPROVED_LABEL_NAME);
31
31
+
32
32
+
const threads = autoLabel.getThreads(0, MAX_THREADS_PER_RUN);
33
33
+
if (!threads.length) {
34
34
+
Logger.log("No threads under College/Auto.");
35
35
+
return;
36
36
+
}
37
37
+
38
38
+
Logger.log(`Processing ${threads.length} threads`);
39
39
+
40
40
+
let stats = {
41
41
+
wouldInbox: 0,
42
42
+
wouldFiltered: 0,
43
43
+
didInbox: 0,
44
44
+
didFiltered: 0,
45
45
+
errors: 0,
46
46
+
skipped: 0
47
47
+
};
48
48
+
49
49
+
for (let i = 0; i < threads.length; i++) {
50
50
+
const elapsed = Date.now() - startTime;
51
51
+
if (elapsed > MAX_EXECUTION_TIME_MS) {
52
52
+
Logger.log(`Time limit reached. Processed ${i}/${threads.length}`);
53
53
+
stats.skipped = threads.length - i;
54
54
+
break;
55
55
+
}
56
56
+
57
57
+
const thread = threads[i];
58
58
+
59
59
+
try {
60
60
+
processThread(thread, autoLabel, approvedLabel, filteredLabel, stats);
61
61
+
} catch (e) {
62
62
+
Logger.log(`ERROR: ${e}. FAIL-SAFE: Moving to inbox.`);
63
63
+
stats.errors += 1;
64
64
+
65
65
+
if (!DRY_RUN) {
66
66
+
thread.removeLabel(autoLabel);
67
67
+
thread.removeLabel(filteredLabel);
68
68
+
thread.moveToInbox();
69
69
+
stats.didInbox += 1;
70
70
+
} else {
71
71
+
stats.wouldInbox += 1;
72
72
+
}
73
73
+
}
74
74
+
75
75
+
if ((i + 1) % GMAIL_BATCH_SIZE === 0) {
76
76
+
Utilities.sleep(100);
77
77
+
}
78
78
+
}
79
79
+
80
80
+
const totalTime = ((Date.now() - startTime) / 1000).toFixed(2);
81
81
+
Logger.log(`Summary: Inbox=${stats.wouldInbox}/${stats.didInbox}, Filtered=${stats.wouldFiltered}/${stats.didFiltered}, Errors=${stats.errors}, Time=${totalTime}s`);
82
82
+
}
83
83
+
84
84
+
function processThread(
85
85
+
thread: GoogleAppsScript.Gmail.GmailThread,
86
86
+
autoLabel: GoogleAppsScript.Gmail.GmailLabel,
87
87
+
approvedLabel: GoogleAppsScript.Gmail.GmailLabel,
88
88
+
filteredLabel: GoogleAppsScript.Gmail.GmailLabel,
89
89
+
stats: any
90
90
+
): void {
91
91
+
const msg = thread.getMessages()[thread.getMessages().length - 1];
92
92
+
if (!msg) throw new Error("No messages in thread");
93
93
+
94
94
+
const meta = {
95
95
+
subject: safeStr(msg.getSubject()),
96
96
+
body: safeStr(msg.getPlainBody(), 10000),
97
97
+
from: safeStr(msg.getFrom()),
98
98
+
};
99
99
+
100
100
+
if (!meta.subject && !meta.body) {
101
101
+
Logger.log(`WARNING: No content. FAIL-SAFE: Moving to inbox.`);
102
102
+
applyInboxAction(thread, autoLabel, approvedLabel, filteredLabel, stats, "no content");
103
103
+
return;
104
104
+
}
105
105
+
106
106
+
const result = classifyEmail(meta);
107
107
+
108
108
+
Logger.log(`[${thread.getId()}] Relevant=${result.pertains} Confidence=${result.confidence} Reason="${result.reason}"`);
109
109
+
110
110
+
if (result.pertains) {
111
111
+
applyInboxAction(thread, autoLabel, approvedLabel, filteredLabel, stats, result.reason);
112
112
+
} else {
113
113
+
applyFilteredAction(thread, autoLabel, filteredLabel, stats, result.reason);
114
114
+
}
115
115
+
}
116
116
+
117
117
+
function applyInboxAction(
118
118
+
thread: GoogleAppsScript.Gmail.GmailThread,
119
119
+
autoLabel: GoogleAppsScript.Gmail.GmailLabel,
120
120
+
approvedLabel: GoogleAppsScript.Gmail.GmailLabel,
121
121
+
filteredLabel: GoogleAppsScript.Gmail.GmailLabel,
122
122
+
stats: any,
123
123
+
reason: string
124
124
+
): void {
125
125
+
if (DRY_RUN) {
126
126
+
stats.wouldInbox += 1;
127
127
+
Logger.log(` DRY_RUN: Would move to Inbox (${reason})`);
128
128
+
} else {
129
129
+
thread.removeLabel(autoLabel);
130
130
+
thread.removeLabel(filteredLabel);
131
131
+
thread.addLabel(approvedLabel);
132
132
+
thread.moveToInbox();
133
133
+
stats.didInbox += 1;
134
134
+
Logger.log(` Applied: Moved to Inbox (${reason})`);
135
135
+
}
136
136
+
}
137
137
+
138
138
+
function applyFilteredAction(
139
139
+
thread: GoogleAppsScript.Gmail.GmailThread,
140
140
+
autoLabel: GoogleAppsScript.Gmail.GmailLabel,
141
141
+
filteredLabel: GoogleAppsScript.Gmail.GmailLabel,
142
142
+
stats: any,
143
143
+
reason: string
144
144
+
): void {
145
145
+
if (DRY_RUN) {
146
146
+
stats.wouldFiltered += 1;
147
147
+
Logger.log(` DRY_RUN: Would filter (${reason})`);
148
148
+
} else {
149
149
+
thread.removeLabel(autoLabel);
150
150
+
thread.addLabel(filteredLabel);
151
151
+
if (thread.isInInbox()) thread.moveToArchive();
152
152
+
stats.didFiltered += 1;
153
153
+
Logger.log(` Applied: Filtered (${reason})`);
154
154
+
}
155
155
+
}
156
156
+
157
157
+
// Classifier
158
158
+
interface ClassificationResult {
159
159
+
pertains: boolean;
160
160
+
reason: string;
161
161
+
confidence: number;
162
162
+
}
163
163
+
164
164
+
interface EmailMeta {
165
165
+
subject: string;
166
166
+
body: string;
167
167
+
from: string;
168
168
+
}
169
169
+
170
170
+
function classifyEmail(meta: EmailMeta): ClassificationResult {
171
171
+
const subject = meta.subject.toLowerCase();
172
172
+
const body = meta.body.toLowerCase();
173
173
+
const combined = subject + " " + body;
174
174
+
175
175
+
// Security alerts - always relevant
176
176
+
const securityResult = checkSecurity(combined);
177
177
+
if (securityResult) return securityResult;
178
178
+
179
179
+
// Student action confirmations
180
180
+
const actionResult = checkStudentAction(combined);
181
181
+
if (actionResult) return actionResult;
182
182
+
183
183
+
// Accepted student info
184
184
+
const acceptedResult = checkAccepted(combined);
185
185
+
if (acceptedResult) return acceptedResult;
186
186
+
187
187
+
// Dual enrollment
188
188
+
const dualResult = checkDualEnrollment(combined);
189
189
+
if (dualResult) return dualResult;
190
190
+
191
191
+
// Scholarships
192
192
+
const scholarshipResult = checkScholarship(subject, combined);
193
193
+
if (scholarshipResult) return scholarshipResult;
194
194
+
195
195
+
// Financial aid
196
196
+
const aidResult = checkFinancialAid(combined);
197
197
+
if (aidResult) return aidResult;
198
198
+
199
199
+
// Marketing/spam
200
200
+
const irrelevantResult = checkIrrelevant(combined);
201
201
+
if (irrelevantResult) return irrelevantResult;
202
202
+
203
203
+
// Default to not relevant
204
204
+
return { pertains: false, reason: "No clear relevance indicators", confidence: 0.3 };
205
205
+
}
206
206
+
207
207
+
function checkSecurity(combined: string): ClassificationResult | null {
208
208
+
const patterns = [
209
209
+
/\bpassword\s+(reset|change|update|expired)\b/,
210
210
+
/\breset\s+your\s+password\b/,
211
211
+
/\baccount\s+security\b/,
212
212
+
/\bsecurity\s+alert\b/,
213
213
+
/\bunusual\s+(sign[- ]?in|activity)\b/,
214
214
+
/\bverification\s+code\b/,
215
215
+
/\b(2fa|mfa|two[- ]factor)\b/,
216
216
+
/\bcompromised\s+account\b/,
217
217
+
/\baccount\s+(locked|suspended)\b/,
218
218
+
/\bsuspicious\s+activity\b/
219
219
+
];
220
220
+
221
221
+
for (let i = 0; i < patterns.length; i++) {
222
222
+
if (patterns[i].test(combined)) {
223
223
+
if (/\bsaving.*\bon\s+tuition\b|\btuition.*\bsaving\b/.test(combined)) {
224
224
+
continue;
225
225
+
}
226
226
+
return { pertains: true, reason: "Security/password alert", confidence: 1.0 };
227
227
+
}
228
228
+
}
229
229
+
return null;
230
230
+
}
231
231
+
232
232
+
function checkStudentAction(combined: string): ClassificationResult | null {
233
233
+
const patterns = [
234
234
+
/\bapplication\s+(received|complete|submitted|confirmation)\b/,
235
235
+
/\breceived\s+your\s+application\b/,
236
236
+
/\bthank\s+you\s+for\s+(applying|submitting)\b/,
237
237
+
/\benrollment\s+confirmation\b/,
238
238
+
/\bconfirmation\s+(of|for)\s+(your\s+)?(application|enrollment)\b/,
239
239
+
/\byour\s+application\s+(has\s+been|is)\s+(received|complete)\b/
240
240
+
];
241
241
+
242
242
+
for (let i = 0; i < patterns.length; i++) {
243
243
+
if (patterns[i].test(combined)) {
244
244
+
if (/\bhow\s+to\s+apply\b|\bapply\s+now\b|\bstart\s+(your\s+)?application\b/.test(combined)) {
245
245
+
continue;
246
246
+
}
247
247
+
return { pertains: true, reason: "Application/enrollment confirmation", confidence: 0.95 };
248
248
+
}
249
249
+
}
250
250
+
return null;
251
251
+
}
252
252
+
253
253
+
function checkAccepted(combined: string): ClassificationResult | null {
254
254
+
const patterns = [
255
255
+
/\baccepted\s+(student\s+)?portal\b/,
256
256
+
/\byour\s+(personalized\s+)?accepted\s+portal\b/,
257
257
+
/\bdeposit\s+(today|now|by|to\s+reserve)\b/,
258
258
+
/\breserve\s+your\s+(place|spot)\b/,
259
259
+
/\bcongratulations.*\baccepted\b/,
260
260
+
/\byou\s+(have\s+been|are|were)\s+accepted\b/,
261
261
+
/\badmission\s+(decision|offer)\b/,
262
262
+
/\benroll(ment)?\s+deposit\b/
263
263
+
];
264
264
+
265
265
+
for (let i = 0; i < patterns.length; i++) {
266
266
+
if (patterns[i].test(combined)) {
267
267
+
if (/\bacceptance\s+rate\b|\bhigh\s+acceptance\b|\bpre[- ]admit(ted)?\b|\bautomatic\s+admission\b/.test(combined)) {
268
268
+
continue;
269
269
+
}
270
270
+
if (/\byou\s+will\s+(also\s+)?receive\s+(an?\s+)?(accelerated\s+)?admission\s+decision\b/.test(combined)) {
271
271
+
continue;
272
272
+
}
273
273
+
if (/\breceive\s+an\s+admission\s+decision\s+within\b/.test(combined)) {
274
274
+
continue;
275
275
+
}
276
276
+
return { pertains: true, reason: "Accepted student information", confidence: 0.95 };
277
277
+
}
278
278
+
}
279
279
+
return null;
280
280
+
}
281
281
+
282
282
+
function checkDualEnrollment(combined: string): ClassificationResult | null {
283
283
+
const patterns = [
284
284
+
/\bdual\s+enrollment\b/,
285
285
+
/\bcourse\s+(registration|deletion|added|dropped)\b/,
286
286
+
/\bspring\s+\d{4}\s+(course|on[- ]campus)\b/,
287
287
+
/\bhow\s+to\s+register\b.*\b(course|class)/
288
288
+
];
289
289
+
290
290
+
for (let i = 0; i < patterns.length; i++) {
291
291
+
if (patterns[i].test(combined)) {
292
292
+
if (/\blearn\s+more\s+about\b|\binterested\s+in\b|\bconsider\s+joining\b/.test(combined)) {
293
293
+
continue;
294
294
+
}
295
295
+
return { pertains: true, reason: "Dual enrollment course information", confidence: 0.9 };
296
296
+
}
297
297
+
}
298
298
+
return null;
299
299
+
}
300
300
+
301
301
+
function checkScholarship(subject: string, combined: string): ClassificationResult | null {
302
302
+
// Specific scholarship applications
303
303
+
if (/\bapply\s+for\s+(the\s+)?.*\bscholarship\b/.test(subject)) {
304
304
+
if (/\bpresident'?s\b|\bministry\b|\bimpact\b/.test(combined)) {
305
305
+
return { pertains: true, reason: "Scholarship application opportunity", confidence: 0.75 };
306
306
+
}
307
307
+
}
308
308
+
309
309
+
// Not awarded patterns (check first)
310
310
+
const notAwardedPatterns = [
311
311
+
/\bscholarship\b.*\b(held|reserved)\s+for\s+you\b/,
312
312
+
/\b(held|reserved)\s+for\s+you\b/,
313
313
+
/\bconsider(ed|ation)\b.*\bscholarship\b/,
314
314
+
/\bscholarship\b.*\bconsider(ed|ation)\b/,
315
315
+
/\beligible\s+for\b.*\bscholarship\b/,
316
316
+
/\bscholarship\b.*\beligible\b/,
317
317
+
/\bmay\s+qualify\b.*\bscholarship\b/
318
318
+
];
319
319
+
320
320
+
if (/\bscholarship\b/.test(combined)) {
321
321
+
for (let i = 0; i < notAwardedPatterns.length; i++) {
322
322
+
if (notAwardedPatterns[i].test(combined)) {
323
323
+
return { pertains: false, reason: "Scholarship not actually awarded", confidence: 0.9 };
324
324
+
}
325
325
+
}
326
326
+
}
327
327
+
328
328
+
// Awarded patterns
329
329
+
const awardedPatterns = [
330
330
+
/\bcongratulations\b.*\bscholarship\b/,
331
331
+
/\byou\s+(have|received|are\s+awarded|won)\b.*\bscholarship\b/,
332
332
+
/\bwe\s+(are\s+)?(pleased\s+to\s+)?award(ing)?\b.*\bscholarship\b/,
333
333
+
/\bscholarship\s+(offer|award)\b/
334
334
+
];
335
335
+
336
336
+
for (let i = 0; i < awardedPatterns.length; i++) {
337
337
+
if (awardedPatterns[i].test(combined)) {
338
338
+
return { pertains: true, reason: "Scholarship awarded", confidence: 0.95 };
339
339
+
}
340
340
+
}
341
341
+
342
342
+
return null;
343
343
+
}
344
344
+
345
345
+
function checkFinancialAid(combined: string): ClassificationResult | null {
346
346
+
const readyPatterns = [
347
347
+
/\bfinancial\s+aid\b.*\boffer\b.*\b(ready|available)\b/,
348
348
+
/\baward\s+letter\b.*\b(ready|available|posted|view)\b/,
349
349
+
/\b(view|review)\s+(your\s+)?award\s+letter\b/,
350
350
+
/\byour\s+aid\s+is\s+ready\b/
351
351
+
];
352
352
+
353
353
+
const notReadyPatterns = [
354
354
+
/\blearn\s+more\s+about\b.*\bfinancial\s+aid\b/,
355
355
+
/\bapply\b.*\b(for\s+)?financial\s+aid\b/,
356
356
+
/\bcomplete\s+(your\s+)?fafsa\b/,
357
357
+
/\bpriority\s+(deadline|consideration)\b.*\bfinancial\s+aid\b/
358
358
+
];
359
359
+
360
360
+
for (let i = 0; i < readyPatterns.length; i++) {
361
361
+
if (readyPatterns[i].test(combined)) {
362
362
+
for (let j = 0; j < notReadyPatterns.length; j++) {
363
363
+
if (notReadyPatterns[j].test(combined)) {
364
364
+
return null;
365
365
+
}
366
366
+
}
367
367
+
return { pertains: true, reason: "Financial aid offer ready", confidence: 0.95 };
368
368
+
}
369
369
+
}
370
370
+
return null;
371
371
+
}
372
372
+
373
373
+
function checkIrrelevant(combined: string): ClassificationResult | null {
374
374
+
const patterns = [
375
375
+
/\bstudent\s+life\s+blog\b/,
376
376
+
/\bnewsletter\b/,
377
377
+
/\bweekly\s+(digest|update)\b/,
378
378
+
/\bupcoming\s+events\b/,
379
379
+
/\bjoin\s+us\s+(for|at)\b/,
380
380
+
/\bopen\s+house\b/,
381
381
+
/\bvirtual\s+tour\b/,
382
382
+
/\bhaven'?t\s+applied.*yet\b/,
383
383
+
/\bstill\s+time\s+to\s+apply\b/,
384
384
+
/\bhow\s+is\s+your\s+college\s+search\b/,
385
385
+
/\bextended.*\bpriority\s+deadline\b/,
386
386
+
/\bpriority\s+deadline.*\bextended\b/,
387
387
+
/\bsummer\s+(academy|camp|program)\b/,
388
388
+
/\bugly\s+sweater\b/,
389
389
+
/\bi\s+hope\s+you\s+have\s+been\s+receiving\s+my\s+emails\b/,
390
390
+
/\bam\s+i\s+reaching\b/,
391
391
+
/\byou\s+are\s+on\s+.*\s+(radar|list)\b/,
392
392
+
/\bi\s+want\s+to\s+make\s+sure\s+you\s+know\b/,
393
393
+
/\byou'?re\s+invited\s+to\s+submit\b/,
394
394
+
/\bi'?m\s+eager\s+to\s+consider\s+you\b/,
395
395
+
/\bsubmit\s+your\s+.*\s+application\b/,
396
396
+
/\bpriority\s+status\b.*\bsubmit.*application\b/
397
397
+
];
398
398
+
399
399
+
for (let i = 0; i < patterns.length; i++) {
400
400
+
if (patterns[i].test(combined)) {
401
401
+
return { pertains: false, reason: "Marketing/newsletter/spam", confidence: 0.95 };
402
402
+
}
403
403
+
}
404
404
+
405
405
+
if (/\bhaven'?t\s+applied\b/.test(combined)) {
406
406
+
return { pertains: false, reason: "Unsolicited outreach", confidence: 0.95 };
407
407
+
}
408
408
+
409
409
+
return null;
410
410
+
}
411
411
+
412
412
+
// Utilities
413
413
+
function getOrCreateLabel(name: string): GoogleAppsScript.Gmail.GmailLabel {
414
414
+
return GmailApp.getUserLabelByName(name) || GmailApp.createLabel(name);
415
415
+
}
416
416
+
417
417
+
function safeStr(s: string | null, maxLen?: number): string {
418
418
+
if (s === null || s === undefined) return "";
419
419
+
const str = s.toString().trim();
420
420
+
if (maxLen && str.length > maxLen) return str.slice(0, maxLen);
421
421
+
return str;
422
422
+
}
423
423
+
424
424
+
function setupTriggers(): void {
425
425
+
// Delete existing triggers
426
426
+
const triggers = ScriptApp.getProjectTriggers();
427
427
+
for (let i = 0; i < triggers.length; i++) {
428
428
+
if (triggers[i].getHandlerFunction() === "runTriage") {
429
429
+
ScriptApp.deleteTrigger(triggers[i]);
430
430
+
}
431
431
+
}
432
432
+
433
433
+
// Create new trigger
434
434
+
ScriptApp.newTrigger("runTriage")
435
435
+
.timeBased()
436
436
+
.everyMinutes(10)
437
437
+
.create();
438
438
+
439
439
+
Logger.log("Trigger created: runTriage every 10 minutes");
440
440
+
}
441
441
+
+11
src/apps-script/appsscript.json
···
1
1
+
{
2
2
+
"timeZone": "America/New_York",
3
3
+
"dependencies": {},
4
4
+
"exceptionLogging": "STACKDRIVER",
5
5
+
"runtimeVersion": "V8",
6
6
+
"oauthScopes": [
7
7
+
"https://www.googleapis.com/auth/gmail.modify",
8
8
+
"https://www.googleapis.com/auth/gmail.labels",
9
9
+
"https://www.googleapis.com/auth/script.external_request"
10
10
+
]
11
11
+
}
+47
src/build-gas.ts
···
1
1
+
#!/usr/bin/env bun
2
2
+
// Build script for Google Apps Script
3
3
+
4
4
+
import { execSync } from "child_process";
5
5
+
6
6
+
const command = process.argv[2] || "build";
7
7
+
8
8
+
if (command === "build") {
9
9
+
console.log("🔨 Building for Apps Script (local .gs file)...\n");
10
10
+
11
11
+
// Compile TypeScript
12
12
+
console.log("1️⃣ Compiling TypeScript...");
13
13
+
try {
14
14
+
execSync("tsc -p tsconfig.apps-script.json", { stdio: "inherit" });
15
15
+
console.log("✅ TypeScript compiled\n");
16
16
+
} catch (e) {
17
17
+
console.error("❌ TypeScript compilation failed");
18
18
+
process.exit(1);
19
19
+
}
20
20
+
21
21
+
// Create .gs file
22
22
+
console.log("2️⃣ Creating .gs file...");
23
23
+
const { mkdirSync, readFileSync, writeFileSync } = await import("fs");
24
24
+
mkdirSync("build", { recursive: true });
25
25
+
const js = readFileSync("build/compiled/Code.js", "utf-8");
26
26
+
27
27
+
const header = `// Auto-generated from TypeScript at: ${new Date().toISOString()}
28
28
+
// Source: src/apps-script/Code.ts
29
29
+
// DO NOT EDIT THIS FILE DIRECTLY - Edit the TypeScript source instead
30
30
+
31
31
+
`;
32
32
+
33
33
+
writeFileSync("build/Code.gs", header + js);
34
34
+
console.log("✅ Created build/Code.gs\n");
35
35
+
36
36
+
console.log("🎉 Build complete!");
37
37
+
console.log("\n📋 Next steps:");
38
38
+
console.log(" 1. Open https://script.google.com");
39
39
+
console.log(" 2. Create a new project (or open existing)");
40
40
+
console.log(" 3. Copy build/Code.gs");
41
41
+
console.log(" 4. Paste into the Code.gs file in Apps Script editor");
42
42
+
console.log(" 5. Save and run setupTriggers()");
43
43
+
} else {
44
44
+
console.log("Usage: bun run gas [build]");
45
45
+
console.log("\nCommands:");
46
46
+
console.log(" build - Compile TypeScript to .gs file (default)");
47
47
+
}
-195
src/generate-gscript.ts
···
1
1
-
#!/usr/bin/env bun
2
2
-
// Generate GScript-compatible classifier code from TypeScript rules
3
3
-
4
4
-
import { readFile, writeFile } from "fs/promises";
5
5
-
6
6
-
// Read the classifier
7
7
-
const classifierSrc = await readFile("src/classifier.ts", "utf-8");
8
8
-
9
9
-
// Extract patterns from each rule function
10
10
-
const extractPatterns = (functionName: string): string[] => {
11
11
-
const match = classifierSrc.match(new RegExp(`private ${functionName}[^}]+\\[([^\\]]+)\\]`, "s"));
12
12
-
if (!match) return [];
13
13
-
14
14
-
return match[1]
15
15
-
.split(/,\s*/)
16
16
-
.map(p => p.trim())
17
17
-
.filter(p => p.startsWith("/"));
18
18
-
};
19
19
-
20
20
-
const securityPatterns = extractPatterns("checkSecurity");
21
21
-
const studentActionPatterns = extractPatterns("checkStudentAction");
22
22
-
const acceptedPatterns = extractPatterns("checkAccepted");
23
23
-
const scholarshipAwardedPatterns = classifierSrc.match(/awardedPatterns = \[([^\]]+)\]/s)?.[1]
24
24
-
.split(/,\s*/).map(p => p.trim()).filter(p => p.startsWith("/")) || [];
25
25
-
const scholarshipNotAwardedPatterns = classifierSrc.match(/notAwardedPatterns = \[([^\]]+)\]/s)?.[1]
26
26
-
.split(/,\s*/).map(p => p.trim()).filter(p => p.startsWith("/")) || [];
27
27
-
const irrelevantPatterns = extractPatterns("checkIrrelevant");
28
28
-
29
29
-
// Generate GScript code
30
30
-
const gscript = `
31
31
-
// Auto-generated from classifier.ts - DO NOT EDIT MANUALLY
32
32
-
// Generated at: ${new Date().toISOString()}
33
33
-
34
34
-
function classifyEmailTS(meta) {
35
35
-
const subject = (meta.subject || "").toLowerCase();
36
36
-
const body = (meta.body || "").toLowerCase();
37
37
-
const from = (meta.from || "").toLowerCase();
38
38
-
const combined = subject + " " + body;
39
39
-
40
40
-
// Security alerts - always relevant
41
41
-
const securityPatterns = [
42
42
-
${securityPatterns.join(",\n ")}
43
43
-
];
44
44
-
45
45
-
for (const pattern of securityPatterns) {
46
46
-
if (pattern.test(combined)) {
47
47
-
// Exclude tuition savings marketing
48
48
-
if (/\\bsaving.*\\bon\\s+tuition\\b|\\btuition.*\\bsaving\\b/.test(combined)) {
49
49
-
continue;
50
50
-
}
51
51
-
return {
52
52
-
pertains: true,
53
53
-
reason: "Security/password alert - always important",
54
54
-
confidence: 1.0
55
55
-
};
56
56
-
}
57
57
-
}
58
58
-
59
59
-
// Student action confirmations
60
60
-
const actionPatterns = [
61
61
-
${studentActionPatterns.join(",\n ")}
62
62
-
];
63
63
-
64
64
-
for (const pattern of actionPatterns) {
65
65
-
if (pattern.test(combined)) {
66
66
-
if (/\\bhow\\s+to\\s+apply\\b|\\bapply\\s+now\\b|\\bstart\\s+(your\\s+)?application\\b/.test(combined)) {
67
67
-
continue;
68
68
-
}
69
69
-
return {
70
70
-
pertains: true,
71
71
-
reason: "Confirmation of student action",
72
72
-
confidence: 0.95
73
73
-
};
74
74
-
}
75
75
-
}
76
76
-
77
77
-
// Accepted student info
78
78
-
const acceptedPatterns = [
79
79
-
${acceptedPatterns.join(",\n ")}
80
80
-
];
81
81
-
82
82
-
for (const pattern of acceptedPatterns) {
83
83
-
if (pattern.test(combined)) {
84
84
-
if (/\\bacceptance\\s+rate\\b|\\bhigh\\s+acceptance\\b|\\bpre[- ]admit(ted)?\\b|\\bautomatic\\s+admission\\b/.test(combined)) {
85
85
-
continue;
86
86
-
}
87
87
-
return {
88
88
-
pertains: true,
89
89
-
reason: "Accepted student portal/deposit information",
90
90
-
confidence: 0.95
91
91
-
};
92
92
-
}
93
93
-
}
94
94
-
95
95
-
// Dual enrollment
96
96
-
if (/\\bdual\\s+enrollment\\b|\\bcourse\\s+(registration|deletion|added|dropped)\\b/.test(combined)) {
97
97
-
if (!/\\blearn\\s+more\\s+about\\b|\\binterested\\s+in\\b|\\bconsider\\s+joining\\b/.test(combined)) {
98
98
-
return {
99
99
-
pertains: true,
100
100
-
reason: "Dual enrollment course information",
101
101
-
confidence: 0.9
102
102
-
};
103
103
-
}
104
104
-
}
105
105
-
106
106
-
// Scholarships - check specific applications first
107
107
-
if (/\\bapply\\s+for\\s+(the\\s+)?.*\\bscholarship\\b/.test(subject)) {
108
108
-
if (/\\bpresident'?s\\b|\\bministry\\b|\\bimpact\\b/.test(combined)) {
109
109
-
return {
110
110
-
pertains: true,
111
111
-
reason: "Scholarship application opportunity",
112
112
-
confidence: 0.75
113
113
-
};
114
114
-
}
115
115
-
}
116
116
-
117
117
-
// Scholarship not awarded (check before awarded)
118
118
-
const scholarshipNotAwardedPatterns = [
119
119
-
${scholarshipNotAwardedPatterns.join(",\n ")}
120
120
-
];
121
121
-
122
122
-
if (/\\bscholarship\\b/.test(combined)) {
123
123
-
for (const pattern of scholarshipNotAwardedPatterns) {
124
124
-
if (pattern.test(combined)) {
125
125
-
return {
126
126
-
pertains: false,
127
127
-
reason: "Scholarship not actually awarded",
128
128
-
confidence: 0.9
129
129
-
};
130
130
-
}
131
131
-
}
132
132
-
}
133
133
-
134
134
-
// Scholarship awarded
135
135
-
const scholarshipAwardedPatterns = [
136
136
-
${scholarshipAwardedPatterns.join(",\n ")}
137
137
-
];
138
138
-
139
139
-
for (const pattern of scholarshipAwardedPatterns) {
140
140
-
if (pattern.test(combined)) {
141
141
-
return {
142
142
-
pertains: true,
143
143
-
reason: "Scholarship actually awarded",
144
144
-
confidence: 0.95
145
145
-
};
146
146
-
}
147
147
-
}
148
148
-
149
149
-
// Financial aid ready
150
150
-
if (/\\bfinancial\\s+aid\\b.*\\boffer\\b.*\\b(ready|available)\\b|\\baward\\s+letter\\b.*\\b(ready|available)\\b/.test(combined)) {
151
151
-
if (!/\\blearn\\s+more\\s+about\\b|\\bapply\\b|\\bcomplete\\s+(your\\s+)?fafsa\\b/.test(combined)) {
152
152
-
return {
153
153
-
pertains: true,
154
154
-
reason: "Financial aid offer ready",
155
155
-
confidence: 0.95
156
156
-
};
157
157
-
}
158
158
-
}
159
159
-
160
160
-
// Marketing/spam - definitely not relevant
161
161
-
const irrelevantPatterns = [
162
162
-
${irrelevantPatterns.join(",\n ")}
163
163
-
];
164
164
-
165
165
-
for (const pattern of irrelevantPatterns) {
166
166
-
if (pattern.test(combined)) {
167
167
-
return {
168
168
-
pertains: false,
169
169
-
reason: "Marketing/newsletter/unsolicited outreach",
170
170
-
confidence: 0.95
171
171
-
};
172
172
-
}
173
173
-
}
174
174
-
175
175
-
// Haven't applied yet
176
176
-
if (/\\bhaven'?t\\s+applied\\b/.test(combined)) {
177
177
-
return {
178
178
-
pertains: false,
179
179
-
reason: "Unsolicited email where student has not applied",
180
180
-
confidence: 0.95
181
181
-
};
182
182
-
}
183
183
-
184
184
-
// Default to not relevant
185
185
-
return {
186
186
-
pertains: false,
187
187
-
reason: "No clear relevance indicators found",
188
188
-
confidence: 0.3
189
189
-
};
190
190
-
}
191
191
-
`.trim();
192
192
-
193
193
-
await writeFile("build/filter-hybrid.gs", gscript);
194
194
-
console.log("✅ Generated build/filter-hybrid.gs");
195
195
-
console.log(" Deploy this file to Google Apps Script");
+17
tsconfig.apps-script.json
···
1
1
+
{
2
2
+
"compilerOptions": {
3
3
+
"target": "ES2015",
4
4
+
"module": "none",
5
5
+
"lib": ["ES2015"],
6
6
+
"noImplicitAny": true,
7
7
+
"strict": false,
8
8
+
"outDir": "build/compiled",
9
9
+
"removeComments": false,
10
10
+
"sourceMap": false,
11
11
+
"esModuleInterop": true,
12
12
+
"skipLibCheck": true,
13
13
+
"types": ["google-apps-script"]
14
14
+
},
15
15
+
"include": ["src/apps-script/**/*.ts"],
16
16
+
"exclude": ["node_modules"]
17
17
+
}