job-forge 2.14.33 → 2.14.34
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/.cursor/rules/main.mdc +9 -3
- package/AGENTS.md +9 -3
- package/CLAUDE.md +9 -3
- package/README.md +8 -4
- package/bin/create-job-forge.mjs +21 -0
- package/bin/job-forge.mjs +69 -0
- package/docs/ARCHITECTURE.md +12 -2
- package/docs/CUSTOMIZATION.md +8 -0
- package/docs/SETUP.md +4 -0
- package/iso/instructions.md +9 -3
- package/lib/jobforge-lineage.mjs +122 -0
- package/lib/jobforge-prioritize.mjs +294 -0
- package/package.json +17 -1
- package/scripts/check-iso-smoke.mjs +2 -0
- package/scripts/lineage.mjs +247 -0
- package/scripts/prioritize.mjs +323 -0
- package/templates/migrations.json +17 -0
- package/templates/prioritize.json +125 -0
- package/verify-pipeline.mjs +48 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"defaults": {
|
|
4
|
+
"profile": "jobforge-next-action",
|
|
5
|
+
"limit": 3
|
|
6
|
+
},
|
|
7
|
+
"profiles": [
|
|
8
|
+
{
|
|
9
|
+
"name": "jobforge-next-action",
|
|
10
|
+
"description": "Rank JobForge follow-up, pipeline, and apply work by fit, urgency, age, and source quality.",
|
|
11
|
+
"criteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "fit-score",
|
|
14
|
+
"label": "Fit score",
|
|
15
|
+
"field": "score",
|
|
16
|
+
"weight": 45,
|
|
17
|
+
"direction": "desc",
|
|
18
|
+
"min": 0,
|
|
19
|
+
"max": 5,
|
|
20
|
+
"required": true
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"id": "urgency",
|
|
24
|
+
"label": "Urgency",
|
|
25
|
+
"field": "urgency",
|
|
26
|
+
"weight": 30,
|
|
27
|
+
"direction": "desc",
|
|
28
|
+
"min": 0,
|
|
29
|
+
"max": 10,
|
|
30
|
+
"default": 0
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "age",
|
|
34
|
+
"label": "Age in days",
|
|
35
|
+
"field": "ageDays",
|
|
36
|
+
"weight": 15,
|
|
37
|
+
"direction": "desc",
|
|
38
|
+
"min": 0,
|
|
39
|
+
"max": 30,
|
|
40
|
+
"default": 0
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "source-quality",
|
|
44
|
+
"label": "Source quality",
|
|
45
|
+
"field": "sourceQuality",
|
|
46
|
+
"weight": 10,
|
|
47
|
+
"direction": "desc",
|
|
48
|
+
"min": 0,
|
|
49
|
+
"max": 1,
|
|
50
|
+
"default": 0.5
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"gates": [
|
|
54
|
+
{
|
|
55
|
+
"id": "already-rejected",
|
|
56
|
+
"action": "skip",
|
|
57
|
+
"reason": "terminal tracker state",
|
|
58
|
+
"when": {
|
|
59
|
+
"where": {
|
|
60
|
+
"status": [
|
|
61
|
+
"Rejected",
|
|
62
|
+
"Discarded",
|
|
63
|
+
"SKIP"
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"id": "duplicate",
|
|
70
|
+
"action": "skip",
|
|
71
|
+
"reason": "duplicate candidate",
|
|
72
|
+
"when": {
|
|
73
|
+
"where": {
|
|
74
|
+
"duplicate": true
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
"adjustments": [
|
|
80
|
+
{
|
|
81
|
+
"id": "due-follow-up",
|
|
82
|
+
"value": 6,
|
|
83
|
+
"reason": "follow-up is due now",
|
|
84
|
+
"when": {
|
|
85
|
+
"type": "followup",
|
|
86
|
+
"where": {
|
|
87
|
+
"timelineState": [
|
|
88
|
+
"due",
|
|
89
|
+
"overdue"
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"id": "dream-company",
|
|
96
|
+
"value": 8,
|
|
97
|
+
"reason": "company is on the priority list",
|
|
98
|
+
"when": {
|
|
99
|
+
"where": {
|
|
100
|
+
"priorityCompany": true
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"id": "weak-source",
|
|
106
|
+
"value": -12,
|
|
107
|
+
"reason": "source lacks a report or score provenance",
|
|
108
|
+
"when": {
|
|
109
|
+
"where": {
|
|
110
|
+
"sourceQuality": 0
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
],
|
|
115
|
+
"quotas": [
|
|
116
|
+
{
|
|
117
|
+
"id": "one-per-company",
|
|
118
|
+
"field": "company",
|
|
119
|
+
"max": 1,
|
|
120
|
+
"reason": "keep the selected queue diverse"
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
package/verify-pipeline.mjs
CHANGED
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
* 11. Artifact index verifies if .jobforge-index.json exists
|
|
21
21
|
* 12. Fact set verifies if .jobforge-facts.json exists
|
|
22
22
|
* 13. Timeline verifies if .jobforge-timeline.json exists
|
|
23
|
+
* 14. Priority queue verifies if .jobforge-prioritize.json exists
|
|
24
|
+
* 15. Artifact lineage verifies/checks if .jobforge-lineage.json exists
|
|
23
25
|
*
|
|
24
26
|
* Run: node verify-pipeline.mjs (from repo root; same as npm run verify)
|
|
25
27
|
*/
|
|
@@ -35,6 +37,8 @@ import { jobForgeLedgerPath, ledgerExists, verifyJobForgeLedger } from './lib/jo
|
|
|
35
37
|
import { indexExists, jobForgeIndexPath, verifyJobForgeIndex } from './lib/jobforge-index.mjs';
|
|
36
38
|
import { factsExist, jobForgeFactsPath, verifyJobForgeFacts } from './lib/jobforge-facts.mjs';
|
|
37
39
|
import { jobForgeTimelinePath, timelineExists, verifyJobForgeTimeline } from './lib/jobforge-timeline.mjs';
|
|
40
|
+
import { jobForgePrioritizePath, prioritizeExists, verifyJobForgePrioritize } from './lib/jobforge-prioritize.mjs';
|
|
41
|
+
import { checkJobForgeLineage, jobForgeLineagePath, lineageExists, verifyJobForgeLineage } from './lib/jobforge-lineage.mjs';
|
|
38
42
|
import {
|
|
39
43
|
canonicalStatusValues,
|
|
40
44
|
formatContractIssues,
|
|
@@ -207,6 +211,46 @@ function verifyTimelineIfPresent() {
|
|
|
207
211
|
}
|
|
208
212
|
}
|
|
209
213
|
|
|
214
|
+
function verifyPrioritizeIfPresent() {
|
|
215
|
+
if (!prioritizeExists(PROJECT_DIR)) {
|
|
216
|
+
ok('Priority queue not initialized');
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const result = verifyJobForgePrioritize({}, PROJECT_DIR);
|
|
220
|
+
for (const issue of result.issues) {
|
|
221
|
+
const msg = `prioritize: ${issue.code}: ${issue.message}`;
|
|
222
|
+
if (issue.severity === 'error') error(msg);
|
|
223
|
+
else warn(msg);
|
|
224
|
+
}
|
|
225
|
+
if (result.ok) {
|
|
226
|
+
ok(`Priority queue valid (${relative(PROJECT_DIR, jobForgePrioritizePath(PROJECT_DIR))})`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function verifyLineageIfPresent() {
|
|
231
|
+
if (!lineageExists(PROJECT_DIR)) {
|
|
232
|
+
ok('Artifact lineage not initialized');
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const verifyResult = verifyJobForgeLineage({}, PROJECT_DIR);
|
|
236
|
+
for (const issue of verifyResult.issues) {
|
|
237
|
+
const msg = `lineage: ${issue.code}: ${issue.message}`;
|
|
238
|
+
if (issue.severity === 'error') error(msg);
|
|
239
|
+
else warn(msg);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const checkResult = checkJobForgeLineage({}, PROJECT_DIR);
|
|
243
|
+
for (const issue of checkResult.issues) {
|
|
244
|
+
const msg = `lineage: ${issue.code}: ${issue.message}`;
|
|
245
|
+
if (issue.severity === 'error') error(msg);
|
|
246
|
+
else warn(msg);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (verifyResult.ok && checkResult.ok) {
|
|
250
|
+
ok(`Artifact lineage current (${checkResult.current}/${checkResult.total} records at ${relative(PROJECT_DIR, jobForgeLineagePath(PROJECT_DIR))})`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
210
254
|
// --- Read entries ---
|
|
211
255
|
const { entries, source } = readAllEntries();
|
|
212
256
|
|
|
@@ -219,6 +263,8 @@ if (entries.length === 0) {
|
|
|
219
263
|
verifyIndexIfPresent();
|
|
220
264
|
verifyFactsIfPresent();
|
|
221
265
|
verifyTimelineIfPresent();
|
|
266
|
+
verifyPrioritizeIfPresent();
|
|
267
|
+
verifyLineageIfPresent();
|
|
222
268
|
console.log('\n' + '='.repeat(50));
|
|
223
269
|
console.log(`📊 Pipeline Health: ${errors} errors, ${warnings} warnings`);
|
|
224
270
|
if (errors === 0 && warnings === 0) console.log('🟢 Pipeline is clean!');
|
|
@@ -357,6 +403,8 @@ verifyLedgerIfPresent();
|
|
|
357
403
|
verifyIndexIfPresent();
|
|
358
404
|
verifyFactsIfPresent();
|
|
359
405
|
verifyTimelineIfPresent();
|
|
406
|
+
verifyPrioritizeIfPresent();
|
|
407
|
+
verifyLineageIfPresent();
|
|
360
408
|
|
|
361
409
|
console.log('\n' + '='.repeat(50));
|
|
362
410
|
console.log(`📊 Pipeline Health: ${errors} errors, ${warnings} warnings`);
|