job-forge 2.14.24 → 2.14.26
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 +4 -1
- package/.opencode/skills/job-forge.md +5 -0
- package/AGENTS.md +4 -1
- package/CLAUDE.md +4 -1
- package/README.md +6 -5
- package/bin/create-job-forge.mjs +24 -0
- package/bin/job-forge.mjs +30 -0
- package/bin/sync.mjs +30 -0
- package/docs/ARCHITECTURE.md +5 -2
- package/docs/CUSTOMIZATION.md +4 -0
- package/docs/SETUP.md +2 -0
- package/iso/commands/job-forge.md +5 -0
- package/iso/instructions.md +4 -1
- package/lib/jobforge-migrate.mjs +33 -0
- package/package.json +6 -1
- package/scripts/migrate.mjs +89 -0
- package/templates/index.json +1 -1
- package/templates/migrations.json +63 -0
package/.cursor/rules/main.mdc
CHANGED
|
@@ -77,11 +77,14 @@ AI-powered job search pipeline: scans portals, evaluates offers, generates CVs v
|
|
|
77
77
|
- [D13] Use `job-forge index:*` for deterministic artifact lookup when available. `index:has` and `index:query` rebuild `.jobforge-index.json` from `templates/index.json` on demand, covering reports, tracker day files, tracker TSVs, pipeline URLs, scan history, and ledger events without loading those growing files into prompt context.
|
|
78
78
|
why: `iso-index` is not an MCP and adds no prompt/tool-schema tokens; it gives agents compact file/line pointers and duplicate prefilters before expensive reads or browser dispatches
|
|
79
79
|
|
|
80
|
+
- [D14] Treat `templates/migrations.json` as the source of truth for consumer-project upgrades. Use `npx job-forge migrate:plan` or `npx job-forge migrate:check` when diagnosing harness drift; `job-forge sync` applies safe migrations automatically unless `JOB_FORGE_SKIP_MIGRATIONS=1` is set.
|
|
81
|
+
why: `iso-migrate` is not an MCP and adds no prompt/tool-schema tokens; it prevents stale consumer scripts and generated-artifact ignores without asking agents to hand-edit package.json
|
|
82
|
+
|
|
80
83
|
## Procedure
|
|
81
84
|
|
|
82
85
|
1. Check `cv.md`, `profile.yml`, and `portals.yml`; onboard if any file is missing.
|
|
83
86
|
2. Pick and name the mode from **Routing** [D6]. No match → ask; do not guess.
|
|
84
|
-
3. Read the active mode file [D3]. Use context bundle checks when changing context loads [D11]. Check cached artifacts before URL/JD refetches [D12]. Use artifact index lookups before broad file reads when they can answer the question [D13]. Decide inline vs delegated work [D1].
|
|
87
|
+
3. Read the active mode file [D3]. Use context bundle checks when changing context loads [D11]. Check cached artifacts before URL/JD refetches [D12]. Use artifact index lookups before broad file reads when they can answer the question [D13]. Use migration checks for harness drift [D14]. Decide inline vs delegated work [D1].
|
|
85
88
|
4. Prepare Geometra dispatches: cleanup [H3], index/ledger prefilter when useful [D8, D13], dedupe [H2], location filter [D5], routing [D2, D10], proxy prompt hygiene [H8].
|
|
86
89
|
5. Dispatch at most 2 tasks per round [H1]; wait for final outcomes, not just task ids [H5b].
|
|
87
90
|
6. Keep multi-job form-filling out of the orchestrator [H4].
|
|
@@ -78,6 +78,11 @@ Local artifact index (terminal, outside opencode):
|
|
|
78
78
|
npx job-forge index:has --key "company-role:acme:staff-engineer"
|
|
79
79
|
npx job-forge index:query "acme"
|
|
80
80
|
|
|
81
|
+
Consumer migrations (terminal, outside opencode):
|
|
82
|
+
npx job-forge migrate:plan # preview package.json/.gitignore drift
|
|
83
|
+
npx job-forge migrate:apply # apply safe harness upgrade migrations
|
|
84
|
+
npx job-forge migrate:check # fail if migrations are pending
|
|
85
|
+
|
|
81
86
|
Artifact contracts (terminal, outside opencode):
|
|
82
87
|
npx iso-contract explain jobforge.tracker-row --contracts templates/contracts.json
|
|
83
88
|
npx job-forge tracker-line ... --write # renders + validates tracker TSV locally
|
package/AGENTS.md
CHANGED
|
@@ -72,11 +72,14 @@ AI-powered job search pipeline: scans portals, evaluates offers, generates CVs v
|
|
|
72
72
|
- [D13] Use `job-forge index:*` for deterministic artifact lookup when available. `index:has` and `index:query` rebuild `.jobforge-index.json` from `templates/index.json` on demand, covering reports, tracker day files, tracker TSVs, pipeline URLs, scan history, and ledger events without loading those growing files into prompt context.
|
|
73
73
|
why: `iso-index` is not an MCP and adds no prompt/tool-schema tokens; it gives agents compact file/line pointers and duplicate prefilters before expensive reads or browser dispatches
|
|
74
74
|
|
|
75
|
+
- [D14] Treat `templates/migrations.json` as the source of truth for consumer-project upgrades. Use `npx job-forge migrate:plan` or `npx job-forge migrate:check` when diagnosing harness drift; `job-forge sync` applies safe migrations automatically unless `JOB_FORGE_SKIP_MIGRATIONS=1` is set.
|
|
76
|
+
why: `iso-migrate` is not an MCP and adds no prompt/tool-schema tokens; it prevents stale consumer scripts and generated-artifact ignores without asking agents to hand-edit package.json
|
|
77
|
+
|
|
75
78
|
## Procedure
|
|
76
79
|
|
|
77
80
|
1. Check `cv.md`, `profile.yml`, and `portals.yml`; onboard if any file is missing.
|
|
78
81
|
2. Pick and name the mode from **Routing** [D6]. No match → ask; do not guess.
|
|
79
|
-
3. Read the active mode file [D3]. Use context bundle checks when changing context loads [D11]. Check cached artifacts before URL/JD refetches [D12]. Use artifact index lookups before broad file reads when they can answer the question [D13]. Decide inline vs delegated work [D1].
|
|
82
|
+
3. Read the active mode file [D3]. Use context bundle checks when changing context loads [D11]. Check cached artifacts before URL/JD refetches [D12]. Use artifact index lookups before broad file reads when they can answer the question [D13]. Use migration checks for harness drift [D14]. Decide inline vs delegated work [D1].
|
|
80
83
|
4. Prepare Geometra dispatches: cleanup [H3], index/ledger prefilter when useful [D8, D13], dedupe [H2], location filter [D5], routing [D2, D10], proxy prompt hygiene [H8].
|
|
81
84
|
5. Dispatch at most 2 tasks per round [H1]; wait for final outcomes, not just task ids [H5b].
|
|
82
85
|
6. Keep multi-job form-filling out of the orchestrator [H4].
|
package/CLAUDE.md
CHANGED
|
@@ -72,11 +72,14 @@ AI-powered job search pipeline: scans portals, evaluates offers, generates CVs v
|
|
|
72
72
|
- [D13] Use `job-forge index:*` for deterministic artifact lookup when available. `index:has` and `index:query` rebuild `.jobforge-index.json` from `templates/index.json` on demand, covering reports, tracker day files, tracker TSVs, pipeline URLs, scan history, and ledger events without loading those growing files into prompt context.
|
|
73
73
|
why: `iso-index` is not an MCP and adds no prompt/tool-schema tokens; it gives agents compact file/line pointers and duplicate prefilters before expensive reads or browser dispatches
|
|
74
74
|
|
|
75
|
+
- [D14] Treat `templates/migrations.json` as the source of truth for consumer-project upgrades. Use `npx job-forge migrate:plan` or `npx job-forge migrate:check` when diagnosing harness drift; `job-forge sync` applies safe migrations automatically unless `JOB_FORGE_SKIP_MIGRATIONS=1` is set.
|
|
76
|
+
why: `iso-migrate` is not an MCP and adds no prompt/tool-schema tokens; it prevents stale consumer scripts and generated-artifact ignores without asking agents to hand-edit package.json
|
|
77
|
+
|
|
75
78
|
## Procedure
|
|
76
79
|
|
|
77
80
|
1. Check `cv.md`, `profile.yml`, and `portals.yml`; onboard if any file is missing.
|
|
78
81
|
2. Pick and name the mode from **Routing** [D6]. No match → ask; do not guess.
|
|
79
|
-
3. Read the active mode file [D3]. Use context bundle checks when changing context loads [D11]. Check cached artifacts before URL/JD refetches [D12]. Use artifact index lookups before broad file reads when they can answer the question [D13]. Decide inline vs delegated work [D1].
|
|
82
|
+
3. Read the active mode file [D3]. Use context bundle checks when changing context loads [D11]. Check cached artifacts before URL/JD refetches [D12]. Use artifact index lookups before broad file reads when they can answer the question [D13]. Use migration checks for harness drift [D14]. Decide inline vs delegated work [D1].
|
|
80
83
|
4. Prepare Geometra dispatches: cleanup [H3], index/ledger prefilter when useful [D8, D13], dedupe [H2], location filter [D5], routing [D2, D10], proxy prompt hygiene [H8].
|
|
81
84
|
5. Dispatch at most 2 tasks per round [H1]; wait for final outcomes, not just task ids [H5b].
|
|
82
85
|
6. Keep multi-job form-filling out of the orchestrator [H4].
|
package/README.md
CHANGED
|
@@ -31,13 +31,13 @@ The scaffolded `opencode.json` already has three MCPs wired up — they launch a
|
|
|
31
31
|
- **Gmail** — reads replies from recruiters
|
|
32
32
|
- **state-trace** — typed working memory for cross-session context (resumed batches, recent decisions, repeated portal quirks). Install once with `python3 -m pip install "state-trace[mcp]"`; the MCP command is `state-trace-mcp`.
|
|
33
33
|
|
|
34
|
-
JobForge also keeps MCP-free local workflow state: `templates/contracts.json` defines tracker/apply artifact shapes via `@razroo/iso-contract`, `templates/capabilities.json` defines role capability boundaries via `@razroo/iso-capabilities`, `templates/context.json` defines deterministic mode/reference bundles via `@razroo/iso-context`, `.jobforge-ledger/events.jsonl` records duplicate/status events via `@razroo/iso-ledger`, `.jobforge-cache/` stores reusable JD/artifact content via `@razroo/iso-cache`, and `.jobforge-index.json` indexes artifact source pointers via `@razroo/iso-index`. None of these add always-on prompt or tool-schema tokens.
|
|
34
|
+
JobForge also keeps MCP-free local workflow state: `templates/contracts.json` defines tracker/apply artifact shapes via `@razroo/iso-contract`, `templates/capabilities.json` defines role capability boundaries via `@razroo/iso-capabilities`, `templates/context.json` defines deterministic mode/reference bundles via `@razroo/iso-context`, `templates/migrations.json` defines safe consumer-project upgrades via `@razroo/iso-migrate`, `.jobforge-ledger/events.jsonl` records duplicate/status events via `@razroo/iso-ledger`, `.jobforge-cache/` stores reusable JD/artifact content via `@razroo/iso-cache`, and `.jobforge-index.json` indexes artifact source pointers via `@razroo/iso-index`. None of these add always-on prompt or tool-schema tokens.
|
|
35
35
|
|
|
36
36
|
`npm install` also materializes symlinks for every supported agent harness — OpenCode, Cursor, Claude Code, and Codex — so you can run `opencode`, `cursor`, `claude`, or `codex` in the same project and each picks up the shared MCP config and instructions.
|
|
37
37
|
|
|
38
38
|
Then fill in `cv.md`, `config/profile.yml`, and `portals.yml` with your personal data, paste a job URL into opencode, and JobForge evaluates + tracks it.
|
|
39
39
|
|
|
40
|
-
**Upgrade later:** `npm run update-harness` (pulls latest `job-forge` from npm, re-syncs symlinks, prints the resolved version)
|
|
40
|
+
**Upgrade later:** `npm run update-harness` (pulls latest `job-forge` from npm, re-syncs symlinks, applies safe consumer migrations, prints the resolved version)
|
|
41
41
|
|
|
42
42
|
Full setup guide and alternative install paths (including contributing to the harness itself): **[docs/SETUP.md](docs/SETUP.md)**.
|
|
43
43
|
|
|
@@ -78,7 +78,7 @@ JobForge turns opencode into a full job search command center. Instead of manual
|
|
|
78
78
|
| **Durable Batch Orchestration** | `batch-runner.sh` uses `@razroo/iso-orchestrator` for resumable bundle execution, bounded fan-out, mutexed state writes, and workflow records in `.jobforge-runs/`. |
|
|
79
79
|
| **Pipeline Integrity** | Automated merge, dedup, status normalization, health checks |
|
|
80
80
|
| **Cost-Aware Agent Routing** | Three subagents (`@general-free`, `@general-paid`, `@glm-minimal`) with per-task tool surfaces. On OpenCode, JobForge pins all tiers to `opencode-go/deepseek-v4-flash` so application runs avoid overloaded free-model pools. See [Subagent Routing in AGENTS.md](AGENTS.md) for the task-to-agent mapping. |
|
|
81
|
-
| **Trace + Telemetry + Guard + Contract + Ledger + Capabilities + Context + Cache + Index** | `job-forge trace:*` exposes local OpenCode transcripts, `job-forge telemetry:*` summarizes runs, `job-forge guard:*` audits deterministic policy rules, `templates/contracts.json` enforces artifact shape with `iso-contract`, `job-forge ledger:*` queries append-only workflow state, `job-forge capabilities:*` checks role boundaries, `job-forge context:*` plans mode/reference context bundles, `job-forge cache:*` reuses fetched JD/artifact content,
|
|
81
|
+
| **Trace + Telemetry + Guard + Contract + Ledger + Capabilities + Context + Cache + Index + Migrate** | `job-forge trace:*` exposes local OpenCode transcripts, `job-forge telemetry:*` summarizes runs, `job-forge guard:*` audits deterministic policy rules, `templates/contracts.json` enforces artifact shape with `iso-contract`, `job-forge ledger:*` queries append-only workflow state, `job-forge capabilities:*` checks role boundaries, `job-forge context:*` plans mode/reference context bundles, `job-forge cache:*` reuses fetched JD/artifact content, `job-forge index:*` queries compact source pointers, and `job-forge migrate:*` applies safe consumer-project upgrades without MCP/tool-schema overhead. |
|
|
82
82
|
| **Token Cost Visibility** | `job-forge tokens --days 1` for per-session breakdown; `job-forge session-report --since-minutes 60 --log` to flag sessions over budget and append history to `data/token-usage.tsv`. Auto-logged after every batch run. |
|
|
83
83
|
|
|
84
84
|
## Usage
|
|
@@ -164,7 +164,7 @@ my-search/
|
|
|
164
164
|
├── .opencode/skills/job-forge.md # → skill router
|
|
165
165
|
├── .opencode/agents/ # → @general-free, @general-paid, @glm-minimal
|
|
166
166
|
├── modes/ # → _shared.md + skill modes
|
|
167
|
-
├── templates/ # → states.yml, portals.example.yml, cv-template.html, capabilities.json, context.json, index.json
|
|
167
|
+
├── templates/ # → states.yml, portals.example.yml, cv-template.html, capabilities.json, context.json, index.json, migrations.json
|
|
168
168
|
├── batch/batch-prompt.md # → batch worker prompt
|
|
169
169
|
├── batch/batch-runner.sh # → parallel orchestrator
|
|
170
170
|
│
|
|
@@ -190,7 +190,7 @@ JobForge/
|
|
|
190
190
|
│ ├── sync.mjs # postinstall: creates symlinks in consumer project
|
|
191
191
|
│ └── create-job-forge.mjs # scaffolder
|
|
192
192
|
├── modes/ # _shared.md + 16 skill modes
|
|
193
|
-
├── templates/ # cv-template.html, portals.example.yml, states.yml, capabilities.json, context.json
|
|
193
|
+
├── templates/ # cv-template.html, portals.example.yml, states.yml, capabilities.json, context.json, migrations.json
|
|
194
194
|
├── config/profile.example.yml # template for consumer's profile.yml
|
|
195
195
|
├── batch/{batch-prompt.md,batch-runner.sh} # batch orchestrator
|
|
196
196
|
├── scripts/
|
|
@@ -201,6 +201,7 @@ JobForge/
|
|
|
201
201
|
│ ├── context.mjs # iso-context-backed context bundle CLI
|
|
202
202
|
│ ├── cache.mjs # iso-cache-backed local artifact cache CLI
|
|
203
203
|
│ ├── index.mjs # iso-index-backed artifact lookup CLI
|
|
204
|
+
│ ├── migrate.mjs # iso-migrate-backed consumer-project migrations
|
|
204
205
|
│ ├── token-usage-report.mjs # opencode cost analyzer
|
|
205
206
|
│ └── release/check-source.mjs # version gate for npm publish
|
|
206
207
|
├── tracker-lib.mjs / merge-tracker.mjs / dedup-tracker.mjs / verify-pipeline.mjs
|
package/bin/create-job-forge.mjs
CHANGED
|
@@ -124,11 +124,33 @@ const consumerPkg = {
|
|
|
124
124
|
'ledger:verify': 'job-forge ledger:verify',
|
|
125
125
|
'ledger:has': 'job-forge ledger:has',
|
|
126
126
|
'ledger:query': 'job-forge ledger:query',
|
|
127
|
+
'capabilities:list': 'job-forge capabilities:list',
|
|
128
|
+
'capabilities:explain': 'job-forge capabilities:explain',
|
|
129
|
+
'capabilities:check': 'job-forge capabilities:check',
|
|
130
|
+
'capabilities:render': 'job-forge capabilities:render',
|
|
131
|
+
'context:list': 'job-forge context:list',
|
|
132
|
+
'context:explain': 'job-forge context:explain',
|
|
133
|
+
'context:plan': 'job-forge context:plan',
|
|
134
|
+
'context:check': 'job-forge context:check',
|
|
135
|
+
'context:render': 'job-forge context:render',
|
|
136
|
+
'cache:key': 'job-forge cache:key',
|
|
137
|
+
'cache:has': 'job-forge cache:has',
|
|
138
|
+
'cache:get': 'job-forge cache:get',
|
|
139
|
+
'cache:put': 'job-forge cache:put',
|
|
140
|
+
'cache:status': 'job-forge cache:status',
|
|
141
|
+
'cache:list': 'job-forge cache:list',
|
|
142
|
+
'cache:verify': 'job-forge cache:verify',
|
|
143
|
+
'cache:prune': 'job-forge cache:prune',
|
|
127
144
|
'index:build': 'job-forge index:build',
|
|
128
145
|
'index:status': 'job-forge index:status',
|
|
129
146
|
'index:verify': 'job-forge index:verify',
|
|
130
147
|
'index:has': 'job-forge index:has',
|
|
131
148
|
'index:query': 'job-forge index:query',
|
|
149
|
+
'index:explain': 'job-forge index:explain',
|
|
150
|
+
'migrate:plan': 'job-forge migrate:plan',
|
|
151
|
+
'migrate:apply': 'job-forge migrate:apply',
|
|
152
|
+
'migrate:check': 'job-forge migrate:check',
|
|
153
|
+
'migrate:explain': 'job-forge migrate:explain',
|
|
132
154
|
// One command to pull the latest harness and any locally-pinned MCP
|
|
133
155
|
// packages. npm update is a no-op on packages not in package.json, so
|
|
134
156
|
// listing @razroo/gmail-mcp + @geometra/mcp is safe for consumers that
|
|
@@ -230,6 +252,7 @@ Before doing any work, remember where things live in *this* project:
|
|
|
230
252
|
| Scanner dedup history | \`data/scan-history.tsv\` | Only touch in \`/job-forge scan\` |
|
|
231
253
|
| Local workflow ledger | \`.jobforge-ledger/events.jsonl\` | Deterministic append-only state; use \`job-forge ledger:*\` |
|
|
232
254
|
| Local artifact index | \`.jobforge-index.json\` | Deterministic file/line lookup; use \`job-forge index:*\` |
|
|
255
|
+
| Consumer migrations | \`templates/migrations.json\` | Safe script/gitignore upgrades; use \`job-forge migrate:*\` |
|
|
233
256
|
| Scanner config | \`portals.yml\` (project root) | Company configs |
|
|
234
257
|
| Profile / identity | \`config/profile.yml\` | Candidate name, email, target roles |
|
|
235
258
|
| CV | \`cv.md\` (project root) | Markdown, source of truth |
|
|
@@ -379,6 +402,7 @@ job-forge merge # merge batch/tracker-additions/*.tsv into the tracke
|
|
|
379
402
|
job-forge verify # verify pipeline integrity
|
|
380
403
|
job-forge ledger:status # local deterministic workflow ledger status
|
|
381
404
|
job-forge index:status # local artifact index status
|
|
405
|
+
job-forge migrate:check # verify consumer package scripts/gitignore are current
|
|
382
406
|
job-forge pdf cv.md out.pdf
|
|
383
407
|
job-forge tokens --days 1 # per-session opencode token usage
|
|
384
408
|
\`\`\`
|
package/bin/job-forge.mjs
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
* context:* Query/render deterministic context bundles via iso-context
|
|
26
26
|
* cache:* Reuse local deterministic artifacts via iso-cache
|
|
27
27
|
* index:* Query local artifacts via iso-index
|
|
28
|
+
* migrate:* Apply deterministic consumer-project migrations via iso-migrate
|
|
28
29
|
* sync Re-run the harness symlink sync (bin/sync.mjs)
|
|
29
30
|
* help, --help Show this message
|
|
30
31
|
*/
|
|
@@ -127,6 +128,14 @@ const indexAliases = {
|
|
|
127
128
|
'index:path': 'path',
|
|
128
129
|
};
|
|
129
130
|
|
|
131
|
+
const migrateAliases = {
|
|
132
|
+
'migrate:plan': 'plan',
|
|
133
|
+
'migrate:apply': 'apply',
|
|
134
|
+
'migrate:check': 'check',
|
|
135
|
+
'migrate:explain': 'explain',
|
|
136
|
+
'migrate:path': 'path',
|
|
137
|
+
};
|
|
138
|
+
|
|
130
139
|
const [, , cmd, ...rest] = process.argv;
|
|
131
140
|
|
|
132
141
|
function printHelp() {
|
|
@@ -177,6 +186,10 @@ Commands:
|
|
|
177
186
|
index:has Check indexed URL/company-role/report facts without loading source files
|
|
178
187
|
index:query Query indexed reports, tracker rows, TSVs, scan history, pipeline, and ledger
|
|
179
188
|
index:verify Validate local artifact index integrity
|
|
189
|
+
migrate:plan Preview deterministic consumer-project migrations
|
|
190
|
+
migrate:apply Apply deterministic consumer-project migrations
|
|
191
|
+
migrate:check Fail if migrations are pending
|
|
192
|
+
migrate:explain Show the active migration policy
|
|
180
193
|
sync Re-create harness symlinks in the current project
|
|
181
194
|
|
|
182
195
|
Deterministic helpers (prefer these over LLM-derived values):
|
|
@@ -215,6 +228,8 @@ Pass --help after a command to see its own flags, e.g.:
|
|
|
215
228
|
job-forge cache:put --url https://example.test/jobs/123 --input @jds/example.md
|
|
216
229
|
job-forge index:has --key "company-role:acme:staff-engineer"
|
|
217
230
|
job-forge index:query "acme"
|
|
231
|
+
job-forge migrate:check
|
|
232
|
+
job-forge migrate:apply
|
|
218
233
|
|
|
219
234
|
Project directory resolves to $JOB_FORGE_PROJECT or cwd.`);
|
|
220
235
|
}
|
|
@@ -344,6 +359,21 @@ if (cmd === 'index' || indexAliases[cmd]) {
|
|
|
344
359
|
process.exit(result.status ?? 1);
|
|
345
360
|
}
|
|
346
361
|
|
|
362
|
+
if (cmd === 'migrate' || migrateAliases[cmd]) {
|
|
363
|
+
const migrateArgs = cmd === 'migrate'
|
|
364
|
+
? (rest.length === 0 ? ['help'] : rest)
|
|
365
|
+
: [migrateAliases[cmd], ...rest];
|
|
366
|
+
|
|
367
|
+
const scriptPath = join(PKG_ROOT, 'scripts/migrate.mjs');
|
|
368
|
+
const result = spawnSync(process.execPath, [scriptPath, ...migrateArgs], {
|
|
369
|
+
stdio: 'inherit',
|
|
370
|
+
cwd: PROJECT_DIR,
|
|
371
|
+
env: process.env,
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
process.exit(result.status ?? 1);
|
|
375
|
+
}
|
|
376
|
+
|
|
347
377
|
const rel = commands[cmd];
|
|
348
378
|
if (!rel) {
|
|
349
379
|
console.error(`Unknown command: ${cmd}\n`);
|
package/bin/sync.mjs
CHANGED
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
import { existsSync, lstatSync, readlinkSync, symlinkSync, mkdirSync, readFileSync } from 'fs';
|
|
24
24
|
import { dirname, join, resolve, relative } from 'path';
|
|
25
25
|
import { fileURLToPath } from 'url';
|
|
26
|
+
import {
|
|
27
|
+
loadMigrationConfig,
|
|
28
|
+
parseJson,
|
|
29
|
+
runMigrations,
|
|
30
|
+
} from '@razroo/iso-migrate';
|
|
26
31
|
|
|
27
32
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
28
33
|
const PKG_ROOT = resolve(__dirname, '..');
|
|
@@ -149,4 +154,29 @@ for (const { src, dst } of links) {
|
|
|
149
154
|
}
|
|
150
155
|
}
|
|
151
156
|
|
|
157
|
+
try {
|
|
158
|
+
const migrationResult = applyConsumerMigrations();
|
|
159
|
+
if (migrationResult?.changeCount > 0) {
|
|
160
|
+
console.log(`\njob-forge migrate: applied ${migrationResult.changeCount} change(s)`);
|
|
161
|
+
}
|
|
162
|
+
} catch (error) {
|
|
163
|
+
console.warn(`\n warn: job-forge migrations skipped: ${error instanceof Error ? error.message : String(error)}`);
|
|
164
|
+
warned++;
|
|
165
|
+
}
|
|
166
|
+
|
|
152
167
|
console.log(`\njob-forge sync: ${created} created, ${skipped} up-to-date, ${warned} warnings (project: ${PROJECT_DIR})`);
|
|
168
|
+
|
|
169
|
+
function applyConsumerMigrations() {
|
|
170
|
+
const skip = process.env.JOB_FORGE_SKIP_MIGRATIONS;
|
|
171
|
+
if (skip === '1' || skip === 'true') return null;
|
|
172
|
+
if (!existsSync(join(PROJECT_DIR, 'package.json'))) return null;
|
|
173
|
+
|
|
174
|
+
const configPath = process.env.JOB_FORGE_MIGRATIONS_CONFIG || join(PKG_ROOT, 'templates', 'migrations.json');
|
|
175
|
+
if (!existsSync(configPath)) return null;
|
|
176
|
+
|
|
177
|
+
const config = loadMigrationConfig(parseJson(readFileSync(configPath, 'utf8'), configPath));
|
|
178
|
+
return runMigrations(config, {
|
|
179
|
+
root: PROJECT_DIR,
|
|
180
|
+
dryRun: false,
|
|
181
|
+
});
|
|
182
|
+
}
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -48,7 +48,7 @@ The skill router (`.opencode/skills/job-forge.md`) loads mode and data files on
|
|
|
48
48
|
|
|
49
49
|
**Multi-harness support.** Because `iso/` is the single source of truth, publishing ships config for OpenCode, Cursor, Claude Code, and Codex in one tarball. Consumers run any of `opencode`, `cursor`, `claude`, or `codex` in the project and each picks up the shared MCP config + instructions via the symlinks above.
|
|
50
50
|
|
|
51
|
-
**Upgrading** the harness in a consumer project is `npm run update-harness` — pulls the latest `job-forge` from npm, refreshes pinned MCPs, re-runs symlink sync, and prints the resolved version.
|
|
51
|
+
**Upgrading** the harness in a consumer project is `npm run update-harness` — pulls the latest `job-forge` from npm, refreshes pinned MCPs, re-runs symlink sync, applies safe consumer migrations, and prints the resolved version.
|
|
52
52
|
|
|
53
53
|
## System Overview
|
|
54
54
|
|
|
@@ -165,6 +165,7 @@ data/pipeline.md → Pending URLs and `local:jds/...` inbox (see modes/p
|
|
|
165
165
|
jds/*.md → Saved job descriptions referenced from the pipeline (`local:jds/{file}`)
|
|
166
166
|
templates/states.yml → Canonical status values
|
|
167
167
|
templates/context.json → Deterministic mode/reference context bundle policy
|
|
168
|
+
templates/migrations.json → Safe consumer-project upgrade policy
|
|
168
169
|
templates/cv-template.html → PDF generation template
|
|
169
170
|
examples/*.md → Fictional layouts only (not read by scripts; see examples/README.md)
|
|
170
171
|
```
|
|
@@ -178,6 +179,7 @@ Create `data/pipeline.md` when you start using the URL inbox (`/job-forge pipeli
|
|
|
178
179
|
- Tracker TSVs: `batch/tracker-additions/{num}-{company-slug}.tsv` (one file per evaluation; merged files move under `batch/tracker-additions/merged/`; shape enforced by `templates/contracts.json`)
|
|
179
180
|
- Ledger: `.jobforge-ledger/events.jsonl` (created by `job-forge ledger:rebuild`, `tracker-line --write`, or `merge`; gitignored personal state)
|
|
180
181
|
- Index: `.jobforge-index.json` (created on demand by `job-forge index:*`; gitignored local lookup state)
|
|
182
|
+
- Migrations: `templates/migrations.json` (applied by `job-forge sync` and inspectable with `job-forge migrate:*`)
|
|
181
183
|
- Capabilities: `templates/capabilities.json` (role boundary policy inspected with `job-forge capabilities:*`)
|
|
182
184
|
- Context: `templates/context.json` (mode/reference file bundles inspected with `job-forge context:*`)
|
|
183
185
|
|
|
@@ -224,8 +226,9 @@ Scripts maintain data consistency. In a consumer project they're invoked via the
|
|
|
224
226
|
| `scripts/ledger.mjs` | `npx job-forge ledger:status` / `ledger:has` / `ledger:rebuild` | Deterministic `@razroo/iso-ledger` state over tracker, TSV, and pipeline files |
|
|
225
227
|
| `scripts/index.mjs` | `npx job-forge index:status` / `index:has` / `index:query` | Deterministic `@razroo/iso-index` lookup over reports, tracker rows, TSVs, pipeline, scan history, and ledger events |
|
|
226
228
|
| `scripts/context.mjs` | `npx job-forge context:list` / `context:plan` / `context:check` / `context:render` | Deterministic `@razroo/iso-context` mode/reference context bundle planning and rendering |
|
|
229
|
+
| `scripts/migrate.mjs` | `npx job-forge migrate:plan` / `migrate:apply` / `migrate:check` | Deterministic `@razroo/iso-migrate` consumer-project upgrades for scripts and generated-artifact ignores |
|
|
227
230
|
| `tracker-lib.mjs` | _(library)_ | Shared helpers for reading/writing day-based tracker files — imported by merge/dedup/verify/normalize |
|
|
228
|
-
| `bin/sync.mjs` | `npx job-forge sync` | Creates the harness symlinks in a consumer project (also runs as `postinstall`) |
|
|
231
|
+
| `bin/sync.mjs` | `npx job-forge sync` | Creates the harness symlinks in a consumer project and applies safe migrations (also runs as `postinstall`) |
|
|
229
232
|
| `bin/create-job-forge.mjs` | `npx create-job-forge <dir>` | Scaffolds a new personal project |
|
|
230
233
|
|
|
231
234
|
All scripts resolve the consumer project dir via `process.env.JOB_FORGE_PROJECT || process.cwd()`, so running the CLI from anywhere in the consumer project Just Works.
|
package/docs/CUSTOMIZATION.md
CHANGED
|
@@ -154,6 +154,10 @@ Mode/reference context bundles live in `templates/context.json` and are planned
|
|
|
154
154
|
|
|
155
155
|
Artifact lookup policy lives in `templates/index.json` and is built locally by `@razroo/iso-index`. Use `job-forge index:has --key "company-role:acme:staff-engineer"` as a cheap duplicate/source prefilter, `job-forge index:query "acme"` to get compact source path/line pointers, and `job-forge index:verify` to validate `.jobforge-index.json`. Query, has, and verify rebuild the index on demand, so scaffolded projects need no setup. This is not an MCP and does not add tool-schema tokens.
|
|
156
156
|
|
|
157
|
+
## JobForge consumer migrations
|
|
158
|
+
|
|
159
|
+
Consumer-project migrations live in `templates/migrations.json` and are applied locally by `@razroo/iso-migrate`. `job-forge sync` applies safe migrations automatically after refreshing symlinks; use `JOB_FORGE_SKIP_MIGRATIONS=1` to opt out. Use `job-forge migrate:plan`, `job-forge migrate:apply`, and `job-forge migrate:check` to inspect or enforce script/gitignore drift explicitly. This is not an MCP and does not add prompt or tool-schema tokens.
|
|
160
|
+
|
|
157
161
|
## JobForge guard audits
|
|
158
162
|
|
|
159
163
|
Guard audits run deterministic `@razroo/iso-guard` policies over the same local OpenCode traces. The default policy lives at `templates/guards/jobforge-baseline.yaml` and checks rules that are reliable from transcript data, including max two task dispatches per assistant message, no task-status polling via `task`, no raw proxy configuration in task prompts, and no child session task recursion.
|
package/docs/SETUP.md
CHANGED
|
@@ -130,6 +130,7 @@ From your project root, these commands maintain the tracker and pipeline checks.
|
|
|
130
130
|
| Inspect context bundle budget | `npx job-forge context:plan apply` | `npm run context:plan -- apply` |
|
|
131
131
|
| Inspect local JD/artifact cache | `npx job-forge cache:status` | `npm run cache:status` |
|
|
132
132
|
| Inspect local artifact index | `npx job-forge index:status` | `npm run index:status` |
|
|
133
|
+
| Inspect pending consumer migrations | `npx job-forge migrate:plan` | `npm run migrate:plan` |
|
|
133
134
|
| Map status column to canonical labels | `npx job-forge normalize` | `npm run normalize` |
|
|
134
135
|
| Merge duplicate company/role rows | `npx job-forge dedup` | `npm run dedup` |
|
|
135
136
|
| Generate ATS-optimized CV PDF | `npx job-forge pdf` | `npm run pdf` |
|
|
@@ -148,6 +149,7 @@ From your project root, these commands maintain the tracker and pipeline checks.
|
|
|
148
149
|
| Check duplicate/status event without loading tracker files | `npx job-forge ledger:has --company "Acme" --role "Staff Engineer" --status Applied` | `npm run ledger:has -- --company ...` |
|
|
149
150
|
| Check/reuse cached JD content | `npx job-forge cache:has --url <url>` / `npx job-forge cache:get --url <url>` | `npm run cache:has -- --url ...` |
|
|
150
151
|
| Query local artifact pointers | `npx job-forge index:query "Acme"` / `npx job-forge index:has --key company-role:acme:staff-engineer` | `npm run index:query -- Acme` |
|
|
152
|
+
| Apply safe consumer migrations | `npx job-forge migrate:apply` | `npm run migrate:apply` |
|
|
151
153
|
| Re-create harness symlinks | `npx job-forge sync` | `npm run sync` |
|
|
152
154
|
| Build optional dashboard TUI (Go on `PATH`) | `(cd node_modules/job-forge/dashboard && go build .)` | `npm run build:dashboard` (harness repo only) |
|
|
153
155
|
|
|
@@ -81,6 +81,11 @@ Local artifact index (terminal, outside opencode):
|
|
|
81
81
|
npx job-forge index:has --key "company-role:acme:staff-engineer"
|
|
82
82
|
npx job-forge index:query "acme"
|
|
83
83
|
|
|
84
|
+
Consumer migrations (terminal, outside opencode):
|
|
85
|
+
npx job-forge migrate:plan # preview package.json/.gitignore drift
|
|
86
|
+
npx job-forge migrate:apply # apply safe harness upgrade migrations
|
|
87
|
+
npx job-forge migrate:check # fail if migrations are pending
|
|
88
|
+
|
|
84
89
|
Artifact contracts (terminal, outside opencode):
|
|
85
90
|
npx iso-contract explain jobforge.tracker-row --contracts templates/contracts.json
|
|
86
91
|
npx job-forge tracker-line ... --write # renders + validates tracker TSV locally
|
package/iso/instructions.md
CHANGED
|
@@ -72,11 +72,14 @@ AI-powered job search pipeline: scans portals, evaluates offers, generates CVs v
|
|
|
72
72
|
- [D13] Use `job-forge index:*` for deterministic artifact lookup when available. `index:has` and `index:query` rebuild `.jobforge-index.json` from `templates/index.json` on demand, covering reports, tracker day files, tracker TSVs, pipeline URLs, scan history, and ledger events without loading those growing files into prompt context.
|
|
73
73
|
why: `iso-index` is not an MCP and adds no prompt/tool-schema tokens; it gives agents compact file/line pointers and duplicate prefilters before expensive reads or browser dispatches
|
|
74
74
|
|
|
75
|
+
- [D14] Treat `templates/migrations.json` as the source of truth for consumer-project upgrades. Use `npx job-forge migrate:plan` or `npx job-forge migrate:check` when diagnosing harness drift; `job-forge sync` applies safe migrations automatically unless `JOB_FORGE_SKIP_MIGRATIONS=1` is set.
|
|
76
|
+
why: `iso-migrate` is not an MCP and adds no prompt/tool-schema tokens; it prevents stale consumer scripts and generated-artifact ignores without asking agents to hand-edit package.json
|
|
77
|
+
|
|
75
78
|
## Procedure
|
|
76
79
|
|
|
77
80
|
1. Check `cv.md`, `profile.yml`, and `portals.yml`; onboard if any file is missing.
|
|
78
81
|
2. Pick and name the mode from **Routing** [D6]. No match → ask; do not guess.
|
|
79
|
-
3. Read the active mode file [D3]. Use context bundle checks when changing context loads [D11]. Check cached artifacts before URL/JD refetches [D12]. Use artifact index lookups before broad file reads when they can answer the question [D13]. Decide inline vs delegated work [D1].
|
|
82
|
+
3. Read the active mode file [D3]. Use context bundle checks when changing context loads [D11]. Check cached artifacts before URL/JD refetches [D12]. Use artifact index lookups before broad file reads when they can answer the question [D13]. Use migration checks for harness drift [D14]. Decide inline vs delegated work [D1].
|
|
80
83
|
4. Prepare Geometra dispatches: cleanup [H3], index/ledger prefilter when useful [D8, D13], dedupe [H2], location filter [D5], routing [D2, D10], proxy prompt hygiene [H8].
|
|
81
84
|
5. Dispatch at most 2 tasks per round [H1]; wait for final outcomes, not just task ids [H5b].
|
|
82
85
|
6. Keep multi-job form-filling out of the orchestrator [H4].
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import {
|
|
4
|
+
loadMigrationConfig,
|
|
5
|
+
parseJson,
|
|
6
|
+
runMigrations,
|
|
7
|
+
} from '@razroo/iso-migrate';
|
|
8
|
+
|
|
9
|
+
export const MIGRATION_CONFIG_FILE = 'templates/migrations.json';
|
|
10
|
+
|
|
11
|
+
export function resolveProjectDir(projectDir = process.env.JOB_FORGE_PROJECT || process.cwd()) {
|
|
12
|
+
return projectDir;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function jobForgeMigrationConfigPath(projectDir = resolveProjectDir()) {
|
|
16
|
+
return process.env.JOB_FORGE_MIGRATIONS_CONFIG || join(projectDir, MIGRATION_CONFIG_FILE);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function migrationConfigExists(projectDir = resolveProjectDir()) {
|
|
20
|
+
return existsSync(jobForgeMigrationConfigPath(projectDir));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function readJobForgeMigrationConfig(projectDir = resolveProjectDir()) {
|
|
24
|
+
const path = jobForgeMigrationConfigPath(projectDir);
|
|
25
|
+
return loadMigrationConfig(parseJson(readFileSync(path, 'utf8'), path));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function runJobForgeMigrations(options = {}, projectDir = resolveProjectDir()) {
|
|
29
|
+
return runMigrations(readJobForgeMigrationConfig(projectDir), {
|
|
30
|
+
root: options.root || projectDir,
|
|
31
|
+
dryRun: options.dryRun,
|
|
32
|
+
});
|
|
33
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "job-forge",
|
|
3
|
-
"version": "2.14.
|
|
3
|
+
"version": "2.14.26",
|
|
4
4
|
"description": "AI-powered job search pipeline built on opencode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -55,6 +55,10 @@
|
|
|
55
55
|
"index:has": "node bin/job-forge.mjs index:has",
|
|
56
56
|
"index:verify": "node bin/job-forge.mjs index:verify",
|
|
57
57
|
"index:explain": "node bin/job-forge.mjs index:explain",
|
|
58
|
+
"migrate:plan": "node bin/job-forge.mjs migrate:plan",
|
|
59
|
+
"migrate:apply": "node bin/job-forge.mjs migrate:apply",
|
|
60
|
+
"migrate:check": "node bin/job-forge.mjs migrate:check",
|
|
61
|
+
"migrate:explain": "node bin/job-forge.mjs migrate:explain",
|
|
58
62
|
"plan": "iso plan .",
|
|
59
63
|
"lint:agentmd": "agentmd lint iso/instructions.md",
|
|
60
64
|
"lint:modes": "isolint lint modes/",
|
|
@@ -128,6 +132,7 @@
|
|
|
128
132
|
"@razroo/iso-guard": "^0.1.0",
|
|
129
133
|
"@razroo/iso-index": "^0.1.0",
|
|
130
134
|
"@razroo/iso-ledger": "^0.1.0",
|
|
135
|
+
"@razroo/iso-migrate": "^0.1.0",
|
|
131
136
|
"@razroo/iso-orchestrator": "^0.1.0",
|
|
132
137
|
"@razroo/iso-trace": "^0.4.0",
|
|
133
138
|
"playwright": "^1.58.1"
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { relative } from 'path';
|
|
4
|
+
import {
|
|
5
|
+
formatConfigSummary,
|
|
6
|
+
formatMigrationResult,
|
|
7
|
+
} from '@razroo/iso-migrate';
|
|
8
|
+
import { PROJECT_DIR } from '../tracker-lib.mjs';
|
|
9
|
+
import {
|
|
10
|
+
jobForgeMigrationConfigPath,
|
|
11
|
+
readJobForgeMigrationConfig,
|
|
12
|
+
runJobForgeMigrations,
|
|
13
|
+
} from '../lib/jobforge-migrate.mjs';
|
|
14
|
+
|
|
15
|
+
const USAGE = `job-forge migrate - deterministic consumer-project migrations
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
job-forge migrate:plan [--json]
|
|
19
|
+
job-forge migrate:apply [--json]
|
|
20
|
+
job-forge migrate:check [--json]
|
|
21
|
+
job-forge migrate:explain [--json]
|
|
22
|
+
job-forge migrate:path
|
|
23
|
+
|
|
24
|
+
The policy is templates/migrations.json. Sync applies these migrations
|
|
25
|
+
automatically unless JOB_FORGE_SKIP_MIGRATIONS=1 is set.`;
|
|
26
|
+
|
|
27
|
+
const [cmd = 'help', ...rawArgs] = process.argv.slice(2);
|
|
28
|
+
const opts = parseArgs(rawArgs);
|
|
29
|
+
|
|
30
|
+
if (opts.help || cmd === 'help' || cmd === '--help' || cmd === '-h') {
|
|
31
|
+
console.log(USAGE);
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
if (cmd === 'path') {
|
|
37
|
+
console.log(jobForgeMigrationConfigPath(PROJECT_DIR));
|
|
38
|
+
} else if (cmd === 'plan') {
|
|
39
|
+
run('plan', opts);
|
|
40
|
+
} else if (cmd === 'apply') {
|
|
41
|
+
run('apply', opts);
|
|
42
|
+
} else if (cmd === 'check') {
|
|
43
|
+
const result = run('check', opts);
|
|
44
|
+
process.exit(result.changed ? 1 : 0);
|
|
45
|
+
} else if (cmd === 'explain') {
|
|
46
|
+
explain(opts);
|
|
47
|
+
} else {
|
|
48
|
+
console.error(`unknown migrate command "${cmd}"\n`);
|
|
49
|
+
console.error(USAGE);
|
|
50
|
+
process.exit(2);
|
|
51
|
+
}
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function parseArgs(args) {
|
|
58
|
+
const opts = { json: false, help: false };
|
|
59
|
+
for (const arg of args) {
|
|
60
|
+
if (arg === '--json') opts.json = true;
|
|
61
|
+
else if (arg === '--help' || arg === '-h') opts.help = true;
|
|
62
|
+
else throw new Error(`unknown flag "${arg}"`);
|
|
63
|
+
}
|
|
64
|
+
return opts;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function run(mode, opts) {
|
|
68
|
+
const result = runJobForgeMigrations({ dryRun: mode !== 'apply' }, PROJECT_DIR);
|
|
69
|
+
if (opts.json) {
|
|
70
|
+
console.log(JSON.stringify(result, null, 2));
|
|
71
|
+
} else {
|
|
72
|
+
console.log(formatMigrationResult(result, mode));
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function explain(opts) {
|
|
78
|
+
const config = readJobForgeMigrationConfig(PROJECT_DIR);
|
|
79
|
+
if (opts.json) {
|
|
80
|
+
console.log(JSON.stringify(config, null, 2));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
console.log(`config: ${relativePath(jobForgeMigrationConfigPath(PROJECT_DIR))}`);
|
|
84
|
+
console.log(formatConfigSummary(config));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function relativePath(path) {
|
|
88
|
+
return relative(PROJECT_DIR, path) || '.';
|
|
89
|
+
}
|
package/templates/index.json
CHANGED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"migrations": [
|
|
4
|
+
{
|
|
5
|
+
"id": "jobforge-managed-scripts",
|
|
6
|
+
"description": "Expose JobForge's deterministic consumer-project helper commands.",
|
|
7
|
+
"operations": [
|
|
8
|
+
{
|
|
9
|
+
"type": "json-merge",
|
|
10
|
+
"path": "package.json",
|
|
11
|
+
"pointer": "/scripts",
|
|
12
|
+
"value": {
|
|
13
|
+
"capabilities:list": "job-forge capabilities:list",
|
|
14
|
+
"capabilities:explain": "job-forge capabilities:explain",
|
|
15
|
+
"capabilities:check": "job-forge capabilities:check",
|
|
16
|
+
"capabilities:render": "job-forge capabilities:render",
|
|
17
|
+
"context:list": "job-forge context:list",
|
|
18
|
+
"context:explain": "job-forge context:explain",
|
|
19
|
+
"context:plan": "job-forge context:plan",
|
|
20
|
+
"context:check": "job-forge context:check",
|
|
21
|
+
"context:render": "job-forge context:render",
|
|
22
|
+
"cache:key": "job-forge cache:key",
|
|
23
|
+
"cache:has": "job-forge cache:has",
|
|
24
|
+
"cache:get": "job-forge cache:get",
|
|
25
|
+
"cache:put": "job-forge cache:put",
|
|
26
|
+
"cache:status": "job-forge cache:status",
|
|
27
|
+
"cache:list": "job-forge cache:list",
|
|
28
|
+
"cache:verify": "job-forge cache:verify",
|
|
29
|
+
"cache:prune": "job-forge cache:prune",
|
|
30
|
+
"index:build": "job-forge index:build",
|
|
31
|
+
"index:status": "job-forge index:status",
|
|
32
|
+
"index:verify": "job-forge index:verify",
|
|
33
|
+
"index:has": "job-forge index:has",
|
|
34
|
+
"index:query": "job-forge index:query",
|
|
35
|
+
"index:explain": "job-forge index:explain",
|
|
36
|
+
"migrate:plan": "job-forge migrate:plan",
|
|
37
|
+
"migrate:apply": "job-forge migrate:apply",
|
|
38
|
+
"migrate:check": "job-forge migrate:check",
|
|
39
|
+
"migrate:explain": "job-forge migrate:explain"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"id": "jobforge-generated-ignores",
|
|
46
|
+
"description": "Keep generated JobForge runtime artifacts out of consumer git state.",
|
|
47
|
+
"operations": [
|
|
48
|
+
{
|
|
49
|
+
"type": "ensure-lines",
|
|
50
|
+
"path": ".gitignore",
|
|
51
|
+
"create": true,
|
|
52
|
+
"after": "# Generated",
|
|
53
|
+
"lines": [
|
|
54
|
+
".jobforge-runs/",
|
|
55
|
+
".jobforge-ledger/",
|
|
56
|
+
".jobforge-cache/",
|
|
57
|
+
".jobforge-index.json"
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
}
|