terminalhire 0.2.4 → 0.3.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/dist/bin/jpi-bounties.js +2031 -0
- package/dist/bin/jpi-dispatch.js +1174 -473
- 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 +757 -311
- package/dist/bin/jpi-save.js +381 -213
- package/dist/bin/jpi-sync.js +502 -230
- 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/src/github-auth.js
CHANGED
|
@@ -22,7 +22,7 @@ var IV_BYTES = 12;
|
|
|
22
22
|
var GITHUB_SCOPE = "read:user";
|
|
23
23
|
var DEVICE_CODE_URL = "https://github.com/login/device/code";
|
|
24
24
|
var ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
|
|
25
|
-
var
|
|
25
|
+
var BAKED_IN_CLIENT_ID = "Ov23lignE2ZSBe0J3a6B";
|
|
26
26
|
async function loadKey() {
|
|
27
27
|
try {
|
|
28
28
|
const kt = await import("keytar");
|
|
@@ -92,7 +92,7 @@ async function runDeviceFlow() {
|
|
|
92
92
|
await writeGitHubToken(MOCK_TOKEN);
|
|
93
93
|
return MOCK_LOGIN;
|
|
94
94
|
}
|
|
95
|
-
const clientId = process.env["GITHUB_DEVICE_CLIENT_ID"] ?? process.env["GITHUB_CLIENT_ID"] ??
|
|
95
|
+
const clientId = process.env["GITHUB_DEVICE_CLIENT_ID"] ?? process.env["GITHUB_CLIENT_ID"] ?? BAKED_IN_CLIENT_ID;
|
|
96
96
|
if (clientId === "Iv1.PLACEHOLDER_REGISTER_YOUR_APP") {
|
|
97
97
|
console.warn("\nWarning: GITHUB_CLIENT_ID env var looks like a placeholder.");
|
|
98
98
|
console.warn("Remove it to use the baked-in client ID, or set it to your own OAuth App Client ID.\n");
|
|
@@ -115,7 +115,7 @@ async function runDeviceFlow() {
|
|
|
115
115
|
console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
116
116
|
console.log(` 1. Open: ${deviceData.verification_uri}`);
|
|
117
117
|
console.log(` 2. Enter code: ${deviceData.user_code}`);
|
|
118
|
-
console.log(' 3. Authorize "
|
|
118
|
+
console.log(' 3. Authorize "Terminalhire" (scope: read:user \u2014 public data only)');
|
|
119
119
|
console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
120
120
|
console.log(" Waiting for authorization...");
|
|
121
121
|
console.log("");
|
package/dist/src/profile.js
CHANGED
|
@@ -13,214 +13,308 @@ import {
|
|
|
13
13
|
import { join as join2 } from "path";
|
|
14
14
|
import { homedir } from "os";
|
|
15
15
|
|
|
16
|
-
// ../../packages/core/src/
|
|
17
|
-
var
|
|
18
|
-
// Languages
|
|
19
|
-
"typescript",
|
|
20
|
-
"javascript",
|
|
21
|
-
"python",
|
|
22
|
-
"go",
|
|
23
|
-
"rust",
|
|
24
|
-
"java",
|
|
25
|
-
"ruby",
|
|
26
|
-
"elixir",
|
|
27
|
-
"scala",
|
|
28
|
-
"kotlin",
|
|
29
|
-
"swift",
|
|
30
|
-
"cpp",
|
|
31
|
-
"csharp",
|
|
32
|
-
"php",
|
|
33
|
-
"haskell",
|
|
34
|
-
"clojure",
|
|
35
|
-
"r",
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
"
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
"
|
|
120
|
-
"
|
|
121
|
-
"
|
|
16
|
+
// ../../packages/core/src/vocab/graph.data.ts
|
|
17
|
+
var VOCAB_NODES = [
|
|
18
|
+
// ── Languages ─────────────────────────────────────────────────────────────
|
|
19
|
+
{ id: "javascript", synonyms: ["js"], related: [{ to: "typescript", w: 0.6 }] },
|
|
20
|
+
{ id: "typescript", parents: ["javascript"], synonyms: ["ts"] },
|
|
21
|
+
{ id: "python", synonyms: ["py"] },
|
|
22
|
+
{ id: "go", synonyms: ["golang"] },
|
|
23
|
+
{ id: "rust" },
|
|
24
|
+
{ id: "java", related: [{ to: "kotlin", w: 0.45 }, { to: "scala", w: 0.4 }] },
|
|
25
|
+
{ id: "ruby" },
|
|
26
|
+
{ id: "elixir" },
|
|
27
|
+
{ id: "scala", related: [{ to: "java", w: 0.4 }] },
|
|
28
|
+
{ id: "kotlin", related: [{ to: "java", w: 0.45 }] },
|
|
29
|
+
{ id: "swift" },
|
|
30
|
+
{ id: "cpp", synonyms: ["c++"] },
|
|
31
|
+
{ id: "csharp", synonyms: ["c#"] },
|
|
32
|
+
{ id: "php" },
|
|
33
|
+
{ id: "haskell" },
|
|
34
|
+
{ id: "clojure" },
|
|
35
|
+
{ id: "r" },
|
|
36
|
+
{ id: "dart" },
|
|
37
|
+
// ── Frontend ──────────────────────────────────────────────────────────────
|
|
38
|
+
{
|
|
39
|
+
id: "react",
|
|
40
|
+
parents: ["javascript"],
|
|
41
|
+
synonyms: ["reactjs"],
|
|
42
|
+
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 }]
|
|
43
|
+
},
|
|
44
|
+
{ id: "nextjs", parents: ["react"], synonyms: ["next", "next.js"], related: [{ to: "remix", w: 0.5 }] },
|
|
45
|
+
{ id: "vue", parents: ["javascript"], synonyms: ["vue.js"], related: [{ to: "nuxt", w: 0.6 }] },
|
|
46
|
+
{ id: "nuxt", parents: ["vue"], synonyms: ["nuxt.js"] },
|
|
47
|
+
{ id: "svelte", parents: ["javascript"], related: [{ to: "sveltekit", w: 0.65 }] },
|
|
48
|
+
{ id: "sveltekit", parents: ["svelte"] },
|
|
49
|
+
{ id: "angular", parents: ["typescript"], synonyms: ["angular.js", "angularjs"] },
|
|
50
|
+
{ id: "solidjs", parents: ["javascript"] },
|
|
51
|
+
{ id: "remix", parents: ["react"], synonyms: ["remix.run"] },
|
|
52
|
+
{ id: "astro", parents: ["javascript"], related: [{ to: "nextjs", w: 0.4 }] },
|
|
53
|
+
{ id: "qwik", parents: ["javascript"] },
|
|
54
|
+
{ id: "tailwind", parents: ["css"], synonyms: ["tailwindcss", "tw"] },
|
|
55
|
+
{ id: "css" },
|
|
56
|
+
{ id: "html" },
|
|
57
|
+
{ id: "redux", parents: ["react"] },
|
|
58
|
+
{ id: "vite", parents: ["frontend"] },
|
|
59
|
+
{ id: "webpack", parents: ["frontend"] },
|
|
60
|
+
{ id: "storybook", parents: ["frontend"] },
|
|
61
|
+
// ── Backend frameworks / runtimes ───────────────────────────────────────────
|
|
62
|
+
{
|
|
63
|
+
id: "nodejs",
|
|
64
|
+
parents: ["javascript"],
|
|
65
|
+
synonyms: ["node", "node.js"],
|
|
66
|
+
related: [{ to: "express", w: 0.5 }, { to: "fastify", w: 0.45 }, { to: "nestjs", w: 0.45 }]
|
|
67
|
+
},
|
|
68
|
+
{ id: "express", parents: ["nodejs"], synonyms: ["express.js", "expressjs"], related: [{ to: "fastify", w: 0.5 }] },
|
|
69
|
+
{ id: "fastify", parents: ["nodejs"] },
|
|
70
|
+
{ id: "nestjs", parents: ["nodejs"], synonyms: ["nest", "nest.js"] },
|
|
71
|
+
{ id: "hono", parents: ["nodejs"] },
|
|
72
|
+
{ id: "deno", parents: ["javascript"], related: [{ to: "nodejs", w: 0.5 }, { to: "bun", w: 0.5 }] },
|
|
73
|
+
{ id: "bun", parents: ["javascript"], related: [{ to: "nodejs", w: 0.5 }] },
|
|
74
|
+
{ id: "django", parents: ["python"], related: [{ to: "flask", w: 0.5 }, { to: "fastapi", w: 0.45 }] },
|
|
75
|
+
{ id: "fastapi", parents: ["python"], related: [{ to: "flask", w: 0.55 }, { to: "django", w: 0.45 }] },
|
|
76
|
+
{ id: "flask", parents: ["python"] },
|
|
77
|
+
{ id: "rails", parents: ["ruby"], synonyms: ["ruby-on-rails", "ror"] },
|
|
78
|
+
{ id: "spring", parents: ["java"], synonyms: ["spring-boot", "springboot"] },
|
|
79
|
+
{ id: "actix", parents: ["rust"] },
|
|
80
|
+
{ id: "gin", parents: ["go"] },
|
|
81
|
+
{ id: "phoenix", parents: ["elixir"] },
|
|
82
|
+
{ id: "laravel", parents: ["php"] },
|
|
83
|
+
{ id: "dotnet", parents: ["csharp"], synonyms: [".net", "asp.net", "dotnet-core"] },
|
|
84
|
+
// ── Infrastructure & DevOps ─────────────────────────────────────────────────
|
|
85
|
+
{ 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 }] },
|
|
86
|
+
{ id: "docker", parents: ["devops"], related: [{ to: "kubernetes", w: 0.5 }] },
|
|
87
|
+
{ id: "terraform", synonyms: ["tf"], related: [{ to: "pulumi", w: 0.55 }, { to: "ansible", w: 0.4 }, { to: "aws", w: 0.4 }] },
|
|
88
|
+
{ id: "pulumi", related: [{ to: "terraform", w: 0.55 }] },
|
|
89
|
+
{ id: "ansible" },
|
|
90
|
+
{ id: "aws", synonyms: ["amazon-web-services"], related: [{ to: "gcp", w: 0.4 }, { to: "azure", w: 0.4 }] },
|
|
91
|
+
{ id: "gcp", synonyms: ["google-cloud", "google-cloud-platform"], related: [{ to: "aws", w: 0.4 }, { to: "azure", w: 0.4 }] },
|
|
92
|
+
{ id: "azure", synonyms: ["microsoft-azure"], related: [{ to: "aws", w: 0.4 }] },
|
|
93
|
+
{ id: "ci-cd", synonyms: ["cicd", "jenkins", "circleci", "circle-ci", "travis"], related: [{ to: "github-actions", w: 0.6 }, { to: "gitlab-ci", w: 0.6 }] },
|
|
94
|
+
{ id: "github-actions", parents: ["ci-cd"], synonyms: ["github-action"] },
|
|
95
|
+
{ id: "gitlab-ci", parents: ["ci-cd"], synonyms: ["gitlab"] },
|
|
96
|
+
{ id: "linux" },
|
|
97
|
+
{ id: "nginx" },
|
|
98
|
+
{ id: "prometheus", parents: ["observability"], related: [{ to: "grafana", w: 0.6 }] },
|
|
99
|
+
{ id: "grafana", parents: ["observability"] },
|
|
100
|
+
{ id: "datadog", parents: ["observability"] },
|
|
101
|
+
{ id: "opentelemetry", parents: ["observability"], synonyms: ["otel"] },
|
|
102
|
+
{ id: "vercel", related: [{ to: "netlify", w: 0.5 }, { to: "nextjs", w: 0.4 }] },
|
|
103
|
+
{ id: "netlify" },
|
|
104
|
+
{ id: "fly", synonyms: ["fly.io"], related: [{ to: "railway", w: 0.5 }, { to: "render", w: 0.5 }] },
|
|
105
|
+
{ id: "railway", related: [{ to: "render", w: 0.5 }] },
|
|
106
|
+
{ id: "render" },
|
|
107
|
+
{ id: "cloudflare", synonyms: ["cloudflare-workers"] },
|
|
108
|
+
{ id: "helm", parents: ["kubernetes"] },
|
|
109
|
+
{ id: "argocd", parents: ["kubernetes"] },
|
|
110
|
+
{ id: "serverless", parents: ["devops"] },
|
|
111
|
+
// ── Databases & storage ─────────────────────────────────────────────────────
|
|
112
|
+
{ id: "postgresql", synonyms: ["postgres", "pg"], related: [{ to: "mysql", w: 0.45 }, { to: "sqlite", w: 0.4 }] },
|
|
113
|
+
{ id: "mysql", related: [{ to: "postgresql", w: 0.45 }] },
|
|
114
|
+
{ id: "sqlite" },
|
|
115
|
+
{ id: "mongodb", synonyms: ["mongo"] },
|
|
116
|
+
{ id: "redis", related: [{ to: "caching", w: 0.5 }] },
|
|
117
|
+
{ id: "elasticsearch", synonyms: ["elastic"], related: [{ to: "search", w: 0.55 }] },
|
|
118
|
+
{ id: "kafka", synonyms: ["apache-kafka"], related: [{ to: "rabbitmq", w: 0.5 }, { to: "message-queue", w: 0.55 }] },
|
|
119
|
+
{ id: "rabbitmq", related: [{ to: "message-queue", w: 0.55 }] },
|
|
120
|
+
{ id: "cassandra" },
|
|
121
|
+
{ id: "dynamodb", parents: ["aws"] },
|
|
122
|
+
{ id: "snowflake", parents: ["data-engineering"], related: [{ to: "clickhouse", w: 0.4 }] },
|
|
123
|
+
{ id: "clickhouse", parents: ["data-engineering"], related: [{ to: "duckdb", w: 0.35 }] },
|
|
124
|
+
{ id: "duckdb", parents: ["data-engineering"] },
|
|
125
|
+
{ id: "supabase", related: [{ to: "postgresql", w: 0.5 }, { to: "neon", w: 0.4 }] },
|
|
126
|
+
{ id: "planetscale", related: [{ to: "mysql", w: 0.5 }] },
|
|
127
|
+
{ id: "neon", related: [{ to: "postgresql", w: 0.5 }] },
|
|
128
|
+
{ id: "turso", related: [{ to: "sqlite", w: 0.5 }] },
|
|
129
|
+
{ id: "cockroachdb", related: [{ to: "postgresql", w: 0.45 }] },
|
|
130
|
+
{ id: "prisma", parents: ["backend"], synonyms: ["@prisma/client"], related: [{ to: "drizzle", w: 0.5 }, { to: "typeorm", w: 0.45 }, { to: "sequelize", w: 0.4 }] },
|
|
131
|
+
{ id: "drizzle", synonyms: ["drizzle-orm"], related: [{ to: "prisma", w: 0.5 }] },
|
|
132
|
+
{ id: "sequelize", related: [{ to: "typeorm", w: 0.4 }] },
|
|
133
|
+
{ id: "typeorm", related: [{ to: "prisma", w: 0.45 }] },
|
|
134
|
+
{ id: "sqlalchemy", parents: ["python"] },
|
|
135
|
+
// ── Data engineering & ML ───────────────────────────────────────────────────
|
|
136
|
+
{ id: "data-engineering", synonyms: ["data-eng"], related: [{ to: "spark", w: 0.5 }, { to: "airflow", w: 0.5 }, { to: "dbt", w: 0.45 }] },
|
|
137
|
+
{ id: "spark", parents: ["data-engineering"], synonyms: ["apache-spark"] },
|
|
138
|
+
{ id: "airflow", parents: ["data-engineering"], synonyms: ["apache-airflow"] },
|
|
139
|
+
{ id: "dbt", parents: ["data-engineering"] },
|
|
140
|
+
{ id: "ml", synonyms: ["machine-learning"], related: [{ to: "pytorch", w: 0.5 }, { to: "tensorflow", w: 0.5 }, { to: "scikit-learn", w: 0.5 }] },
|
|
141
|
+
{ 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 }] },
|
|
142
|
+
{ id: "pytorch", parents: ["ml"], synonyms: ["torch"], related: [{ to: "tensorflow", w: 0.5 }] },
|
|
143
|
+
{ id: "tensorflow", parents: ["ml"], synonyms: ["keras", "tf-keras"] },
|
|
144
|
+
{ id: "pandas", parents: ["python"], related: [{ to: "numpy", w: 0.6 }] },
|
|
145
|
+
{ id: "numpy", parents: ["python"] },
|
|
146
|
+
{ id: "scikit-learn", parents: ["ml"], synonyms: ["sklearn"] },
|
|
147
|
+
{ id: "jupyter", parents: ["python"] },
|
|
148
|
+
{ id: "langchain", parents: ["llm"], synonyms: ["llamaindex"] },
|
|
149
|
+
{ id: "huggingface", parents: ["ml"], synonyms: ["hugging-face"] },
|
|
150
|
+
{ id: "openai", parents: ["llm"] },
|
|
151
|
+
{ id: "anthropic", parents: ["llm"], synonyms: ["claude"] },
|
|
152
|
+
{ id: "rag", parents: ["llm"], synonyms: ["retrieval-augmented-generation"] },
|
|
153
|
+
{ id: "mlops", parents: ["ml"], related: [{ to: "devops", w: 0.4 }] },
|
|
154
|
+
// ── Mobile ──────────────────────────────────────────────────────────────────
|
|
155
|
+
{ id: "mobile", related: [{ to: "ios", w: 0.5 }, { to: "android", w: 0.5 }] },
|
|
156
|
+
{ id: "ios", parents: ["mobile", "swift"], related: [{ to: "android", w: 0.4 }] },
|
|
157
|
+
{ id: "android", parents: ["mobile"], related: [{ to: "kotlin", w: 0.4 }] },
|
|
158
|
+
{ id: "swiftui", parents: ["ios", "swift"] },
|
|
159
|
+
{ id: "react-native", parents: ["mobile", "react"], synonyms: ["reactnative"], related: [{ to: "flutter", w: 0.4 }, { to: "expo", w: 0.6 }] },
|
|
160
|
+
{ id: "flutter", parents: ["mobile", "dart"] },
|
|
161
|
+
{ id: "expo", parents: ["react-native"] },
|
|
162
|
+
{ id: "kotlin-multiplatform", parents: ["mobile", "kotlin"], synonyms: ["kmp"] },
|
|
163
|
+
// ── Domains / capabilities ──────────────────────────────────────────────────
|
|
164
|
+
{ id: "frontend", related: [{ to: "react", w: 0.4 }, { to: "css", w: 0.3 }] },
|
|
165
|
+
{ id: "backend", related: [{ to: "api-design", w: 0.4 }, { to: "microservices", w: 0.4 }] },
|
|
166
|
+
{ id: "devops", related: [{ to: "kubernetes", w: 0.4 }, { to: "ci-cd", w: 0.4 }, { to: "docker", w: 0.4 }] },
|
|
167
|
+
{ id: "authentication", synonyms: ["auth", "jwt", "saml", "passport", "auth0", "clerk", "nextauth"], related: [{ to: "oauth", w: 0.6 }, { to: "security", w: 0.5 }] },
|
|
168
|
+
{ id: "oauth", parents: ["authentication"], synonyms: ["oauth2", "oidc"], related: [{ to: "security", w: 0.4 }] },
|
|
169
|
+
{ id: "security", related: [{ to: "authentication", w: 0.5 }] },
|
|
170
|
+
{ id: "payments", synonyms: ["stripe", "braintree", "paddle", "lemonsqueezy", "@stripe/stripe-js"], related: [{ to: "billing", w: 0.6 }] },
|
|
171
|
+
{ id: "billing", synonyms: ["recurly", "chargebee"] },
|
|
172
|
+
{ id: "api-design", synonyms: ["rest", "restful", "rest-api"], related: [{ to: "graphql", w: 0.4 }, { to: "grpc", w: 0.4 }, { to: "backend", w: 0.4 }] },
|
|
173
|
+
{ id: "graphql", synonyms: ["gql"], related: [{ to: "trpc", w: 0.4 }] },
|
|
174
|
+
{ id: "trpc", related: [{ to: "graphql", w: 0.4 }] },
|
|
175
|
+
{ id: "grpc", synonyms: ["grpc-web"], related: [{ to: "microservices", w: 0.3 }] },
|
|
176
|
+
{ id: "microservices" },
|
|
177
|
+
{ id: "websockets", synonyms: ["ws", "socket.io"], related: [{ to: "realtime", w: 0.6 }] },
|
|
178
|
+
{ id: "realtime", synonyms: ["real-time"] },
|
|
179
|
+
{ id: "message-queue", synonyms: ["mq"] },
|
|
180
|
+
{ id: "caching", synonyms: ["cache"] },
|
|
181
|
+
{ id: "search", synonyms: ["full-text-search"] },
|
|
182
|
+
{ id: "observability", synonyms: ["o11y"], related: [{ to: "monitoring", w: 0.6 }] },
|
|
183
|
+
{ id: "monitoring", related: [{ to: "prometheus", w: 0.4 }] },
|
|
184
|
+
{ id: "testing", related: [{ to: "unit-testing", w: 0.5 }, { to: "e2e-testing", w: 0.5 }] },
|
|
185
|
+
{ id: "unit-testing", parents: ["testing"] },
|
|
186
|
+
{ id: "e2e-testing", parents: ["testing"], synonyms: ["e2e", "end-to-end-testing"] },
|
|
187
|
+
{ id: "jest", parents: ["testing"], related: [{ to: "vitest", w: 0.6 }, { to: "mocha", w: 0.5 }] },
|
|
188
|
+
{ id: "vitest", parents: ["testing"], related: [{ to: "jest", w: 0.6 }] },
|
|
189
|
+
{ id: "playwright", parents: ["e2e-testing"], related: [{ to: "cypress", w: 0.6 }] },
|
|
190
|
+
{ id: "cypress", parents: ["e2e-testing"] },
|
|
191
|
+
{ id: "mocha", parents: ["testing"] },
|
|
192
|
+
{ id: "pytest", parents: ["testing", "python"] },
|
|
193
|
+
{ id: "accessibility", synonyms: ["a11y"] },
|
|
194
|
+
{ id: "seo" },
|
|
195
|
+
{ id: "performance", synonyms: ["perf", "web-performance"] }
|
|
122
196
|
];
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
};
|
|
211
|
-
|
|
197
|
+
|
|
198
|
+
// ../../packages/core/src/vocab/closure.ts
|
|
199
|
+
var PARENT_UP = 0.6;
|
|
200
|
+
var PARENT_DOWN = 0.35;
|
|
201
|
+
var DECAY_FLOOR = 0.25;
|
|
202
|
+
function round3(n) {
|
|
203
|
+
return Math.round(n * 1e3) / 1e3;
|
|
204
|
+
}
|
|
205
|
+
function validateGraph(nodes) {
|
|
206
|
+
const ids = /* @__PURE__ */ new Set();
|
|
207
|
+
for (const n of nodes) {
|
|
208
|
+
if (ids.has(n.id)) throw new Error(`vocab: duplicate id "${n.id}"`);
|
|
209
|
+
ids.add(n.id);
|
|
210
|
+
}
|
|
211
|
+
const seenAlias = /* @__PURE__ */ new Map();
|
|
212
|
+
for (const n of nodes) {
|
|
213
|
+
for (const p of n.parents ?? []) {
|
|
214
|
+
if (p === n.id) throw new Error(`vocab: "${n.id}" lists itself as a parent`);
|
|
215
|
+
if (!ids.has(p)) throw new Error(`vocab: "${n.id}" parent "${p}" is not a defined id`);
|
|
216
|
+
}
|
|
217
|
+
for (const e of n.related ?? []) {
|
|
218
|
+
if (e.to === n.id) throw new Error(`vocab: "${n.id}" relates to itself`);
|
|
219
|
+
if (!ids.has(e.to)) throw new Error(`vocab: "${n.id}" related "${e.to}" is not a defined id`);
|
|
220
|
+
if (!(e.w > 0 && e.w <= 1)) throw new Error(`vocab: "${n.id}"\u2192"${e.to}" weight ${e.w} out of (0,1]`);
|
|
221
|
+
}
|
|
222
|
+
for (const s of n.synonyms ?? []) {
|
|
223
|
+
const alias = s.toLowerCase();
|
|
224
|
+
if (ids.has(alias)) throw new Error(`vocab: synonym "${alias}" collides with a canonical id`);
|
|
225
|
+
const prev = seenAlias.get(alias);
|
|
226
|
+
if (prev && prev !== n.id) throw new Error(`vocab: synonym "${alias}" maps to both "${prev}" and "${n.id}"`);
|
|
227
|
+
seenAlias.set(alias, n.id);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
231
|
+
const done = /* @__PURE__ */ new Set();
|
|
232
|
+
const parentMap = new Map(nodes.map((n) => [n.id, n.parents ?? []]));
|
|
233
|
+
const walk = (id, path) => {
|
|
234
|
+
if (done.has(id)) return;
|
|
235
|
+
if (visiting.has(id)) throw new Error(`vocab: parent cycle ${[...path, id].join(" \u2192 ")}`);
|
|
236
|
+
visiting.add(id);
|
|
237
|
+
for (const p of parentMap.get(id) ?? []) walk(p, [...path, id]);
|
|
238
|
+
visiting.delete(id);
|
|
239
|
+
done.add(id);
|
|
240
|
+
};
|
|
241
|
+
for (const n of nodes) walk(n.id, []);
|
|
242
|
+
}
|
|
243
|
+
function buildAdjacency(nodes) {
|
|
244
|
+
const adj = /* @__PURE__ */ new Map();
|
|
245
|
+
const add = (from, to, w) => {
|
|
246
|
+
let m = adj.get(from);
|
|
247
|
+
if (!m) adj.set(from, m = /* @__PURE__ */ new Map());
|
|
248
|
+
if (w > (m.get(to) ?? 0)) m.set(to, w);
|
|
249
|
+
};
|
|
250
|
+
for (const n of nodes) {
|
|
251
|
+
for (const p of n.parents ?? []) {
|
|
252
|
+
add(n.id, p, PARENT_UP);
|
|
253
|
+
add(p, n.id, PARENT_DOWN);
|
|
254
|
+
}
|
|
255
|
+
for (const e of n.related ?? []) {
|
|
256
|
+
add(n.id, e.to, e.w);
|
|
257
|
+
add(e.to, n.id, e.w);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return adj;
|
|
261
|
+
}
|
|
262
|
+
function closureFrom(source, adj) {
|
|
263
|
+
const best = /* @__PURE__ */ new Map();
|
|
264
|
+
for (const [t, w] of adj.get(source) ?? []) {
|
|
265
|
+
if (w >= DECAY_FLOOR) best.set(t, { w: round3(w), via: t });
|
|
266
|
+
}
|
|
267
|
+
const settled = /* @__PURE__ */ new Set([source]);
|
|
268
|
+
while (true) {
|
|
269
|
+
let u;
|
|
270
|
+
let uw = 0;
|
|
271
|
+
for (const [t, e] of best) {
|
|
272
|
+
if (!settled.has(t) && e.w > uw) {
|
|
273
|
+
u = t;
|
|
274
|
+
uw = e.w;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (!u) break;
|
|
278
|
+
settled.add(u);
|
|
279
|
+
const via = best.get(u).via;
|
|
280
|
+
for (const [t, we] of adj.get(u) ?? []) {
|
|
281
|
+
if (settled.has(t)) continue;
|
|
282
|
+
const cand = round3(uw * we);
|
|
283
|
+
if (cand >= DECAY_FLOOR && cand > (best.get(t)?.w ?? 0)) {
|
|
284
|
+
best.set(t, { w: cand, via });
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
best.delete(source);
|
|
289
|
+
return best;
|
|
290
|
+
}
|
|
291
|
+
function buildGraph(nodes) {
|
|
292
|
+
validateGraph(nodes);
|
|
293
|
+
const ids = new Set(nodes.map((n) => n.id));
|
|
294
|
+
const synonyms = /* @__PURE__ */ new Map();
|
|
295
|
+
for (const n of nodes) {
|
|
296
|
+
for (const s of n.synonyms ?? []) synonyms.set(s.toLowerCase(), n.id);
|
|
297
|
+
}
|
|
298
|
+
const adj = buildAdjacency(nodes);
|
|
299
|
+
const closure = /* @__PURE__ */ new Map();
|
|
300
|
+
for (const n of nodes) closure.set(n.id, closureFrom(n.id, adj));
|
|
301
|
+
return { ids, synonyms, closure };
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// ../../packages/core/src/vocab/index.ts
|
|
305
|
+
var GRAPH = buildGraph(VOCAB_NODES);
|
|
306
|
+
var VOCABULARY = [...GRAPH.ids];
|
|
307
|
+
var SYNONYMS = Object.fromEntries(GRAPH.synonyms);
|
|
212
308
|
function normalize(tokens) {
|
|
213
309
|
const result = /* @__PURE__ */ new Set();
|
|
214
310
|
for (const raw of tokens) {
|
|
215
311
|
const lower = raw.toLowerCase().trim();
|
|
216
|
-
if (
|
|
312
|
+
if (GRAPH.ids.has(lower)) {
|
|
217
313
|
result.add(lower);
|
|
218
314
|
continue;
|
|
219
315
|
}
|
|
220
|
-
const mapped =
|
|
221
|
-
if (mapped
|
|
222
|
-
result.add(mapped);
|
|
223
|
-
}
|
|
316
|
+
const mapped = GRAPH.synonyms.get(lower);
|
|
317
|
+
if (mapped) result.add(mapped);
|
|
224
318
|
}
|
|
225
319
|
return Array.from(result);
|
|
226
320
|
}
|
|
@@ -335,10 +429,18 @@ var DEFAULT_GREENHOUSE_SLUGS = flattenTiers(GREENHOUSE_SLUGS_BY_TIER);
|
|
|
335
429
|
var DEFAULT_ASHBY_SLUGS = flattenTiers(ASHBY_SLUGS_BY_TIER);
|
|
336
430
|
var DEFAULT_LEVER_SLUGS = flattenTiers(LEVER_SLUGS_BY_TIER);
|
|
337
431
|
|
|
338
|
-
// ../../packages/core/src/
|
|
432
|
+
// ../../packages/core/src/partners.ts
|
|
339
433
|
import { readFileSync } from "fs";
|
|
340
434
|
import { join } from "path";
|
|
341
435
|
import { fileURLToPath } from "url";
|
|
436
|
+
var EXAMPLE_BUYER = {
|
|
437
|
+
id: "northstar",
|
|
438
|
+
legalName: "Northstar Talent Partners",
|
|
439
|
+
matchCriteria: { roleTypes: ["full_time"] }
|
|
440
|
+
};
|
|
441
|
+
var BUYER_REGISTRY = {
|
|
442
|
+
[EXAMPLE_BUYER.id]: EXAMPLE_BUYER
|
|
443
|
+
};
|
|
342
444
|
|
|
343
445
|
// src/profile.ts
|
|
344
446
|
var TERMINALHIRE_DIR = join2(homedir(), ".terminalhire");
|
|
@@ -415,10 +517,10 @@ function migrateTagWeights(profile) {
|
|
|
415
517
|
if (!profile.tagWeights) {
|
|
416
518
|
profile.tagWeights = {};
|
|
417
519
|
}
|
|
418
|
-
const
|
|
520
|
+
const seed = profile.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
419
521
|
for (const tag of profile.skillTags) {
|
|
420
522
|
if (!profile.tagWeights[tag]) {
|
|
421
|
-
profile.tagWeights[tag] = { count: 1, firstSeen:
|
|
523
|
+
profile.tagWeights[tag] = { count: 1, firstSeen: seed, lastSeen: seed, sessions: 1 };
|
|
422
524
|
}
|
|
423
525
|
}
|
|
424
526
|
}
|
|
@@ -463,7 +565,7 @@ var LANGUAGE_TAGS = /* @__PURE__ */ new Set([
|
|
|
463
565
|
"clojure",
|
|
464
566
|
"r"
|
|
465
567
|
]);
|
|
466
|
-
function accumulateSession(profile, tags, isEmployerContext, inferredSeniority) {
|
|
568
|
+
function accumulateSession(profile, tags, isEmployerContext, inferredSeniority, seniorityIsAuthoritative = false) {
|
|
467
569
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
468
570
|
let filtered = normalize(tags);
|
|
469
571
|
if (isEmployerContext) {
|
|
@@ -481,7 +583,9 @@ function accumulateSession(profile, tags, isEmployerContext, inferredSeniority)
|
|
|
481
583
|
}
|
|
482
584
|
}
|
|
483
585
|
if (inferredSeniority && !isEmployerContext) {
|
|
484
|
-
profile.
|
|
586
|
+
if (seniorityIsAuthoritative || !profile.github) {
|
|
587
|
+
profile.seniority = inferredSeniority;
|
|
588
|
+
}
|
|
485
589
|
}
|
|
486
590
|
}
|
|
487
591
|
async function accumulateTags(rawTokens, isEmployerContext, inferredSeniority) {
|
|
@@ -489,12 +593,14 @@ async function accumulateTags(rawTokens, isEmployerContext, inferredSeniority) {
|
|
|
489
593
|
accumulateSession(profile, rawTokens, isEmployerContext, inferredSeniority);
|
|
490
594
|
await writeProfile(profile);
|
|
491
595
|
}
|
|
492
|
-
function accumulateGitHubTags(profile, tags) {
|
|
596
|
+
function accumulateGitHubTags(profile, tags, inferredSeniority) {
|
|
493
597
|
accumulateSession(
|
|
494
598
|
profile,
|
|
495
599
|
tags,
|
|
496
600
|
/* isEmployerContext */
|
|
497
|
-
false
|
|
601
|
+
false,
|
|
602
|
+
inferredSeniority,
|
|
603
|
+
true
|
|
498
604
|
);
|
|
499
605
|
}
|
|
500
606
|
async function listSavedJobs() {
|