@wonsukchoi/crondex 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/bin/crondex.js +85 -0
- package/catalog.json +2397 -522
- package/jobs/construction/inspection-deadline-reminder.yaml +31 -0
- package/jobs/construction/permit-expiry-check.yaml +31 -0
- package/jobs/content/canonical-tag-check.yaml +25 -0
- package/jobs/content/hreflang-audit.yaml +25 -0
- package/jobs/content/image-alt-text-audit.yaml +21 -0
- package/jobs/content/page-speed-regression-watch.yaml +26 -0
- package/jobs/content/sitemap-freshness-check.yaml +31 -0
- package/jobs/content/stale-post-audit.yaml +28 -0
- package/jobs/creator/content-calendar-gap-check.yaml +31 -0
- package/jobs/creator/engagement-drop-watch.yaml +36 -0
- package/jobs/devops/cdn-cache-purge-reminder.yaml +27 -0
- package/jobs/devops/ci-build-time-regression-watch.yaml +35 -0
- package/jobs/devops/error-rate-spike-watch.yaml +43 -0
- package/jobs/devops/feature-flag-staleness-audit.yaml +30 -0
- package/jobs/devops/k8s-pod-restart-watch.yaml +26 -0
- package/jobs/devops/log-forwarding-health-check.yaml +32 -0
- package/jobs/devops/staging-prod-config-diff.yaml +32 -0
- package/jobs/devops/terraform-drift-check.yaml +24 -0
- package/jobs/education/assignment-grading-backlog-check.yaml +23 -0
- package/jobs/education/attendance-anomaly-check.yaml +33 -0
- package/jobs/events/rsvp-followup-reminder.yaml +30 -0
- package/jobs/events/vendor-payment-deadline-reminder.yaml +31 -0
- package/jobs/finance/budget-overspend-check.yaml +29 -0
- package/jobs/finance/fx-rate-watch.yaml +33 -0
- package/jobs/finance/payroll-run-reminder.yaml +27 -0
- package/jobs/finance/recurring-payment-failure-check.yaml +23 -0
- package/jobs/fleet/fuel-card-anomaly-check.yaml +37 -0
- package/jobs/fleet/vehicle-maintenance-due-check.yaml +36 -0
- package/jobs/growth/churn-risk-watch.yaml +33 -0
- package/jobs/growth/trial-expiring-nudge.yaml +33 -0
- package/jobs/hiring/candidate-followup-nudge.yaml +23 -0
- package/jobs/hiring/open-req-aging-check.yaml +31 -0
- package/jobs/home/car-maintenance-due-reminder.yaml +30 -0
- package/jobs/home/warranty-expiry-reminder.yaml +31 -0
- package/jobs/hospitality/food-safety-temp-log-check.yaml +36 -0
- package/jobs/hospitality/reservation-noshow-check.yaml +20 -0
- package/jobs/inventory/inventory-count-discrepancy-check.yaml +38 -0
- package/jobs/inventory/low-stock-alert.yaml +20 -0
- package/jobs/investing/crypto-price-alert.yaml +33 -0
- package/jobs/investing/portfolio-rebalance-check.yaml +32 -0
- package/jobs/learning/cert-renewal-reminder.yaml +30 -0
- package/jobs/learning/conference-cfp-deadline-reminder.yaml +42 -0
- package/jobs/legal/contract-renewal-reminder.yaml +31 -0
- package/jobs/legal/trademark-renewal-reminder.yaml +30 -0
- package/jobs/logistics/customs-clearance-check.yaml +34 -0
- package/jobs/logistics/shipment-delay-watch.yaml +38 -0
- package/jobs/manufacturing/production-line-downtime-watch.yaml +34 -0
- package/jobs/manufacturing/quality-defect-rate-check.yaml +20 -0
- package/jobs/marketing/ad-spend-pacing-check.yaml +37 -0
- package/jobs/marketing/email-deliverability-check.yaml +37 -0
- package/jobs/nonprofit/grant-deadline-reminder.yaml +44 -0
- package/jobs/nonprofit/lapsed-donor-check.yaml +26 -0
- package/jobs/personal/medication-refill-reminder.yaml +30 -0
- package/jobs/podcast/episode-publish-gap-check.yaml +29 -0
- package/jobs/podcast/sponsor-deliverable-tracker.yaml +31 -0
- package/jobs/productivity/calendar-double-booking-check.yaml +21 -0
- package/jobs/productivity/stale-todo-sweep.yaml +26 -0
- package/jobs/productivity/timezone-meeting-conflict-check.yaml +31 -0
- package/jobs/realestate/lease-expiry-reminder.yaml +30 -0
- package/jobs/realestate/rental-vacancy-check.yaml +30 -0
- package/jobs/sales/lead-response-time-check.yaml +23 -0
- package/jobs/sales/stale-deal-nudge.yaml +35 -0
- package/jobs/security/2fa-enrollment-audit.yaml +24 -0
- package/jobs/security/cve-watch.yaml +27 -0
- package/jobs/security/dependabot-alert-digest.yaml +30 -0
- package/jobs/security/expiring-api-key-rotation.yaml +31 -0
- package/jobs/security/iam-key-rotation-reminder.yaml +27 -0
- package/jobs/security/s3-public-bucket-check.yaml +20 -0
- package/jobs/security/tls-cipher-weak-check.yaml +31 -0
- package/jobs/security/waf-rule-change-watch.yaml +38 -0
- package/jobs/support/csat-score-watch.yaml +32 -0
- package/jobs/support/ticket-backlog-aging-check.yaml +30 -0
- package/jobs/team/oncall-handoff-reminder.yaml +26 -0
- package/jobs/team/team-anniversary-reminder.yaml +22 -0
- package/jobs/travel/frequent-flyer-miles-expiry.yaml +30 -0
- package/jobs/travel/travel-insurance-expiry-check.yaml +26 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,8 +27,16 @@ npx @wonsukchoi/crondex list # browse everything
|
|
|
27
27
|
npx @wonsukchoi/crondex list --category devops # filter by category or --tag
|
|
28
28
|
npx @wonsukchoi/crondex show backup-reminder # print one job's YAML
|
|
29
29
|
npx @wonsukchoi/crondex add backup-reminder --dest ./cron/backup-reminder.yaml
|
|
30
|
+
npx @wonsukchoi/crondex recommend "warn me before my SSL cert expires"
|
|
30
31
|
```
|
|
31
32
|
|
|
33
|
+
`recommend` takes a free-text description of what you want and ranks the
|
|
34
|
+
catalog against it (weighted keyword match over tags/name/id/category/
|
|
35
|
+
description, zero tokens, no network call) — handy for an agent that just
|
|
36
|
+
got asked "can you set up something for X" and needs to check whether a
|
|
37
|
+
ready-made job already covers it before writing one from scratch. Add
|
|
38
|
+
`--limit <n>` to control how many results come back (default 5).
|
|
39
|
+
|
|
32
40
|
Or install once and drop the scope prefix on every call:
|
|
33
41
|
|
|
34
42
|
```bash
|
|
@@ -52,7 +60,7 @@ node bin/crondex.js list
|
|
|
52
60
|
|
|
53
61
|
```
|
|
54
62
|
crondex/
|
|
55
|
-
├── bin/crondex.js CLI: list / show / add
|
|
63
|
+
├── bin/crondex.js CLI: list / show / add / recommend
|
|
56
64
|
├── catalog.json generated index of every job — read this first
|
|
57
65
|
├── schema/job.schema.json spec every job file follows
|
|
58
66
|
├── jobs/
|
package/bin/crondex.js
CHANGED
|
@@ -30,14 +30,92 @@ Usage:
|
|
|
30
30
|
crondex list [--category <name>] [--tag <name>]
|
|
31
31
|
crondex show <id>
|
|
32
32
|
crondex add <id> [--dest <path>]
|
|
33
|
+
crondex recommend "<what you want done>" [--limit <n>]
|
|
33
34
|
|
|
34
35
|
Examples:
|
|
35
36
|
crondex list --category devops
|
|
36
37
|
crondex show dependency-audit
|
|
37
38
|
crondex add backup-reminder --dest ./cron/backup-reminder.yaml
|
|
39
|
+
crondex recommend "warn me before my SSL cert expires"
|
|
38
40
|
`);
|
|
39
41
|
}
|
|
40
42
|
|
|
43
|
+
const STOPWORDS = new Set([
|
|
44
|
+
"a", "an", "the", "to", "for", "of", "in", "on", "at", "by", "and", "or", "my", "me", "i",
|
|
45
|
+
"can", "you", "do", "does", "this", "that", "these", "those", "please", "want", "wants",
|
|
46
|
+
"wanted", "need", "needs", "help", "with", "is", "are", "be", "it", "so", "when", "should",
|
|
47
|
+
"could", "would", "how", "what", "which", "up", "down", "get", "make", "set", "just", "really",
|
|
48
|
+
"some", "something", "any", "want", "us", "our", "your", "yours", "if", "then", "than",
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
function stem(word) {
|
|
52
|
+
if (word.length > 4 && word.endsWith("ies")) return word.slice(0, -3) + "y";
|
|
53
|
+
if (word.length > 4 && word.endsWith("es") && !word.endsWith("ses")) return word.slice(0, -2);
|
|
54
|
+
if (word.length > 3 && word.endsWith("s") && !word.endsWith("ss")) return word.slice(0, -1);
|
|
55
|
+
return word;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function tokenize(text) {
|
|
59
|
+
return text
|
|
60
|
+
.toLowerCase()
|
|
61
|
+
.replace(/[^a-z0-9\s-]/g, " ")
|
|
62
|
+
.split(/[\s-]+/)
|
|
63
|
+
.filter((w) => w.length > 1 && !STOPWORDS.has(w))
|
|
64
|
+
.map(stem);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// id and name are near-duplicates of each other (id is just the slugified
|
|
68
|
+
// name), so they're merged into one "title" field — otherwise a match on a
|
|
69
|
+
// shared word like "water" gets weighted 3+3 instead of 3, which can outrank
|
|
70
|
+
// a more specific job that only matches once via tags.
|
|
71
|
+
const RECOMMEND_WEIGHTS = { tags: 4, title: 3, category: 2, description: 1 };
|
|
72
|
+
|
|
73
|
+
function scoreJob(queryTokens, job) {
|
|
74
|
+
const fields = {
|
|
75
|
+
tags: job.tags.map((t) => stem(t.toLowerCase())),
|
|
76
|
+
title: [...new Set([...tokenize(job.name), ...tokenize(job.id.replace(/-/g, " "))])],
|
|
77
|
+
category: tokenize(job.category ?? ""),
|
|
78
|
+
description: tokenize(job.description ?? ""),
|
|
79
|
+
};
|
|
80
|
+
let score = 0;
|
|
81
|
+
const matched = new Set();
|
|
82
|
+
for (const qt of queryTokens) {
|
|
83
|
+
for (const [field, weight] of Object.entries(RECOMMEND_WEIGHTS)) {
|
|
84
|
+
if (fields[field].includes(qt)) {
|
|
85
|
+
score += weight;
|
|
86
|
+
matched.add(qt);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return { score, matchedTerms: [...matched] };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function recommend(queryText) {
|
|
94
|
+
const limit = Number(flag("limit")) || 5;
|
|
95
|
+
const queryTokens = tokenize(queryText);
|
|
96
|
+
if (!queryTokens.length) {
|
|
97
|
+
console.log("query too vague to match on — describe what you want the job to check or remind you about.");
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const ranked = CATALOG.jobs
|
|
101
|
+
.map((job) => ({ job, ...scoreJob(queryTokens, job) }))
|
|
102
|
+
.filter((r) => r.score > 0)
|
|
103
|
+
.sort((a, b) => b.score - a.score)
|
|
104
|
+
.slice(0, limit);
|
|
105
|
+
if (!ranked.length) {
|
|
106
|
+
console.log(`no confident match for "${queryText}". Run "crondex list" to browse everything.`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
console.log(`top match${ranked.length > 1 ? "es" : ""} for "${queryText}":`);
|
|
110
|
+
console.log();
|
|
111
|
+
for (const r of ranked) {
|
|
112
|
+
console.log(`${r.job.id} [${r.job.category}] score ${r.score} (${r.job.modes.join(", ")})`);
|
|
113
|
+
console.log(` ${r.job.description}`);
|
|
114
|
+
console.log(` matched: ${r.matchedTerms.join(", ")}`);
|
|
115
|
+
console.log();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
41
119
|
function catalogInfoLine() {
|
|
42
120
|
const viaNpx = process.env.npm_command === "exec";
|
|
43
121
|
const freshness = viaNpx
|
|
@@ -98,6 +176,13 @@ switch (cmd) {
|
|
|
98
176
|
}
|
|
99
177
|
add(args[0]);
|
|
100
178
|
break;
|
|
179
|
+
case "recommend":
|
|
180
|
+
if (!args[0]) {
|
|
181
|
+
console.error('usage: crondex recommend "<what you want done>" [--limit <n>]');
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
recommend(args[0]);
|
|
185
|
+
break;
|
|
101
186
|
default:
|
|
102
187
|
printHelp();
|
|
103
188
|
}
|