terminalhire 0.2.5 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/jpi-bounties.js +2031 -0
- package/dist/bin/jpi-dispatch.js +1087 -469
- package/dist/bin/jpi-jobs.js +705 -276
- package/dist/bin/jpi-learn.js +442 -249
- package/dist/bin/jpi-login.js +700 -282
- package/dist/bin/jpi-profile.js +381 -213
- package/dist/bin/jpi-refresh.js +785 -318
- package/dist/bin/jpi-save.js +381 -213
- package/dist/bin/jpi-spinner.js +15 -5
- package/dist/bin/jpi-sync.js +381 -213
- package/dist/bin/spinner.js +22 -6
- package/dist/src/github-auth.js +3 -3
- package/dist/src/profile.js +313 -207
- package/dist/src/signal.js +364 -237
- package/package.json +3 -3
package/dist/bin/jpi-learn.js
CHANGED
|
@@ -16,221 +16,347 @@ var init_types = __esm({
|
|
|
16
16
|
}
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
// ../../packages/core/src/
|
|
19
|
+
// ../../packages/core/src/vocab/graph.data.ts
|
|
20
|
+
var VOCAB_NODES;
|
|
21
|
+
var init_graph_data = __esm({
|
|
22
|
+
"../../packages/core/src/vocab/graph.data.ts"() {
|
|
23
|
+
"use strict";
|
|
24
|
+
VOCAB_NODES = [
|
|
25
|
+
// ── Languages ─────────────────────────────────────────────────────────────
|
|
26
|
+
{ id: "javascript", synonyms: ["js"], related: [{ to: "typescript", w: 0.6 }] },
|
|
27
|
+
{ id: "typescript", parents: ["javascript"], synonyms: ["ts"] },
|
|
28
|
+
{ id: "python", synonyms: ["py"] },
|
|
29
|
+
{ id: "go", synonyms: ["golang"] },
|
|
30
|
+
{ id: "rust" },
|
|
31
|
+
{ id: "java", related: [{ to: "kotlin", w: 0.45 }, { to: "scala", w: 0.4 }] },
|
|
32
|
+
{ id: "ruby" },
|
|
33
|
+
{ id: "elixir" },
|
|
34
|
+
{ id: "scala", related: [{ to: "java", w: 0.4 }] },
|
|
35
|
+
{ id: "kotlin", related: [{ to: "java", w: 0.45 }] },
|
|
36
|
+
{ id: "swift" },
|
|
37
|
+
{ id: "cpp", synonyms: ["c++"] },
|
|
38
|
+
{ id: "csharp", synonyms: ["c#"] },
|
|
39
|
+
{ id: "php" },
|
|
40
|
+
{ id: "haskell" },
|
|
41
|
+
{ id: "clojure" },
|
|
42
|
+
{ id: "r" },
|
|
43
|
+
{ id: "dart" },
|
|
44
|
+
// ── Frontend ──────────────────────────────────────────────────────────────
|
|
45
|
+
{
|
|
46
|
+
id: "react",
|
|
47
|
+
parents: ["javascript"],
|
|
48
|
+
synonyms: ["reactjs"],
|
|
49
|
+
related: [{ to: "nextjs", w: 0.55 }, { to: "vue", w: 0.4 }, { to: "svelte", w: 0.4 }, { to: "solidjs", w: 0.5 }, { to: "angular", w: 0.35 }]
|
|
50
|
+
},
|
|
51
|
+
{ id: "nextjs", parents: ["react"], synonyms: ["next", "next.js"], related: [{ to: "remix", w: 0.5 }] },
|
|
52
|
+
{ id: "vue", parents: ["javascript"], synonyms: ["vue.js"], related: [{ to: "nuxt", w: 0.6 }] },
|
|
53
|
+
{ id: "nuxt", parents: ["vue"], synonyms: ["nuxt.js"] },
|
|
54
|
+
{ id: "svelte", parents: ["javascript"], related: [{ to: "sveltekit", w: 0.65 }] },
|
|
55
|
+
{ id: "sveltekit", parents: ["svelte"] },
|
|
56
|
+
{ id: "angular", parents: ["typescript"], synonyms: ["angular.js", "angularjs"] },
|
|
57
|
+
{ id: "solidjs", parents: ["javascript"] },
|
|
58
|
+
{ id: "remix", parents: ["react"], synonyms: ["remix.run"] },
|
|
59
|
+
{ id: "astro", parents: ["javascript"], related: [{ to: "nextjs", w: 0.4 }] },
|
|
60
|
+
{ id: "qwik", parents: ["javascript"] },
|
|
61
|
+
{ id: "tailwind", parents: ["css"], synonyms: ["tailwindcss", "tw"] },
|
|
62
|
+
{ id: "css" },
|
|
63
|
+
{ id: "html" },
|
|
64
|
+
{ id: "redux", parents: ["react"] },
|
|
65
|
+
{ id: "vite", parents: ["frontend"] },
|
|
66
|
+
{ id: "webpack", parents: ["frontend"] },
|
|
67
|
+
{ id: "storybook", parents: ["frontend"] },
|
|
68
|
+
// ── Backend frameworks / runtimes ───────────────────────────────────────────
|
|
69
|
+
{
|
|
70
|
+
id: "nodejs",
|
|
71
|
+
parents: ["javascript"],
|
|
72
|
+
synonyms: ["node", "node.js"],
|
|
73
|
+
related: [{ to: "express", w: 0.5 }, { to: "fastify", w: 0.45 }, { to: "nestjs", w: 0.45 }]
|
|
74
|
+
},
|
|
75
|
+
{ id: "express", parents: ["nodejs"], synonyms: ["express.js", "expressjs"], related: [{ to: "fastify", w: 0.5 }] },
|
|
76
|
+
{ id: "fastify", parents: ["nodejs"] },
|
|
77
|
+
{ id: "nestjs", parents: ["nodejs"], synonyms: ["nest", "nest.js"] },
|
|
78
|
+
{ id: "hono", parents: ["nodejs"] },
|
|
79
|
+
{ id: "deno", parents: ["javascript"], related: [{ to: "nodejs", w: 0.5 }, { to: "bun", w: 0.5 }] },
|
|
80
|
+
{ id: "bun", parents: ["javascript"], related: [{ to: "nodejs", w: 0.5 }] },
|
|
81
|
+
{ id: "django", parents: ["python"], related: [{ to: "flask", w: 0.5 }, { to: "fastapi", w: 0.45 }] },
|
|
82
|
+
{ id: "fastapi", parents: ["python"], related: [{ to: "flask", w: 0.55 }, { to: "django", w: 0.45 }] },
|
|
83
|
+
{ id: "flask", parents: ["python"] },
|
|
84
|
+
{ id: "rails", parents: ["ruby"], synonyms: ["ruby-on-rails", "ror"] },
|
|
85
|
+
{ id: "spring", parents: ["java"], synonyms: ["spring-boot", "springboot"] },
|
|
86
|
+
{ id: "actix", parents: ["rust"] },
|
|
87
|
+
{ id: "gin", parents: ["go"] },
|
|
88
|
+
{ id: "phoenix", parents: ["elixir"] },
|
|
89
|
+
{ id: "laravel", parents: ["php"] },
|
|
90
|
+
{ id: "dotnet", parents: ["csharp"], synonyms: [".net", "asp.net", "dotnet-core"] },
|
|
91
|
+
// ── Infrastructure & DevOps ─────────────────────────────────────────────────
|
|
92
|
+
{ id: "kubernetes", synonyms: ["k8s", "kube"], related: [{ to: "docker", w: 0.5 }, { to: "helm", w: 0.55 }, { to: "terraform", w: 0.4 }, { to: "argocd", w: 0.45 }] },
|
|
93
|
+
{ id: "docker", parents: ["devops"], related: [{ to: "kubernetes", w: 0.5 }] },
|
|
94
|
+
{ id: "terraform", synonyms: ["tf"], related: [{ to: "pulumi", w: 0.55 }, { to: "ansible", w: 0.4 }, { to: "aws", w: 0.4 }] },
|
|
95
|
+
{ id: "pulumi", related: [{ to: "terraform", w: 0.55 }] },
|
|
96
|
+
{ id: "ansible" },
|
|
97
|
+
{ id: "aws", synonyms: ["amazon-web-services"], related: [{ to: "gcp", w: 0.4 }, { to: "azure", w: 0.4 }] },
|
|
98
|
+
{ id: "gcp", synonyms: ["google-cloud", "google-cloud-platform"], related: [{ to: "aws", w: 0.4 }, { to: "azure", w: 0.4 }] },
|
|
99
|
+
{ id: "azure", synonyms: ["microsoft-azure"], related: [{ to: "aws", w: 0.4 }] },
|
|
100
|
+
{ id: "ci-cd", synonyms: ["cicd", "jenkins", "circleci", "circle-ci", "travis"], related: [{ to: "github-actions", w: 0.6 }, { to: "gitlab-ci", w: 0.6 }] },
|
|
101
|
+
{ id: "github-actions", parents: ["ci-cd"], synonyms: ["github-action"] },
|
|
102
|
+
{ id: "gitlab-ci", parents: ["ci-cd"], synonyms: ["gitlab"] },
|
|
103
|
+
{ id: "linux" },
|
|
104
|
+
{ id: "nginx" },
|
|
105
|
+
{ id: "prometheus", parents: ["observability"], related: [{ to: "grafana", w: 0.6 }] },
|
|
106
|
+
{ id: "grafana", parents: ["observability"] },
|
|
107
|
+
{ id: "datadog", parents: ["observability"] },
|
|
108
|
+
{ id: "opentelemetry", parents: ["observability"], synonyms: ["otel"] },
|
|
109
|
+
{ id: "vercel", related: [{ to: "netlify", w: 0.5 }, { to: "nextjs", w: 0.4 }] },
|
|
110
|
+
{ id: "netlify" },
|
|
111
|
+
{ id: "fly", synonyms: ["fly.io"], related: [{ to: "railway", w: 0.5 }, { to: "render", w: 0.5 }] },
|
|
112
|
+
{ id: "railway", related: [{ to: "render", w: 0.5 }] },
|
|
113
|
+
{ id: "render" },
|
|
114
|
+
{ id: "cloudflare", synonyms: ["cloudflare-workers"] },
|
|
115
|
+
{ id: "helm", parents: ["kubernetes"] },
|
|
116
|
+
{ id: "argocd", parents: ["kubernetes"] },
|
|
117
|
+
{ id: "serverless", parents: ["devops"] },
|
|
118
|
+
// ── Databases & storage ─────────────────────────────────────────────────────
|
|
119
|
+
{ id: "postgresql", synonyms: ["postgres", "pg"], related: [{ to: "mysql", w: 0.45 }, { to: "sqlite", w: 0.4 }] },
|
|
120
|
+
{ id: "mysql", related: [{ to: "postgresql", w: 0.45 }] },
|
|
121
|
+
{ id: "sqlite" },
|
|
122
|
+
{ id: "mongodb", synonyms: ["mongo"] },
|
|
123
|
+
{ id: "redis", related: [{ to: "caching", w: 0.5 }] },
|
|
124
|
+
{ id: "elasticsearch", synonyms: ["elastic"], related: [{ to: "search", w: 0.55 }] },
|
|
125
|
+
{ id: "kafka", synonyms: ["apache-kafka"], related: [{ to: "rabbitmq", w: 0.5 }, { to: "message-queue", w: 0.55 }] },
|
|
126
|
+
{ id: "rabbitmq", related: [{ to: "message-queue", w: 0.55 }] },
|
|
127
|
+
{ id: "cassandra" },
|
|
128
|
+
{ id: "dynamodb", parents: ["aws"] },
|
|
129
|
+
{ id: "snowflake", parents: ["data-engineering"], related: [{ to: "clickhouse", w: 0.4 }] },
|
|
130
|
+
{ id: "clickhouse", parents: ["data-engineering"], related: [{ to: "duckdb", w: 0.35 }] },
|
|
131
|
+
{ id: "duckdb", parents: ["data-engineering"] },
|
|
132
|
+
{ id: "supabase", related: [{ to: "postgresql", w: 0.5 }, { to: "neon", w: 0.4 }] },
|
|
133
|
+
{ id: "planetscale", related: [{ to: "mysql", w: 0.5 }] },
|
|
134
|
+
{ id: "neon", related: [{ to: "postgresql", w: 0.5 }] },
|
|
135
|
+
{ id: "turso", related: [{ to: "sqlite", w: 0.5 }] },
|
|
136
|
+
{ id: "cockroachdb", related: [{ to: "postgresql", w: 0.45 }] },
|
|
137
|
+
{ id: "prisma", parents: ["backend"], synonyms: ["@prisma/client"], related: [{ to: "drizzle", w: 0.5 }, { to: "typeorm", w: 0.45 }, { to: "sequelize", w: 0.4 }] },
|
|
138
|
+
{ id: "drizzle", synonyms: ["drizzle-orm"], related: [{ to: "prisma", w: 0.5 }] },
|
|
139
|
+
{ id: "sequelize", related: [{ to: "typeorm", w: 0.4 }] },
|
|
140
|
+
{ id: "typeorm", related: [{ to: "prisma", w: 0.45 }] },
|
|
141
|
+
{ id: "sqlalchemy", parents: ["python"] },
|
|
142
|
+
// ── Data engineering & ML ───────────────────────────────────────────────────
|
|
143
|
+
{ id: "data-engineering", synonyms: ["data-eng"], related: [{ to: "spark", w: 0.5 }, { to: "airflow", w: 0.5 }, { to: "dbt", w: 0.45 }] },
|
|
144
|
+
{ id: "spark", parents: ["data-engineering"], synonyms: ["apache-spark"] },
|
|
145
|
+
{ id: "airflow", parents: ["data-engineering"], synonyms: ["apache-airflow"] },
|
|
146
|
+
{ id: "dbt", parents: ["data-engineering"] },
|
|
147
|
+
{ id: "ml", synonyms: ["machine-learning"], related: [{ to: "pytorch", w: 0.5 }, { to: "tensorflow", w: 0.5 }, { to: "scikit-learn", w: 0.5 }] },
|
|
148
|
+
{ id: "llm", parents: ["ml"], synonyms: ["llms", "genai", "generative-ai"], related: [{ to: "langchain", w: 0.5 }, { to: "rag", w: 0.55 }, { to: "openai", w: 0.45 }, { to: "anthropic", w: 0.45 }] },
|
|
149
|
+
{ id: "pytorch", parents: ["ml"], synonyms: ["torch"], related: [{ to: "tensorflow", w: 0.5 }] },
|
|
150
|
+
{ id: "tensorflow", parents: ["ml"], synonyms: ["keras", "tf-keras"] },
|
|
151
|
+
{ id: "pandas", parents: ["python"], related: [{ to: "numpy", w: 0.6 }] },
|
|
152
|
+
{ id: "numpy", parents: ["python"] },
|
|
153
|
+
{ id: "scikit-learn", parents: ["ml"], synonyms: ["sklearn"] },
|
|
154
|
+
{ id: "jupyter", parents: ["python"] },
|
|
155
|
+
{ id: "langchain", parents: ["llm"], synonyms: ["llamaindex"] },
|
|
156
|
+
{ id: "huggingface", parents: ["ml"], synonyms: ["hugging-face"] },
|
|
157
|
+
{ id: "openai", parents: ["llm"] },
|
|
158
|
+
{ id: "anthropic", parents: ["llm"], synonyms: ["claude"] },
|
|
159
|
+
{ id: "rag", parents: ["llm"], synonyms: ["retrieval-augmented-generation"] },
|
|
160
|
+
{ id: "mlops", parents: ["ml"], related: [{ to: "devops", w: 0.4 }] },
|
|
161
|
+
// ── Mobile ──────────────────────────────────────────────────────────────────
|
|
162
|
+
{ id: "mobile", related: [{ to: "ios", w: 0.5 }, { to: "android", w: 0.5 }] },
|
|
163
|
+
{ id: "ios", parents: ["mobile", "swift"], related: [{ to: "android", w: 0.4 }] },
|
|
164
|
+
{ id: "android", parents: ["mobile"], related: [{ to: "kotlin", w: 0.4 }] },
|
|
165
|
+
{ id: "swiftui", parents: ["ios", "swift"] },
|
|
166
|
+
{ id: "react-native", parents: ["mobile", "react"], synonyms: ["reactnative"], related: [{ to: "flutter", w: 0.4 }, { to: "expo", w: 0.6 }] },
|
|
167
|
+
{ id: "flutter", parents: ["mobile", "dart"] },
|
|
168
|
+
{ id: "expo", parents: ["react-native"] },
|
|
169
|
+
{ id: "kotlin-multiplatform", parents: ["mobile", "kotlin"], synonyms: ["kmp"] },
|
|
170
|
+
// ── Domains / capabilities ──────────────────────────────────────────────────
|
|
171
|
+
{ id: "frontend", related: [{ to: "react", w: 0.4 }, { to: "css", w: 0.3 }] },
|
|
172
|
+
{ id: "backend", related: [{ to: "api-design", w: 0.4 }, { to: "microservices", w: 0.4 }] },
|
|
173
|
+
{ id: "devops", related: [{ to: "kubernetes", w: 0.4 }, { to: "ci-cd", w: 0.4 }, { to: "docker", w: 0.4 }] },
|
|
174
|
+
{ id: "authentication", synonyms: ["auth", "jwt", "saml", "passport", "auth0", "clerk", "nextauth"], related: [{ to: "oauth", w: 0.6 }, { to: "security", w: 0.5 }] },
|
|
175
|
+
{ id: "oauth", parents: ["authentication"], synonyms: ["oauth2", "oidc"], related: [{ to: "security", w: 0.4 }] },
|
|
176
|
+
{ id: "security", related: [{ to: "authentication", w: 0.5 }] },
|
|
177
|
+
{ id: "payments", synonyms: ["stripe", "braintree", "paddle", "lemonsqueezy", "@stripe/stripe-js"], related: [{ to: "billing", w: 0.6 }] },
|
|
178
|
+
{ id: "billing", synonyms: ["recurly", "chargebee"] },
|
|
179
|
+
{ id: "api-design", synonyms: ["rest", "restful", "rest-api"], related: [{ to: "graphql", w: 0.4 }, { to: "grpc", w: 0.4 }, { to: "backend", w: 0.4 }] },
|
|
180
|
+
{ id: "graphql", synonyms: ["gql"], related: [{ to: "trpc", w: 0.4 }] },
|
|
181
|
+
{ id: "trpc", related: [{ to: "graphql", w: 0.4 }] },
|
|
182
|
+
{ id: "grpc", synonyms: ["grpc-web"], related: [{ to: "microservices", w: 0.3 }] },
|
|
183
|
+
{ id: "microservices" },
|
|
184
|
+
{ id: "websockets", synonyms: ["ws", "socket.io"], related: [{ to: "realtime", w: 0.6 }] },
|
|
185
|
+
{ id: "realtime", synonyms: ["real-time"] },
|
|
186
|
+
{ id: "message-queue", synonyms: ["mq"] },
|
|
187
|
+
{ id: "caching", synonyms: ["cache"] },
|
|
188
|
+
{ id: "search", synonyms: ["full-text-search"] },
|
|
189
|
+
{ id: "observability", synonyms: ["o11y"], related: [{ to: "monitoring", w: 0.6 }] },
|
|
190
|
+
{ id: "monitoring", related: [{ to: "prometheus", w: 0.4 }] },
|
|
191
|
+
{ id: "testing", related: [{ to: "unit-testing", w: 0.5 }, { to: "e2e-testing", w: 0.5 }] },
|
|
192
|
+
{ id: "unit-testing", parents: ["testing"] },
|
|
193
|
+
{ id: "e2e-testing", parents: ["testing"], synonyms: ["e2e", "end-to-end-testing"] },
|
|
194
|
+
{ id: "jest", parents: ["testing"], related: [{ to: "vitest", w: 0.6 }, { to: "mocha", w: 0.5 }] },
|
|
195
|
+
{ id: "vitest", parents: ["testing"], related: [{ to: "jest", w: 0.6 }] },
|
|
196
|
+
{ id: "playwright", parents: ["e2e-testing"], related: [{ to: "cypress", w: 0.6 }] },
|
|
197
|
+
{ id: "cypress", parents: ["e2e-testing"] },
|
|
198
|
+
{ id: "mocha", parents: ["testing"] },
|
|
199
|
+
{ id: "pytest", parents: ["testing", "python"] },
|
|
200
|
+
{ id: "accessibility", synonyms: ["a11y"] },
|
|
201
|
+
{ id: "seo" },
|
|
202
|
+
{ id: "performance", synonyms: ["perf", "web-performance"] }
|
|
203
|
+
];
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// ../../packages/core/src/vocab/closure.ts
|
|
208
|
+
function round3(n) {
|
|
209
|
+
return Math.round(n * 1e3) / 1e3;
|
|
210
|
+
}
|
|
211
|
+
function validateGraph(nodes) {
|
|
212
|
+
const ids = /* @__PURE__ */ new Set();
|
|
213
|
+
for (const n of nodes) {
|
|
214
|
+
if (ids.has(n.id)) throw new Error(`vocab: duplicate id "${n.id}"`);
|
|
215
|
+
ids.add(n.id);
|
|
216
|
+
}
|
|
217
|
+
const seenAlias = /* @__PURE__ */ new Map();
|
|
218
|
+
for (const n of nodes) {
|
|
219
|
+
for (const p of n.parents ?? []) {
|
|
220
|
+
if (p === n.id) throw new Error(`vocab: "${n.id}" lists itself as a parent`);
|
|
221
|
+
if (!ids.has(p)) throw new Error(`vocab: "${n.id}" parent "${p}" is not a defined id`);
|
|
222
|
+
}
|
|
223
|
+
for (const e of n.related ?? []) {
|
|
224
|
+
if (e.to === n.id) throw new Error(`vocab: "${n.id}" relates to itself`);
|
|
225
|
+
if (!ids.has(e.to)) throw new Error(`vocab: "${n.id}" related "${e.to}" is not a defined id`);
|
|
226
|
+
if (!(e.w > 0 && e.w <= 1)) throw new Error(`vocab: "${n.id}"\u2192"${e.to}" weight ${e.w} out of (0,1]`);
|
|
227
|
+
}
|
|
228
|
+
for (const s of n.synonyms ?? []) {
|
|
229
|
+
const alias = s.toLowerCase();
|
|
230
|
+
if (ids.has(alias)) throw new Error(`vocab: synonym "${alias}" collides with a canonical id`);
|
|
231
|
+
const prev = seenAlias.get(alias);
|
|
232
|
+
if (prev && prev !== n.id) throw new Error(`vocab: synonym "${alias}" maps to both "${prev}" and "${n.id}"`);
|
|
233
|
+
seenAlias.set(alias, n.id);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
237
|
+
const done = /* @__PURE__ */ new Set();
|
|
238
|
+
const parentMap = new Map(nodes.map((n) => [n.id, n.parents ?? []]));
|
|
239
|
+
const walk = (id, path) => {
|
|
240
|
+
if (done.has(id)) return;
|
|
241
|
+
if (visiting.has(id)) throw new Error(`vocab: parent cycle ${[...path, id].join(" \u2192 ")}`);
|
|
242
|
+
visiting.add(id);
|
|
243
|
+
for (const p of parentMap.get(id) ?? []) walk(p, [...path, id]);
|
|
244
|
+
visiting.delete(id);
|
|
245
|
+
done.add(id);
|
|
246
|
+
};
|
|
247
|
+
for (const n of nodes) walk(n.id, []);
|
|
248
|
+
}
|
|
249
|
+
function buildAdjacency(nodes) {
|
|
250
|
+
const adj = /* @__PURE__ */ new Map();
|
|
251
|
+
const add = (from, to, w) => {
|
|
252
|
+
let m = adj.get(from);
|
|
253
|
+
if (!m) adj.set(from, m = /* @__PURE__ */ new Map());
|
|
254
|
+
if (w > (m.get(to) ?? 0)) m.set(to, w);
|
|
255
|
+
};
|
|
256
|
+
for (const n of nodes) {
|
|
257
|
+
for (const p of n.parents ?? []) {
|
|
258
|
+
add(n.id, p, PARENT_UP);
|
|
259
|
+
add(p, n.id, PARENT_DOWN);
|
|
260
|
+
}
|
|
261
|
+
for (const e of n.related ?? []) {
|
|
262
|
+
add(n.id, e.to, e.w);
|
|
263
|
+
add(e.to, n.id, e.w);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return adj;
|
|
267
|
+
}
|
|
268
|
+
function closureFrom(source, adj) {
|
|
269
|
+
const best = /* @__PURE__ */ new Map();
|
|
270
|
+
for (const [t, w] of adj.get(source) ?? []) {
|
|
271
|
+
if (w >= DECAY_FLOOR) best.set(t, { w: round3(w), via: t });
|
|
272
|
+
}
|
|
273
|
+
const settled = /* @__PURE__ */ new Set([source]);
|
|
274
|
+
while (true) {
|
|
275
|
+
let u;
|
|
276
|
+
let uw = 0;
|
|
277
|
+
for (const [t, e] of best) {
|
|
278
|
+
if (!settled.has(t) && e.w > uw) {
|
|
279
|
+
u = t;
|
|
280
|
+
uw = e.w;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (!u) break;
|
|
284
|
+
settled.add(u);
|
|
285
|
+
const via = best.get(u).via;
|
|
286
|
+
for (const [t, we] of adj.get(u) ?? []) {
|
|
287
|
+
if (settled.has(t)) continue;
|
|
288
|
+
const cand = round3(uw * we);
|
|
289
|
+
if (cand >= DECAY_FLOOR && cand > (best.get(t)?.w ?? 0)) {
|
|
290
|
+
best.set(t, { w: cand, via });
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
best.delete(source);
|
|
295
|
+
return best;
|
|
296
|
+
}
|
|
297
|
+
function buildGraph(nodes) {
|
|
298
|
+
validateGraph(nodes);
|
|
299
|
+
const ids = new Set(nodes.map((n) => n.id));
|
|
300
|
+
const synonyms = /* @__PURE__ */ new Map();
|
|
301
|
+
for (const n of nodes) {
|
|
302
|
+
for (const s of n.synonyms ?? []) synonyms.set(s.toLowerCase(), n.id);
|
|
303
|
+
}
|
|
304
|
+
const adj = buildAdjacency(nodes);
|
|
305
|
+
const closure = /* @__PURE__ */ new Map();
|
|
306
|
+
for (const n of nodes) closure.set(n.id, closureFrom(n.id, adj));
|
|
307
|
+
return { ids, synonyms, closure };
|
|
308
|
+
}
|
|
309
|
+
var PARENT_UP, PARENT_DOWN, DECAY_FLOOR;
|
|
310
|
+
var init_closure = __esm({
|
|
311
|
+
"../../packages/core/src/vocab/closure.ts"() {
|
|
312
|
+
"use strict";
|
|
313
|
+
PARENT_UP = 0.6;
|
|
314
|
+
PARENT_DOWN = 0.35;
|
|
315
|
+
DECAY_FLOOR = 0.25;
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// ../../packages/core/src/vocab/types.ts
|
|
320
|
+
var init_types2 = __esm({
|
|
321
|
+
"../../packages/core/src/vocab/types.ts"() {
|
|
322
|
+
"use strict";
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// ../../packages/core/src/vocab/index.ts
|
|
20
327
|
function normalize(tokens) {
|
|
21
328
|
const result = /* @__PURE__ */ new Set();
|
|
22
329
|
for (const raw of tokens) {
|
|
23
330
|
const lower = raw.toLowerCase().trim();
|
|
24
|
-
if (
|
|
331
|
+
if (GRAPH.ids.has(lower)) {
|
|
25
332
|
result.add(lower);
|
|
26
333
|
continue;
|
|
27
334
|
}
|
|
28
|
-
const mapped =
|
|
29
|
-
if (mapped
|
|
30
|
-
result.add(mapped);
|
|
31
|
-
}
|
|
335
|
+
const mapped = GRAPH.synonyms.get(lower);
|
|
336
|
+
if (mapped) result.add(mapped);
|
|
32
337
|
}
|
|
33
338
|
return Array.from(result);
|
|
34
339
|
}
|
|
35
|
-
var VOCABULARY, SYNONYMS
|
|
340
|
+
var GRAPH, VOCABULARY, SYNONYMS;
|
|
341
|
+
var init_vocab = __esm({
|
|
342
|
+
"../../packages/core/src/vocab/index.ts"() {
|
|
343
|
+
"use strict";
|
|
344
|
+
init_graph_data();
|
|
345
|
+
init_closure();
|
|
346
|
+
init_types2();
|
|
347
|
+
init_closure();
|
|
348
|
+
init_graph_data();
|
|
349
|
+
GRAPH = buildGraph(VOCAB_NODES);
|
|
350
|
+
VOCABULARY = [...GRAPH.ids];
|
|
351
|
+
SYNONYMS = Object.fromEntries(GRAPH.synonyms);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// ../../packages/core/src/vocabulary.ts
|
|
36
356
|
var init_vocabulary = __esm({
|
|
37
357
|
"../../packages/core/src/vocabulary.ts"() {
|
|
38
358
|
"use strict";
|
|
39
|
-
|
|
40
|
-
// Languages
|
|
41
|
-
"typescript",
|
|
42
|
-
"javascript",
|
|
43
|
-
"python",
|
|
44
|
-
"go",
|
|
45
|
-
"rust",
|
|
46
|
-
"java",
|
|
47
|
-
"ruby",
|
|
48
|
-
"elixir",
|
|
49
|
-
"scala",
|
|
50
|
-
"kotlin",
|
|
51
|
-
"swift",
|
|
52
|
-
"cpp",
|
|
53
|
-
"csharp",
|
|
54
|
-
"php",
|
|
55
|
-
"haskell",
|
|
56
|
-
"clojure",
|
|
57
|
-
"r",
|
|
58
|
-
// Frontend frameworks / libs
|
|
59
|
-
"react",
|
|
60
|
-
"nextjs",
|
|
61
|
-
"vue",
|
|
62
|
-
"nuxt",
|
|
63
|
-
"svelte",
|
|
64
|
-
"angular",
|
|
65
|
-
"solidjs",
|
|
66
|
-
"tailwind",
|
|
67
|
-
"css",
|
|
68
|
-
"html",
|
|
69
|
-
"graphql",
|
|
70
|
-
"trpc",
|
|
71
|
-
// Backend frameworks
|
|
72
|
-
"nodejs",
|
|
73
|
-
"express",
|
|
74
|
-
"fastify",
|
|
75
|
-
"nestjs",
|
|
76
|
-
"django",
|
|
77
|
-
"fastapi",
|
|
78
|
-
"flask",
|
|
79
|
-
"rails",
|
|
80
|
-
"spring",
|
|
81
|
-
"actix",
|
|
82
|
-
"gin",
|
|
83
|
-
"phoenix",
|
|
84
|
-
"laravel",
|
|
85
|
-
"dotnet",
|
|
86
|
-
// Infrastructure & DevOps
|
|
87
|
-
"kubernetes",
|
|
88
|
-
"docker",
|
|
89
|
-
"terraform",
|
|
90
|
-
"aws",
|
|
91
|
-
"gcp",
|
|
92
|
-
"azure",
|
|
93
|
-
"ci-cd",
|
|
94
|
-
"github-actions",
|
|
95
|
-
"linux",
|
|
96
|
-
"nginx",
|
|
97
|
-
"pulumi",
|
|
98
|
-
"ansible",
|
|
99
|
-
"prometheus",
|
|
100
|
-
"grafana",
|
|
101
|
-
"datadog",
|
|
102
|
-
"opentelemetry",
|
|
103
|
-
// Data & ML
|
|
104
|
-
"postgresql",
|
|
105
|
-
"mysql",
|
|
106
|
-
"sqlite",
|
|
107
|
-
"mongodb",
|
|
108
|
-
"redis",
|
|
109
|
-
"elasticsearch",
|
|
110
|
-
"kafka",
|
|
111
|
-
"rabbitmq",
|
|
112
|
-
"data-engineering",
|
|
113
|
-
"spark",
|
|
114
|
-
"airflow",
|
|
115
|
-
"dbt",
|
|
116
|
-
"ml",
|
|
117
|
-
"llm",
|
|
118
|
-
"pytorch",
|
|
119
|
-
"tensorflow",
|
|
120
|
-
"pandas",
|
|
121
|
-
"numpy",
|
|
122
|
-
// Domains / capabilities
|
|
123
|
-
"oauth",
|
|
124
|
-
"authentication",
|
|
125
|
-
"security",
|
|
126
|
-
"payments",
|
|
127
|
-
"billing",
|
|
128
|
-
"frontend",
|
|
129
|
-
"backend",
|
|
130
|
-
"devops",
|
|
131
|
-
"mobile",
|
|
132
|
-
"ios",
|
|
133
|
-
"android",
|
|
134
|
-
"api-design",
|
|
135
|
-
"microservices",
|
|
136
|
-
"websockets",
|
|
137
|
-
"testing",
|
|
138
|
-
"accessibility",
|
|
139
|
-
"seo",
|
|
140
|
-
"performance",
|
|
141
|
-
"observability",
|
|
142
|
-
"search",
|
|
143
|
-
"realtime"
|
|
144
|
-
];
|
|
145
|
-
SYNONYMS = {
|
|
146
|
-
// Kubernetes aliases
|
|
147
|
-
"k8s": "kubernetes",
|
|
148
|
-
"kube": "kubernetes",
|
|
149
|
-
// Auth / identity
|
|
150
|
-
"passport": "authentication",
|
|
151
|
-
"oauth2": "oauth",
|
|
152
|
-
"oidc": "oauth",
|
|
153
|
-
"jwt": "authentication",
|
|
154
|
-
"saml": "authentication",
|
|
155
|
-
"auth0": "authentication",
|
|
156
|
-
"clerk": "authentication",
|
|
157
|
-
"nextauth": "authentication",
|
|
158
|
-
// Payments
|
|
159
|
-
"@stripe/stripe-js": "payments",
|
|
160
|
-
"stripe": "payments",
|
|
161
|
-
"braintree": "payments",
|
|
162
|
-
"paddle": "payments",
|
|
163
|
-
"lemonsqueezy": "payments",
|
|
164
|
-
"recurly": "billing",
|
|
165
|
-
"chargebee": "billing",
|
|
166
|
-
// Framework / lib aliases
|
|
167
|
-
"next": "nextjs",
|
|
168
|
-
"next.js": "nextjs",
|
|
169
|
-
"nuxt.js": "nuxt",
|
|
170
|
-
"vue.js": "vue",
|
|
171
|
-
"angular.js": "angular",
|
|
172
|
-
"angularjs": "angular",
|
|
173
|
-
"express.js": "express",
|
|
174
|
-
"expressjs": "express",
|
|
175
|
-
"fastapi": "fastapi",
|
|
176
|
-
"nest": "nestjs",
|
|
177
|
-
"nest.js": "nestjs",
|
|
178
|
-
"sveltekit": "svelte",
|
|
179
|
-
// Language aliases
|
|
180
|
-
"ts": "typescript",
|
|
181
|
-
"js": "javascript",
|
|
182
|
-
"py": "python",
|
|
183
|
-
"golang": "go",
|
|
184
|
-
"c++": "cpp",
|
|
185
|
-
"c#": "csharp",
|
|
186
|
-
".net": "dotnet",
|
|
187
|
-
"asp.net": "dotnet",
|
|
188
|
-
// DB aliases
|
|
189
|
-
"postgres": "postgresql",
|
|
190
|
-
"pg": "postgresql",
|
|
191
|
-
"mongo": "mongodb",
|
|
192
|
-
"elastic": "elasticsearch",
|
|
193
|
-
// Cloud aliases
|
|
194
|
-
"amazon web services": "aws",
|
|
195
|
-
"google cloud": "gcp",
|
|
196
|
-
"google cloud platform": "gcp",
|
|
197
|
-
"microsoft azure": "azure",
|
|
198
|
-
// CI/CD aliases
|
|
199
|
-
"github actions": "github-actions",
|
|
200
|
-
"circle ci": "ci-cd",
|
|
201
|
-
"circleci": "ci-cd",
|
|
202
|
-
"jenkins": "ci-cd",
|
|
203
|
-
"gitlab ci": "ci-cd",
|
|
204
|
-
"travis": "ci-cd",
|
|
205
|
-
// Mobile
|
|
206
|
-
"react native": "mobile",
|
|
207
|
-
"flutter": "mobile",
|
|
208
|
-
"expo": "mobile",
|
|
209
|
-
// AI / ML
|
|
210
|
-
"openai": "llm",
|
|
211
|
-
"anthropic": "llm",
|
|
212
|
-
"langchain": "llm",
|
|
213
|
-
"llamaindex": "llm",
|
|
214
|
-
"hugging face": "ml",
|
|
215
|
-
"huggingface": "ml",
|
|
216
|
-
"scikit-learn": "ml",
|
|
217
|
-
"sklearn": "ml",
|
|
218
|
-
// Data pipeline
|
|
219
|
-
"apache kafka": "kafka",
|
|
220
|
-
"apache spark": "spark",
|
|
221
|
-
"apache airflow": "airflow",
|
|
222
|
-
// Misc
|
|
223
|
-
"tailwindcss": "tailwind",
|
|
224
|
-
"tw": "tailwind",
|
|
225
|
-
"gql": "graphql",
|
|
226
|
-
"ws": "websockets",
|
|
227
|
-
"socket.io": "websockets",
|
|
228
|
-
"jest": "testing",
|
|
229
|
-
"vitest": "testing",
|
|
230
|
-
"playwright": "testing",
|
|
231
|
-
"cypress": "testing"
|
|
232
|
-
};
|
|
233
|
-
VOCAB_SET = new Set(VOCABULARY);
|
|
359
|
+
init_vocab();
|
|
234
360
|
}
|
|
235
361
|
});
|
|
236
362
|
|
|
@@ -238,6 +364,7 @@ var init_vocabulary = __esm({
|
|
|
238
364
|
var init_matcher = __esm({
|
|
239
365
|
"../../packages/core/src/matcher.ts"() {
|
|
240
366
|
"use strict";
|
|
367
|
+
init_vocabulary();
|
|
241
368
|
}
|
|
242
369
|
});
|
|
243
370
|
|
|
@@ -273,11 +400,19 @@ var init_himalayas = __esm({
|
|
|
273
400
|
}
|
|
274
401
|
});
|
|
275
402
|
|
|
403
|
+
// ../../packages/core/src/feeds/entities.ts
|
|
404
|
+
var init_entities = __esm({
|
|
405
|
+
"../../packages/core/src/feeds/entities.ts"() {
|
|
406
|
+
"use strict";
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
|
|
276
410
|
// ../../packages/core/src/feeds/wwr.ts
|
|
277
411
|
var init_wwr = __esm({
|
|
278
412
|
"../../packages/core/src/feeds/wwr.ts"() {
|
|
279
413
|
"use strict";
|
|
280
414
|
init_vocabulary();
|
|
415
|
+
init_entities();
|
|
281
416
|
}
|
|
282
417
|
});
|
|
283
418
|
|
|
@@ -286,6 +421,24 @@ var init_hn = __esm({
|
|
|
286
421
|
"../../packages/core/src/feeds/hn.ts"() {
|
|
287
422
|
"use strict";
|
|
288
423
|
init_vocabulary();
|
|
424
|
+
init_entities();
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
// ../../packages/core/src/feeds/bounty-gate.ts
|
|
429
|
+
var init_bounty_gate = __esm({
|
|
430
|
+
"../../packages/core/src/feeds/bounty-gate.ts"() {
|
|
431
|
+
"use strict";
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
// ../../packages/core/src/feeds/github-bounties.ts
|
|
436
|
+
var init_github_bounties = __esm({
|
|
437
|
+
"../../packages/core/src/feeds/github-bounties.ts"() {
|
|
438
|
+
"use strict";
|
|
439
|
+
init_vocabulary();
|
|
440
|
+
init_entities();
|
|
441
|
+
init_bounty_gate();
|
|
289
442
|
}
|
|
290
443
|
});
|
|
291
444
|
|
|
@@ -303,6 +456,8 @@ var init_feeds = __esm({
|
|
|
303
456
|
init_himalayas();
|
|
304
457
|
init_wwr();
|
|
305
458
|
init_hn();
|
|
459
|
+
init_github_bounties();
|
|
460
|
+
init_bounty_gate();
|
|
306
461
|
GREENHOUSE_SLUGS_BY_TIER = {
|
|
307
462
|
bigco: [
|
|
308
463
|
"stripe",
|
|
@@ -411,13 +566,22 @@ var init_feeds = __esm({
|
|
|
411
566
|
}
|
|
412
567
|
});
|
|
413
568
|
|
|
414
|
-
// ../../packages/core/src/
|
|
569
|
+
// ../../packages/core/src/partners.ts
|
|
415
570
|
import { readFileSync } from "fs";
|
|
416
571
|
import { join } from "path";
|
|
417
572
|
import { fileURLToPath } from "url";
|
|
418
|
-
var
|
|
419
|
-
|
|
573
|
+
var EXAMPLE_BUYER, BUYER_REGISTRY;
|
|
574
|
+
var init_partners = __esm({
|
|
575
|
+
"../../packages/core/src/partners.ts"() {
|
|
420
576
|
"use strict";
|
|
577
|
+
EXAMPLE_BUYER = {
|
|
578
|
+
id: "northstar",
|
|
579
|
+
legalName: "Northstar Talent Partners",
|
|
580
|
+
matchCriteria: { roleTypes: ["full_time"] }
|
|
581
|
+
};
|
|
582
|
+
BUYER_REGISTRY = {
|
|
583
|
+
[EXAMPLE_BUYER.id]: EXAMPLE_BUYER
|
|
584
|
+
};
|
|
421
585
|
}
|
|
422
586
|
});
|
|
423
587
|
|
|
@@ -426,7 +590,7 @@ var init_indexer = __esm({
|
|
|
426
590
|
"../../packages/core/src/indexer.ts"() {
|
|
427
591
|
"use strict";
|
|
428
592
|
init_feeds();
|
|
429
|
-
|
|
593
|
+
init_partners();
|
|
430
594
|
}
|
|
431
595
|
});
|
|
432
596
|
|
|
@@ -447,7 +611,7 @@ var init_src = __esm({
|
|
|
447
611
|
init_matcher();
|
|
448
612
|
init_feeds();
|
|
449
613
|
init_indexer();
|
|
450
|
-
|
|
614
|
+
init_partners();
|
|
451
615
|
init_github();
|
|
452
616
|
}
|
|
453
617
|
});
|
|
@@ -458,35 +622,31 @@ __export(signal_exports, {
|
|
|
458
622
|
extractFingerprint: () => extractFingerprint
|
|
459
623
|
});
|
|
460
624
|
import { readFileSync as readFileSync2, readdirSync } from "fs";
|
|
461
|
-
import {
|
|
625
|
+
import { execFileSync } from "child_process";
|
|
462
626
|
import { join as join2 } from "path";
|
|
463
|
-
function
|
|
627
|
+
function safeGit(args, cwd) {
|
|
464
628
|
try {
|
|
465
|
-
return
|
|
629
|
+
return execFileSync("git", ["-C", cwd, ...args], {
|
|
630
|
+
timeout: 2e3,
|
|
631
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
632
|
+
}).toString().trim();
|
|
466
633
|
} catch {
|
|
467
634
|
return "";
|
|
468
635
|
}
|
|
469
636
|
}
|
|
470
637
|
function isEmployerContext(cwd) {
|
|
471
|
-
const
|
|
638
|
+
const inRepo = safeGit(["rev-parse", "--is-inside-work-tree"], cwd);
|
|
639
|
+
if (inRepo !== "true") return false;
|
|
640
|
+
const remote = safeGit(["remote", "get-url", "origin"], cwd);
|
|
472
641
|
if (remote) {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
if (host && !PERSONAL_GIT_HOSTS.has(host)) {
|
|
478
|
-
return true;
|
|
479
|
-
}
|
|
480
|
-
} catch {
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
const email = safeExec('git -C "' + cwd + '" config user.email 2>/dev/null');
|
|
484
|
-
if (email) {
|
|
485
|
-
const domain = email.split("@")[1]?.toLowerCase() ?? "";
|
|
486
|
-
if (domain && !PERSONAL_EMAIL_DOMAINS.has(domain)) {
|
|
487
|
-
return true;
|
|
488
|
-
}
|
|
642
|
+
const sshMatch = remote.match(/^git@([^:]+):/);
|
|
643
|
+
const httpsMatch = remote.match(/^https?:\/\/([^/]+)/);
|
|
644
|
+
const host = (sshMatch?.[1] ?? httpsMatch?.[1] ?? "").toLowerCase();
|
|
645
|
+
if (host) return !PERSONAL_GIT_HOSTS.has(host);
|
|
489
646
|
}
|
|
647
|
+
const email = safeGit(["config", "user.email"], cwd);
|
|
648
|
+
const domain = email.split("@")[1]?.toLowerCase() ?? "";
|
|
649
|
+
if (domain) return !PERSONAL_EMAIL_DOMAINS.has(domain);
|
|
490
650
|
return false;
|
|
491
651
|
}
|
|
492
652
|
function readJsonSafe(path) {
|
|
@@ -509,10 +669,24 @@ function tokensFromPackageJson(cwd) {
|
|
|
509
669
|
const p = pkg;
|
|
510
670
|
const deps = {
|
|
511
671
|
...typeof p["dependencies"] === "object" ? p["dependencies"] : {},
|
|
512
|
-
...typeof p["devDependencies"] === "object" ? p["devDependencies"] : {}
|
|
672
|
+
...typeof p["devDependencies"] === "object" ? p["devDependencies"] : {},
|
|
673
|
+
...typeof p["peerDependencies"] === "object" ? p["peerDependencies"] : {}
|
|
513
674
|
};
|
|
514
675
|
return Object.keys(deps);
|
|
515
676
|
}
|
|
677
|
+
function workspaceMemberDirs(cwd) {
|
|
678
|
+
const dirs = [cwd];
|
|
679
|
+
for (const group of ["apps", "packages"]) {
|
|
680
|
+
try {
|
|
681
|
+
const groupDir = join2(cwd, group);
|
|
682
|
+
for (const e of readdirSync(groupDir, { withFileTypes: true })) {
|
|
683
|
+
if (e.isDirectory() && !e.isSymbolicLink()) dirs.push(join2(groupDir, e.name));
|
|
684
|
+
}
|
|
685
|
+
} catch {
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
return dirs;
|
|
689
|
+
}
|
|
516
690
|
function tokensFromRequirementsTxt(cwd) {
|
|
517
691
|
const content = readFileSafe(join2(cwd, "requirements.txt"));
|
|
518
692
|
if (!content) return [];
|
|
@@ -520,14 +694,26 @@ function tokensFromRequirementsTxt(cwd) {
|
|
|
520
694
|
}
|
|
521
695
|
function tokensFromGoMod(cwd) {
|
|
522
696
|
const content = readFileSafe(join2(cwd, "go.mod"));
|
|
523
|
-
if (!content) return [
|
|
697
|
+
if (!content) return [];
|
|
524
698
|
const requires = Array.from(content.matchAll(/^\s+([^\s]+)\s+v/gm)).map((m) => m[1].split("/").pop() ?? "").filter(Boolean);
|
|
525
699
|
return ["go", ...requires];
|
|
526
700
|
}
|
|
527
701
|
function tokensFromCargoToml(cwd) {
|
|
528
702
|
const content = readFileSafe(join2(cwd, "Cargo.toml"));
|
|
529
703
|
if (!content) return [];
|
|
530
|
-
const deps =
|
|
704
|
+
const deps = [];
|
|
705
|
+
let inDeps = false;
|
|
706
|
+
for (const line of content.split("\n")) {
|
|
707
|
+
const trimmed = line.trim();
|
|
708
|
+
const section = trimmed.match(/^\[([^\]]+)\]/);
|
|
709
|
+
if (section) {
|
|
710
|
+
inDeps = /(^|\.)(dependencies|dev-dependencies|build-dependencies)$/.test(section[1].trim());
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
if (!inDeps) continue;
|
|
714
|
+
const key = trimmed.match(/^([a-zA-Z0-9_-]+)\s*=/);
|
|
715
|
+
if (key) deps.push(key[1].toLowerCase());
|
|
716
|
+
}
|
|
531
717
|
return ["rust", ...deps];
|
|
532
718
|
}
|
|
533
719
|
function tokensFromFileExtensions(cwd) {
|
|
@@ -567,11 +753,7 @@ function inferSeniority(rawTokens) {
|
|
|
567
753
|
"opentelemetry",
|
|
568
754
|
"prometheus",
|
|
569
755
|
"grafana",
|
|
570
|
-
"microservices"
|
|
571
|
-
"api-design",
|
|
572
|
-
"security",
|
|
573
|
-
"oauth",
|
|
574
|
-
"payments"
|
|
756
|
+
"microservices"
|
|
575
757
|
]);
|
|
576
758
|
const midSignals = /* @__PURE__ */ new Set([
|
|
577
759
|
"docker",
|
|
@@ -581,7 +763,11 @@ function inferSeniority(rawTokens) {
|
|
|
581
763
|
"postgresql",
|
|
582
764
|
"redis",
|
|
583
765
|
"graphql",
|
|
584
|
-
"trpc"
|
|
766
|
+
"trpc",
|
|
767
|
+
"api-design",
|
|
768
|
+
"security",
|
|
769
|
+
"oauth",
|
|
770
|
+
"payments"
|
|
585
771
|
]);
|
|
586
772
|
const normalized = new Set(normalize(rawTokens));
|
|
587
773
|
const seniorHits = [...normalized].filter((t) => seniorSignals.has(t)).length;
|
|
@@ -592,13 +778,16 @@ function inferSeniority(rawTokens) {
|
|
|
592
778
|
}
|
|
593
779
|
function extractFingerprint(cwd) {
|
|
594
780
|
const employer = isEmployerContext(cwd);
|
|
595
|
-
const rawTokens = [
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
781
|
+
const rawTokens = [];
|
|
782
|
+
for (const dir of workspaceMemberDirs(cwd)) {
|
|
783
|
+
rawTokens.push(
|
|
784
|
+
...tokensFromPackageJson(dir),
|
|
785
|
+
...tokensFromRequirementsTxt(dir),
|
|
786
|
+
...tokensFromGoMod(dir),
|
|
787
|
+
...tokensFromCargoToml(dir),
|
|
788
|
+
...tokensFromFileExtensions(dir)
|
|
789
|
+
);
|
|
790
|
+
}
|
|
602
791
|
let skillTags = normalize(rawTokens);
|
|
603
792
|
if (employer) {
|
|
604
793
|
skillTags = skillTags.filter((t) => LANGUAGE_TAGS.has(t));
|
|
@@ -783,10 +972,10 @@ function migrateTagWeights(profile) {
|
|
|
783
972
|
if (!profile.tagWeights) {
|
|
784
973
|
profile.tagWeights = {};
|
|
785
974
|
}
|
|
786
|
-
const
|
|
975
|
+
const seed = profile.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
787
976
|
for (const tag of profile.skillTags) {
|
|
788
977
|
if (!profile.tagWeights[tag]) {
|
|
789
|
-
profile.tagWeights[tag] = { count: 1, firstSeen:
|
|
978
|
+
profile.tagWeights[tag] = { count: 1, firstSeen: seed, lastSeen: seed, sessions: 1 };
|
|
790
979
|
}
|
|
791
980
|
}
|
|
792
981
|
}
|
|
@@ -812,7 +1001,7 @@ async function writeProfile(profile) {
|
|
|
812
1001
|
const blob = encrypt(JSON.stringify(profile), key);
|
|
813
1002
|
writeFileSync(PROFILE_FILE, JSON.stringify(blob, null, 2), { encoding: "utf8" });
|
|
814
1003
|
}
|
|
815
|
-
function accumulateSession(profile, tags, isEmployerContext2, inferredSeniority) {
|
|
1004
|
+
function accumulateSession(profile, tags, isEmployerContext2, inferredSeniority, seniorityIsAuthoritative = false) {
|
|
816
1005
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
817
1006
|
let filtered = normalize(tags);
|
|
818
1007
|
if (isEmployerContext2) {
|
|
@@ -830,7 +1019,9 @@ function accumulateSession(profile, tags, isEmployerContext2, inferredSeniority)
|
|
|
830
1019
|
}
|
|
831
1020
|
}
|
|
832
1021
|
if (inferredSeniority && !isEmployerContext2) {
|
|
833
|
-
profile.
|
|
1022
|
+
if (seniorityIsAuthoritative || !profile.github) {
|
|
1023
|
+
profile.seniority = inferredSeniority;
|
|
1024
|
+
}
|
|
834
1025
|
}
|
|
835
1026
|
}
|
|
836
1027
|
async function accumulateTags(rawTokens, isEmployerContext2, inferredSeniority) {
|
|
@@ -838,12 +1029,14 @@ async function accumulateTags(rawTokens, isEmployerContext2, inferredSeniority)
|
|
|
838
1029
|
accumulateSession(profile, rawTokens, isEmployerContext2, inferredSeniority);
|
|
839
1030
|
await writeProfile(profile);
|
|
840
1031
|
}
|
|
841
|
-
function accumulateGitHubTags(profile, tags) {
|
|
1032
|
+
function accumulateGitHubTags(profile, tags, inferredSeniority) {
|
|
842
1033
|
accumulateSession(
|
|
843
1034
|
profile,
|
|
844
1035
|
tags,
|
|
845
1036
|
/* isEmployerContext */
|
|
846
|
-
false
|
|
1037
|
+
false,
|
|
1038
|
+
inferredSeniority,
|
|
1039
|
+
true
|
|
847
1040
|
);
|
|
848
1041
|
}
|
|
849
1042
|
async function listSavedJobs() {
|