knowme-careerforge-skill 0.0.4 → 0.0.7

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.
Files changed (117) hide show
  1. package/AGENT.md +276 -0
  2. package/ARCHITECTURE.md +220 -0
  3. package/README.md +46 -63
  4. package/README.zh-CN.md +47 -66
  5. package/SKILL.md +38 -135
  6. package/agents/claude/knowme-careerforge.md +2 -17
  7. package/agents/codex/knowme-careerforge.yaml +2 -20
  8. package/agents/cursor/knowme-careerforge.mdc +4 -13
  9. package/agents/gemini/knowme-careerforge.json +1 -1
  10. package/agents/opencode/skill.yaml +1 -1
  11. package/agents/windsurf/knowme-careerforge.rules +2 -12
  12. package/dist/cli/src/commands/init.js +51 -32
  13. package/dist/cli/src/index.js +25 -21
  14. package/dist/scripts/rendering/engine-loader.d.ts +2 -0
  15. package/dist/scripts/rendering/engine-loader.js +46 -0
  16. package/dist/scripts/rendering/render-pdf.d.ts +3 -8
  17. package/dist/scripts/rendering/render-pdf.js +7 -103
  18. package/dist/scripts/rendering/runtime.d.ts +9 -0
  19. package/dist/scripts/rendering/runtime.js +63 -0
  20. package/dist/scripts/validation/validate-ats.d.ts +2 -22
  21. package/dist/scripts/validation/validate-ats.js +6 -168
  22. package/dist/scripts/validation/validate-layout.d.ts +2 -23
  23. package/dist/scripts/validation/validate-layout.js +5 -159
  24. package/package.json +15 -4
  25. package/references/01-evidence-mining.md +35 -0
  26. package/references/02-career-goal.md +40 -0
  27. package/references/03-jd-analysis.md +32 -0
  28. package/references/04-template-selection.md +30 -0
  29. package/references/05-html-canvas-tokens.md +12 -0
  30. package/references/06-qa-and-rendering.md +27 -0
  31. package/references/07-artifact-contract.md +83 -0
  32. package/scripts/Agent.md +9 -136
  33. package/scripts/build/build-gallery.py +66 -56
  34. package/scripts/build/run-all-tests.py +1 -0
  35. package/scripts/build/sync-version.py +27 -9
  36. package/scripts/contracts/profile.py +101 -0
  37. package/scripts/evidence/extract-evidence.py +109 -62
  38. package/scripts/pipeline/forge.py +276 -136
  39. package/scripts/rendering/README.md +65 -0
  40. package/scripts/rendering/browser-engine.d.ts +15 -0
  41. package/scripts/rendering/browser-engine.js +408 -0
  42. package/scripts/rendering/browser_engine.py +39 -0
  43. package/scripts/rendering/engine-loader.ts +11 -0
  44. package/scripts/rendering/render-pdf.py +26 -151
  45. package/scripts/rendering/render-pdf.ts +7 -83
  46. package/scripts/template/instantiate-resume.py +266 -173
  47. package/scripts/template/search-template.py +89 -3
  48. package/scripts/validation/measure-dom.js +5 -0
  49. package/scripts/validation/validate-ats.ts +6 -174
  50. package/scripts/validation/validate-layout.ts +5 -159
  51. package/scripts/validation/validate-resume.py +23 -134
  52. package/skill.json +7 -6
  53. package/src/knowledge/index.json +391 -3
  54. package/src/knowledge/resume-schema.json +377 -71
  55. package/src/knowledge/templates.json +389 -1
  56. package/src/references/01-evidence-mining.md +24 -30
  57. package/src/references/02-career-goal.md +4 -2
  58. package/src/references/03-jd-analysis.md +5 -17
  59. package/src/references/04-template-selection.md +20 -33
  60. package/src/references/05-html-canvas-tokens.md +6 -45
  61. package/src/references/06-qa-and-rendering.md +16 -43
  62. package/src/references/07-artifact-contract.md +83 -0
  63. package/src/templates/Agent.md +11 -0
  64. package/src/templates/academic-research/README.md +25 -0
  65. package/src/templates/academic-research/canvas.html +21 -0
  66. package/src/templates/academic-research/metadata.json +38 -0
  67. package/src/templates/academic-research/sample-profile.json +86 -0
  68. package/src/templates/academic-research/style.css +213 -0
  69. package/src/templates/classic/README.md +9 -0
  70. package/src/templates/classic/canvas.html +21 -0
  71. package/src/templates/classic/metadata.json +3 -0
  72. package/src/templates/classic/sample-profile.json +86 -0
  73. package/src/templates/classic/style.css +14 -4
  74. package/src/templates/common/base.css +32 -0
  75. package/src/templates/common/canvas-bindings.css +41 -0
  76. package/src/templates/common/resume-contract.md +8 -0
  77. package/src/templates/compact-dense/README.md +25 -0
  78. package/src/templates/compact-dense/canvas.html +14 -0
  79. package/src/templates/compact-dense/metadata.json +38 -0
  80. package/src/templates/compact-dense/sample-profile.json +86 -0
  81. package/src/templates/compact-dense/style.css +218 -0
  82. package/src/templates/creative-tech/README.md +26 -0
  83. package/src/templates/creative-tech/canvas.html +15 -0
  84. package/src/templates/creative-tech/metadata.json +39 -0
  85. package/src/templates/creative-tech/sample-profile.json +86 -0
  86. package/src/templates/creative-tech/style.css +257 -0
  87. package/src/templates/data-analyst/README.md +26 -0
  88. package/src/templates/data-analyst/canvas.html +15 -0
  89. package/src/templates/data-analyst/metadata.json +39 -0
  90. package/src/templates/data-analyst/sample-profile.json +86 -0
  91. package/src/templates/data-analyst/style.css +285 -0
  92. package/src/templates/executive/README.md +9 -0
  93. package/src/templates/executive/canvas.html +15 -0
  94. package/src/templates/executive/sample-profile.json +86 -0
  95. package/src/templates/executive/style.css +58 -6
  96. package/src/templates/international-flow/README.md +26 -0
  97. package/src/templates/international-flow/canvas.html +21 -0
  98. package/src/templates/international-flow/metadata.json +37 -0
  99. package/src/templates/international-flow/sample-profile.json +86 -0
  100. package/src/templates/international-flow/style.css +208 -0
  101. package/src/templates/minimal/README.md +12 -1
  102. package/src/templates/minimal/canvas.html +21 -0
  103. package/src/templates/minimal/sample-profile.json +86 -0
  104. package/src/templates/minimal/style.css +24 -0
  105. package/src/templates/modern/README.md +9 -0
  106. package/src/templates/modern/canvas.html +15 -0
  107. package/src/templates/modern/sample-profile.json +86 -0
  108. package/src/templates/modern/style.css +48 -1
  109. package/src/templates/startup-generalist/README.md +25 -0
  110. package/src/templates/startup-generalist/canvas.html +21 -0
  111. package/src/templates/startup-generalist/metadata.json +37 -0
  112. package/src/templates/startup-generalist/sample-profile.json +86 -0
  113. package/src/templates/startup-generalist/style.css +237 -0
  114. package/src/templates/classic/template.html +0 -133
  115. package/src/templates/executive/template.html +0 -101
  116. package/src/templates/minimal/template.html +0 -114
  117. package/src/templates/modern/template.html +0 -139
@@ -1,24 +1,6 @@
1
1
  name: knowme-careerforge
2
2
  description: An agent-native skill for self-discovery, career positioning, and tailored resume engineering.
3
- version: 0.0.4
3
+ version: 0.0.7
4
4
  entrypoint: SKILL.md
5
- tools:
6
- - name: forge
7
- command: python3 scripts/pipeline/forge.py
8
- - name: extract-evidence
9
- command: python3 scripts/evidence/extract-evidence.py
10
- - name: search-template
11
- command: python3 scripts/template/search-template.py
12
- - name: analyze-jd
13
- command: python3 scripts/evidence/analyze-jd.py
14
- - name: instantiate-resume
15
- command: python3 scripts/template/instantiate-resume.py
16
- - name: validate-resume
17
- command: python3 scripts/validation/validate-resume.py
18
- - name: render-pdf
19
- command: python3 scripts/rendering/render-pdf.py
20
5
  rules:
21
- - "Execute tools silently in background with --quiet (DO NOT print raw HTML, full CSS, or scripts in chat)."
22
- - "Use workspace/resume.html as the sole Intermediate Working Canvas."
23
- - "Deliver final concise summary and path to workspace/resume.pdf."
24
- - "Reference AGENT.md, ARCHITECTURE.md, and references/01~06 for complete specifications."
6
+ - "Read SKILL.md at the installed skill root and follow it as the single runtime workflow. Resolve its scripts and references from that directory, not the candidate workspace. Load supporting references only when the current step needs them. Do not load AGENT.md or architecture documents to make a resume."
@@ -1,17 +1,8 @@
1
1
  ---
2
- description: KnowMe CareerForge — Agent-native career positioning and resume engineering
3
- globs: ["workspace/*", "src/**/*", "scripts/**/*", "references/*"]
2
+ description: Resume drafting and verified delivery from user-provided facts
3
+ alwaysApply: false
4
4
  ---
5
5
 
6
- # KnowMe CareerForge MDC Rules (Cursor)
6
+ # KnowMe CareerForge
7
7
 
8
- When activated for career positioning, resume tailoring, or repo-to-resume analysis:
9
-
10
- 1. **Evidence-First Invariant**: Enforce strict L1~L3 evidence classification (see `references/01-evidence-mining.md`). Never hallucinate ungrounded revenue metrics, fake degrees, or false tenures.
11
- 2. **Repo-to-Resume Extraction**: Extract codebase facts using `python3 scripts/evidence/extract-evidence.py --repo .` or execute the one-shot pipeline `python3 scripts/pipeline/forge.py`.
12
- 3. **Target Alignment & JD Parsing**: Analyze target Job Descriptions using `python3 scripts/evidence/analyze-jd.py` (see `references/03-jd-analysis.md`).
13
- 4. **Template Search**: Match template via `python3 scripts/template/search-template.py "<Target Role>"` (see `references/04-template-selection.md`).
14
- 5. **HTML Canvas Editing**: Edit exclusively in `workspace/resume.html` Intermediate Working Canvas (`scripts/template/instantiate-resume.py`). Calibrate CSS variables (`--resume-*`) in `:root` (see `references/05-html-canvas-tokens.md`).
15
- 6. **Dual QA & Deterministic PDF**: Validate layout height ($297\text{mm} \le 1122.5\text{px}$) and ATS via `python3 scripts/validation/validate-resume.py`. Export final vector PDF via `python3 scripts/rendering/render-pdf.py`.
16
- 7. **Quiet Execution Protocol**: Execute all tools silently with `--quiet`. Never output raw HTML/CSS into the chat. Deliver concise value proposition and direct output file paths.
17
- 8. **Authoritative Guide**: Refer to root `AGENT.md` for Vercel-inspired editorial standards and `ARCHITECTURE.md` for system design.
8
+ Read SKILL.md at the installed skill root and follow it as the single runtime workflow. Resolve its scripts and references from that directory, not the candidate workspace. Load supporting references only when the current step needs them. Do not load AGENT.md or architecture documents to make a resume.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knowme-careerforge",
3
3
  "description": "An agent-native skill for self-discovery, career positioning, and tailored resume engineering.",
4
- "instructions": "Execute the 6-stage KnowMe CareerForge workflow: Know Me (L1~L3 evidence) -> Define -> Understand (JD signals) -> Position -> Forge (HTML canvas & tokens) -> Review (Dual QA & PDF export).",
4
+ "instructions": "Read SKILL.md at the installed skill root and follow it as the single runtime workflow. Resolve its scripts and references from that directory, not the candidate workspace. Load supporting references only when the current step needs them. Do not load AGENT.md or architecture documents to make a resume.",
5
5
  "entrypoint": "SKILL.md"
6
6
  }
@@ -1,7 +1,7 @@
1
1
  name: knowme-careerforge
2
2
  displayName: KnowMe CareerForge
3
3
  description: An agent-native skill for self-discovery, career positioning, and tailored resume engineering.
4
- version: 0.0.4
4
+ version: 0.0.7
5
5
  schema: 1.0
6
6
  entrypoint: SKILL.md
7
7
  tags:
@@ -1,13 +1,3 @@
1
- # KnowMe CareerForge — Windsurf Rules
2
- # Trigger: Career discovery, resume tailoring, JD analysis, repo-to-resume
1
+ # KnowMe CareerForge
3
2
 
4
- When user requests resume tailoring, project analysis, or career positioning:
5
- 1. **Evidence Mining**: Extract candidate facts using `python3 scripts/evidence/extract-evidence.py --repo .` or execute one-shot `python3 scripts/pipeline/forge.py`.
6
- 2. **Anti-Hallucination Gate**: Tag all experience items with Evidence Level (L1~L3 only, see `references/01-evidence-mining.md`).
7
- 3. **JD & Signal Analysis**: Analyze target JD requirements using `python3 scripts/evidence/analyze-jd.py` (see `references/03-jd-analysis.md`).
8
- 4. **Template Search**: Recommend best template using `python3 scripts/template/search-template.py` (see `references/04-template-selection.md`).
9
- 5. **Canvas Instantiation**: Instantiate `workspace/resume.html` using `python3 scripts/template/instantiate-resume.py` and calibrate CSS design tokens (see `references/05-html-canvas-tokens.md`).
10
- 6. **Dual QA Verification**: Validate DOM fit ($297\text{mm} \le 1122.5\text{px}$) and ATS compatibility using `python3 scripts/validation/validate-resume.py`.
11
- 7. **Deterministic PDF Export**: Export final vector PDF using `python3 scripts/rendering/render-pdf.py` (see `references/06-qa-and-rendering.md`).
12
- 8. **Quiet Delivery**: Execute silently in background (`--quiet`); deliver concise value proposition and direct output file paths (`workspace/resume.pdf`).
13
- 9. **Authoritative Guide**: Refer to root `AGENT.md` for editorial standards and `ARCHITECTURE.md` for system architecture.
3
+ Read SKILL.md at the installed skill root and follow it as the single runtime workflow. Resolve its scripts and references from that directory, not the candidate workspace. Load supporting references only when the current step needs them. Do not load AGENT.md or architecture documents to make a resume.
@@ -70,6 +70,25 @@ function copyDirRecursive(src, dest) {
70
70
  }
71
71
  }
72
72
  }
73
+ function copyRuntimeBundle(rootDir, destination) {
74
+ fs.mkdirSync(destination, { recursive: true });
75
+ for (const directory of ['scripts', 'src', 'references']) {
76
+ copyDirRecursive(path.join(rootDir, directory), path.join(destination, directory));
77
+ }
78
+ for (const file of ['SKILL.md', 'skill.json', 'package.json']) {
79
+ fs.copyFileSync(path.join(rootDir, file), path.join(destination, file));
80
+ }
81
+ // npm archives omit package-lock.json; source checkouts can retain a locked install.
82
+ const lock = path.join(rootDir, 'package-lock.json');
83
+ const installedLock = path.join(destination, 'package-lock.json');
84
+ if (fs.existsSync(lock))
85
+ fs.copyFileSync(lock, installedLock);
86
+ else
87
+ fs.rmSync(installedLock, { force: true });
88
+ console.log(`Runtime files copied -> ${destination}`);
89
+ console.log(`Prepare dependencies in that directory: npm ${fs.existsSync(lock) ? 'ci' : 'install'} --omit=dev`);
90
+ console.log('Then run: node scripts/rendering/browser-engine.js --check-runtime');
91
+ }
73
92
  function runInit(options) {
74
93
  const rootDir = findPackageRoot(__dirname);
75
94
  const projectDir = options.projectDir ? path.resolve(options.projectDir) : process.cwd();
@@ -85,82 +104,82 @@ function runInit(options) {
85
104
  console.log(` Target Project: ${projectDir}`);
86
105
  console.log(` Platforms : ${targetPlatforms.join(', ')}`);
87
106
  console.log('==============================================================');
107
+ let failures = 0;
88
108
  for (const plat of targetPlatforms) {
89
109
  try {
90
110
  switch (plat) {
91
111
  case 'claude': {
92
112
  const claudeDir = path.join(homeDir, '.claude', 'skills', 'knowme-careerforge');
93
- fs.mkdirSync(claudeDir, { recursive: true });
94
- copyDirRecursive(path.join(rootDir, 'scripts'), path.join(claudeDir, 'scripts'));
95
- copyDirRecursive(path.join(rootDir, 'src'), path.join(claudeDir, 'src'));
96
- copyDirRecursive(path.join(rootDir, 'references'), path.join(claudeDir, 'references'));
97
- fs.copyFileSync(path.join(rootDir, 'SKILL.md'), path.join(claudeDir, 'SKILL.md'));
98
- fs.copyFileSync(path.join(rootDir, 'AGENT.md'), path.join(claudeDir, 'AGENT.md'));
99
- fs.copyFileSync(path.join(rootDir, 'ARCHITECTURE.md'), path.join(claudeDir, 'ARCHITECTURE.md'));
100
- fs.copyFileSync(path.join(rootDir, 'skill.json'), path.join(claudeDir, 'skill.json'));
101
- console.log(`[✓] Claude Code Skill fully bundled -> ${claudeDir}`);
113
+ copyRuntimeBundle(rootDir, claudeDir);
114
+ console.log(`[✓] Claude Code Skill files installed -> ${claudeDir}`);
102
115
  break;
103
116
  }
104
117
  case 'codex': {
105
118
  const codexDir = path.join(homeDir, '.codex', 'skills', 'knowme-careerforge');
106
- fs.mkdirSync(codexDir, { recursive: true });
107
- copyDirRecursive(path.join(rootDir, 'scripts'), path.join(codexDir, 'scripts'));
108
- copyDirRecursive(path.join(rootDir, 'src'), path.join(codexDir, 'src'));
109
- copyDirRecursive(path.join(rootDir, 'references'), path.join(codexDir, 'references'));
110
- fs.copyFileSync(path.join(rootDir, 'SKILL.md'), path.join(codexDir, 'SKILL.md'));
111
- fs.copyFileSync(path.join(rootDir, 'AGENT.md'), path.join(codexDir, 'AGENT.md'));
112
- fs.copyFileSync(path.join(rootDir, 'ARCHITECTURE.md'), path.join(codexDir, 'ARCHITECTURE.md'));
113
- fs.copyFileSync(path.join(rootDir, 'skill.json'), path.join(codexDir, 'skill.json'));
119
+ copyRuntimeBundle(rootDir, codexDir);
114
120
  if (fs.existsSync(path.join(rootDir, 'agents', 'codex', 'knowme-careerforge.yaml'))) {
115
121
  fs.copyFileSync(path.join(rootDir, 'agents', 'codex', 'knowme-careerforge.yaml'), path.join(codexDir, 'skill.yaml'));
116
122
  }
117
- console.log(`[✓] Codex Native Skill fully bundled -> ${codexDir}`);
123
+ console.log(`[✓] Codex Native Skill files installed -> ${codexDir}`);
118
124
  break;
119
125
  }
120
126
  case 'cursor': {
121
127
  const cursorRulesDir = path.join(projectDir, '.cursor', 'rules');
122
128
  fs.mkdirSync(cursorRulesDir, { recursive: true });
129
+ const runtimeDir = path.join(projectDir, '.knowme', 'skills', 'knowme-careerforge');
130
+ copyRuntimeBundle(rootDir, runtimeDir);
123
131
  const mdcContent = fs.readFileSync(path.join(rootDir, 'agents', 'cursor', 'knowme-careerforge.mdc'), 'utf-8');
124
- fs.writeFileSync(path.join(cursorRulesDir, 'knowme-careerforge.mdc'), mdcContent, 'utf-8');
132
+ fs.writeFileSync(path.join(cursorRulesDir, 'knowme-careerforge.mdc'), mdcContent + `\nRuntime entry: ${JSON.stringify(path.join(runtimeDir, 'SKILL.md'))}\n`, 'utf-8');
125
133
  console.log(`[✓] Cursor MDC Rule configured -> ${path.join(cursorRulesDir, 'knowme-careerforge.mdc')}`);
126
134
  break;
127
135
  }
128
136
  case 'windsurf': {
129
137
  const windsurfRulePath = path.join(projectDir, '.windsurfrules');
138
+ const runtimeDir = path.join(projectDir, '.knowme', 'skills', 'knowme-careerforge');
139
+ copyRuntimeBundle(rootDir, runtimeDir);
130
140
  const ruleContent = fs.readFileSync(path.join(rootDir, 'agents', 'windsurf', 'knowme-careerforge.rules'), 'utf-8');
131
- fs.appendFileSync(windsurfRulePath, `\n\n${ruleContent}`, 'utf-8');
141
+ const begin = '<!-- knowme-careerforge:start -->';
142
+ const end = '<!-- knowme-careerforge:end -->';
143
+ const previous = fs.existsSync(windsurfRulePath) ? fs.readFileSync(windsurfRulePath, 'utf-8') : '';
144
+ const block = `${begin}\n${ruleContent}\nRuntime entry: ${JSON.stringify(path.join(runtimeDir, 'SKILL.md'))}\n${end}`;
145
+ const managed = /<!-- knowme-careerforge:start -->[\s\S]*?<!-- knowme-careerforge:end -->/;
146
+ fs.writeFileSync(windsurfRulePath, managed.test(previous) ? previous.replace(managed, () => block) : previous + `\n\n${block}\n`, 'utf-8');
132
147
  console.log(`[✓] Windsurf Rule configured -> ${windsurfRulePath}`);
133
148
  break;
134
149
  }
135
150
  case 'gemini': {
136
151
  const geminiDir = path.join(homeDir, '.gemini', 'skills');
137
152
  fs.mkdirSync(geminiDir, { recursive: true });
138
- const geminiJson = fs.readFileSync(path.join(rootDir, 'agents', 'gemini', 'knowme-careerforge.json'), 'utf-8');
139
- fs.writeFileSync(path.join(geminiDir, 'knowme-careerforge.json'), geminiJson, 'utf-8');
153
+ const runtimeDir = path.join(geminiDir, 'knowme-careerforge');
154
+ copyRuntimeBundle(rootDir, runtimeDir);
155
+ const geminiConfig = JSON.parse(fs.readFileSync(path.join(rootDir, 'agents', 'gemini', 'knowme-careerforge.json'), 'utf-8'));
156
+ geminiConfig.entrypoint = path.join(runtimeDir, 'SKILL.md');
157
+ fs.writeFileSync(path.join(geminiDir, 'knowme-careerforge.json'), JSON.stringify(geminiConfig, null, 2) + '\n', 'utf-8');
140
158
  console.log(`[✓] Gemini CLI Skill configured -> ${path.join(geminiDir, 'knowme-careerforge.json')}`);
141
159
  break;
142
160
  }
143
161
  case 'opencode': {
144
162
  const opencodeDir = path.join(projectDir, '.opencode', 'skills', 'knowme-careerforge');
145
- fs.mkdirSync(opencodeDir, { recursive: true });
146
- copyDirRecursive(path.join(rootDir, 'scripts'), path.join(opencodeDir, 'scripts'));
147
- copyDirRecursive(path.join(rootDir, 'src'), path.join(opencodeDir, 'src'));
148
- copyDirRecursive(path.join(rootDir, 'references'), path.join(opencodeDir, 'references'));
149
- fs.copyFileSync(path.join(rootDir, 'SKILL.md'), path.join(opencodeDir, 'SKILL.md'));
150
- fs.copyFileSync(path.join(rootDir, 'AGENT.md'), path.join(opencodeDir, 'AGENT.md'));
151
- fs.copyFileSync(path.join(rootDir, 'ARCHITECTURE.md'), path.join(opencodeDir, 'ARCHITECTURE.md'));
152
- fs.copyFileSync(path.join(rootDir, 'skill.json'), path.join(opencodeDir, 'skill.json'));
153
- console.log(`[✓] OpenCode Skill fully bundled -> ${opencodeDir}`);
163
+ copyRuntimeBundle(rootDir, opencodeDir);
164
+ console.log(`[✓] OpenCode Skill files installed -> ${opencodeDir}`);
154
165
  break;
155
166
  }
156
167
  default:
168
+ failures += 1;
157
169
  console.log(`[!] Unknown platform: ${plat}. Supported: ${SUPPORTED_PLATFORMS.join(', ')}`);
158
170
  }
159
171
  }
160
172
  catch (err) {
173
+ failures += 1;
161
174
  const msg = err instanceof Error ? err.message : String(err);
162
175
  console.error(`[✗] Failed to initialize ${plat}: ${msg}`);
163
176
  }
164
177
  }
165
- console.log('\n[✓] Skill setup complete. You can now use knowme-careerforge in your agent workflows!');
178
+ if (failures) {
179
+ process.exitCode = 1;
180
+ console.error(`[✗] ${failures} platform setup(s) failed.`);
181
+ }
182
+ else {
183
+ console.log('Configuration and runtime files installed. Prepare dependencies and check runtime before generating PDFs; host discovery must be verified separately.');
184
+ }
166
185
  }
@@ -58,11 +58,11 @@ function getVersion(rootDir) {
58
58
  const pkgJson = path.join(rootDir, 'package.json');
59
59
  if (require('fs').existsSync(pkgJson)) {
60
60
  const data = JSON.parse(require('fs').readFileSync(pkgJson, 'utf-8'));
61
- return data.version || '0.0.4';
61
+ return data.version || '0.0.7';
62
62
  }
63
63
  }
64
64
  catch { }
65
- return '0.0.4';
65
+ return '0.0.7';
66
66
  }
67
67
  function showHelp() {
68
68
  console.log(`
@@ -74,8 +74,7 @@ Usage:
74
74
  knowme <command> [options]
75
75
 
76
76
  Commands:
77
- forge One-shot resume engineering pipeline (repo mining -> canvas -> QA -> PDF)
78
- extract Extract candidate evidence & facts from codebase/Git repo
77
+ forge Isolated user facts -> variant -> canvas -> verified PDF
79
78
  render Multi-strategy deterministic A4 PDF export
80
79
  init Install and configure Skill for AI Agent platforms (cursor, claude, codex, windsurf, gemini, opencode)
81
80
  list Display all available role profiles and HTML templates
@@ -86,17 +85,19 @@ Commands:
86
85
  help Show this help message
87
86
 
88
87
  Options (for forge):
89
- --repo, -r <dir> Target repository path (default: .)
88
+ --profile-json <file> User/Agent prepared facts or Master document
89
+ --workspace <dir> Parent for isolated run directories (default: workspace/runs)
90
+ --draft Create a draft canvas without PDF delivery
90
91
  --role <title> Target role title
91
92
  --jd <file|text> Target job description
92
- --template, -t <id> Template ID (minimal, modern, executive, classic)
93
+ --template, -t <id> Template ID (minimal, modern, executive, classic, academic-research, international-flow, creative-tech, compact-dense, startup-generalist, data-analyst)
93
94
  --name <name> Candidate name override
94
- --output, -o <path> Output PDF path (default: workspace/resume.pdf)
95
+ --output, -o <path> Optional verified PDF copy (default: isolated run)
96
+ --font-preset <name> system or arial-unicode (requires local Arial Unicode MS)
97
+ --auto-heal Enable heuristic token auto-healing to eliminate A4 height overflow
95
98
  --quiet, -q Quiet execution (compact JSON output)
96
-
97
99
  Examples:
98
- knowme forge --repo . --role "AI Agent Engineer" --template modern
99
- knowme extract --repo . --output workspace/evidence-master.json
100
+ knowme forge --profile-json candidate.json --role "AI Agent Engineer" --template modern
100
101
  knowme render workspace/resume.html workspace/resume.pdf
101
102
  knowme init --ai codex
102
103
  knowme init --all
@@ -118,13 +119,8 @@ function main() {
118
119
  break;
119
120
  }
120
121
  case 'extract': {
121
- let scriptPath = path.join(rootDir, 'scripts', 'evidence', 'extract-evidence.py');
122
- if (!require('fs').existsSync(scriptPath))
123
- scriptPath = path.join(rootDir, 'scripts', 'extract-evidence.py');
124
- const passArgs = args.slice(1);
125
- const proc = child_process.spawnSync('python3', [scriptPath, ...passArgs], { stdio: 'inherit' });
126
- if (proc.status !== 0)
127
- process.exit(proc.status || 1);
122
+ console.error('Repository-to-resume extraction is not supported. Use user-provided facts with forge --profile-json.');
123
+ process.exitCode = 1;
128
124
  break;
129
125
  }
130
126
  case 'render': {
@@ -165,7 +161,9 @@ function main() {
165
161
  if (!require('fs').existsSync(scriptPath))
166
162
  scriptPath = path.join(rootDir, 'scripts', 'search-template.py');
167
163
  const passArgs = args.slice(1);
168
- child_process.spawnSync('python3', [scriptPath, ...passArgs], { stdio: 'inherit' });
164
+ const proc = child_process.spawnSync('python3', [scriptPath, ...passArgs], { stdio: 'inherit' });
165
+ if (proc.status !== 0)
166
+ process.exit(proc.status || 1);
169
167
  break;
170
168
  }
171
169
  case 'validate': {
@@ -173,21 +171,27 @@ function main() {
173
171
  if (!require('fs').existsSync(scriptPath))
174
172
  scriptPath = path.join(rootDir, 'scripts', 'validate-resume.py');
175
173
  const passArgs = args.slice(1);
176
- child_process.spawnSync('python3', [scriptPath, ...passArgs], { stdio: 'inherit' });
174
+ const proc = child_process.spawnSync('python3', [scriptPath, ...passArgs], { stdio: 'inherit' });
175
+ if (proc.status !== 0)
176
+ process.exit(proc.status || 1);
177
177
  break;
178
178
  }
179
179
  case 'gallery': {
180
180
  let scriptPath = path.join(rootDir, 'scripts', 'build', 'build-gallery.py');
181
181
  if (!require('fs').existsSync(scriptPath))
182
182
  scriptPath = path.join(rootDir, 'scripts', 'build-gallery.py');
183
- child_process.spawnSync('python3', [scriptPath], { stdio: 'inherit' });
183
+ const proc = child_process.spawnSync('python3', [scriptPath], { stdio: 'inherit' });
184
+ if (proc.status !== 0)
185
+ process.exit(proc.status || 1);
184
186
  break;
185
187
  }
186
188
  case 'test': {
187
189
  let scriptPath = path.join(rootDir, 'scripts', 'build', 'run-all-tests.py');
188
190
  if (!require('fs').existsSync(scriptPath))
189
191
  scriptPath = path.join(rootDir, 'scripts', 'run-all-tests.py');
190
- child_process.spawnSync('python3', [scriptPath], { stdio: 'inherit' });
192
+ const proc = child_process.spawnSync('python3', [scriptPath], { stdio: 'inherit' });
193
+ if (proc.status !== 0)
194
+ process.exit(proc.status || 1);
191
195
  break;
192
196
  }
193
197
  case '--version':
@@ -0,0 +1,2 @@
1
+ declare const engine: typeof import('./browser-engine');
2
+ export = engine;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ const fs = __importStar(require("fs"));
36
+ const path = __importStar(require("path"));
37
+ // tsc does not copy JS. Resolve the shipped source engine from source or dist.
38
+ let root = __dirname;
39
+ while (!fs.existsSync(path.join(root, 'package.json'))) {
40
+ const parent = path.dirname(root);
41
+ if (parent === root)
42
+ throw new Error('Cannot locate browser engine project root');
43
+ root = parent;
44
+ }
45
+ const engine = require(path.join(root, 'scripts/rendering/browser-engine.js'));
46
+ module.exports = engine;
@@ -1,11 +1,6 @@
1
1
  #!/usr/bin/env ts-node
2
- /**
3
- * KnowMe CareerForge — Playwright Deterministic PDF Renderer
4
- * 加载自包含 HTML 中间工作区,等待字体及样式准备就绪,输出标准像素级 A4 PDF。
5
- */
6
- interface RenderOptions {
2
+ import type { EngineOptions, EngineResult } from './browser-engine';
3
+ export declare function renderResumePdf(options: EngineOptions & {
7
4
  inputHtml: string;
8
5
  outputPdf: string;
9
- }
10
- export declare function renderResumePdf(options: RenderOptions): Promise<void>;
11
- export {};
6
+ }): Promise<EngineResult>;
@@ -1,109 +1,13 @@
1
1
  #!/usr/bin/env ts-node
2
2
  "use strict";
3
- /**
4
- * KnowMe CareerForge — Playwright Deterministic PDF Renderer
5
- * 加载自包含 HTML 中间工作区,等待字体及样式准备就绪,输出标准像素级 A4 PDF。
6
- */
7
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
- if (k2 === undefined) k2 = k;
9
- var desc = Object.getOwnPropertyDescriptor(m, k);
10
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
- desc = { enumerable: true, get: function() { return m[k]; } };
12
- }
13
- Object.defineProperty(o, k2, desc);
14
- }) : (function(o, m, k, k2) {
15
- if (k2 === undefined) k2 = k;
16
- o[k2] = m[k];
17
- }));
18
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
- Object.defineProperty(o, "default", { enumerable: true, value: v });
20
- }) : function(o, v) {
21
- o["default"] = v;
22
- });
23
- var __importStar = (this && this.__importStar) || (function () {
24
- var ownKeys = function(o) {
25
- ownKeys = Object.getOwnPropertyNames || function (o) {
26
- var ar = [];
27
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
- return ar;
29
- };
30
- return ownKeys(o);
31
- };
32
- return function (mod) {
33
- if (mod && mod.__esModule) return mod;
34
- var result = {};
35
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
- __setModuleDefault(result, mod);
37
- return result;
38
- };
39
- })();
40
3
  Object.defineProperty(exports, "__esModule", { value: true });
41
4
  exports.renderResumePdf = renderResumePdf;
42
- const playwright_1 = require("playwright");
43
- const path = __importStar(require("path"));
44
- const fs = __importStar(require("fs"));
5
+ const engine = require("./engine-loader");
45
6
  async function renderResumePdf(options) {
46
- const absoluteHtml = path.resolve(options.inputHtml);
47
- const absolutePdf = path.resolve(options.outputPdf);
48
- if (!fs.existsSync(absoluteHtml)) {
49
- throw new Error(`Input HTML file does not exist: ${absoluteHtml}`);
50
- }
51
- const outputDir = path.dirname(absolutePdf);
52
- if (!fs.existsSync(outputDir)) {
53
- fs.mkdirSync(outputDir, { recursive: true });
54
- }
55
- console.log('======================================================');
56
- console.log(' KnowMe CareerForge — Playwright PDF Renderer');
57
- console.log(` Source Canvas : ${absoluteHtml}`);
58
- console.log(` Target PDF : ${absolutePdf}`);
59
- console.log('======================================================');
60
- const browser = await playwright_1.chromium.launch({ headless: true });
61
- const context = await browser.newContext({
62
- viewport: { width: 794, height: 1123 }, // A4 at 96 DPI
63
- deviceScaleFactor: 2
64
- });
65
- const page = await context.newPage();
66
- await page.goto(`file://${absoluteHtml}`, { waitUntil: 'networkidle' });
67
- await page.evaluateHandle('document.fonts.ready');
68
- await page.pdf({
69
- path: absolutePdf,
70
- format: 'A4',
71
- printBackground: true,
72
- preferCSSPageSize: true,
73
- margin: { top: '0px', right: '0px', bottom: '0px', left: '0px' }
74
- });
75
- await browser.close();
76
- console.log(`[✓] Deterministic PDF Rendered Successfully -> ${absolutePdf}`);
77
- }
78
- async function main() {
79
- const args = process.argv.slice(2);
80
- let inputHtml = 'workspace/resume.html';
81
- let outputPdf = 'workspace/resume.pdf';
82
- for (let i = 0; i < args.length; i++) {
83
- if (args[i] === '--input' || args[i] === '-i') {
84
- inputHtml = args[i + 1];
85
- i++;
86
- }
87
- else if (args[i] === '--output' || args[i] === '-o') {
88
- outputPdf = args[i + 1];
89
- i++;
90
- }
91
- else if (!args[i].startsWith('-')) {
92
- if (i === 0)
93
- inputHtml = args[i];
94
- else if (i === 1)
95
- outputPdf = args[i];
96
- }
97
- }
98
- try {
99
- await renderResumePdf({ inputHtml, outputPdf });
100
- }
101
- catch (err) {
102
- const errorMsg = err instanceof Error ? err.message : String(err);
103
- console.error(`[✗] PDF Rendering Failed: ${errorMsg}`);
104
- process.exit(1);
105
- }
106
- }
107
- if (require.main === module) {
108
- main();
7
+ const result = await engine.run(options.inputHtml, options);
8
+ if (result.status !== 'PASS')
9
+ throw new Error(JSON.stringify(result));
10
+ return result;
109
11
  }
12
+ if (require.main === module)
13
+ engine.cli(process.argv.slice(2), { outputPdf: 'workspace/resume.pdf' });
@@ -0,0 +1,9 @@
1
+ export interface PrintInspection {
2
+ status: 'PASS' | 'FAIL' | 'UNVERIFIED';
3
+ errors: string[];
4
+ warnings?: string[];
5
+ pdfPages?: number;
6
+ actualHeightPx?: number;
7
+ measurementSource?: string;
8
+ }
9
+ export declare function inspectPrint(htmlPath: string, expectedPages?: number, outputPdf?: string): PrintInspection;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.inspectPrint = inspectPrint;
37
+ /** Typed bridge used by legacy TypeScript entry points and their compiled output. */
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const child_process_1 = require("child_process");
41
+ function inspectPrint(htmlPath, expectedPages = 1, outputPdf) {
42
+ let root = __dirname;
43
+ while (!fs.existsSync(path.join(root, 'SKILL.md'))) {
44
+ const parent = path.dirname(root);
45
+ if (parent === root)
46
+ throw new Error('Skill root not found');
47
+ root = parent;
48
+ }
49
+ const args = [path.join(root, 'scripts/rendering/browser-engine.js'), path.resolve(htmlPath), '--expected-pages', String(expectedPages)];
50
+ if (outputPdf)
51
+ args.push('--output', path.resolve(outputPdf));
52
+ const result = (0, child_process_1.spawnSync)(process.execPath, args, { encoding: 'utf8', timeout: 120000 });
53
+ if (result.error)
54
+ throw result.error;
55
+ const parsed = JSON.parse(result.stdout);
56
+ if (!parsed || typeof parsed !== 'object' || !('status' in parsed) || !('errors' in parsed) || !Array.isArray(parsed.errors))
57
+ throw new Error('Invalid print inspection result');
58
+ if (parsed.status !== 'PASS' && parsed.status !== 'FAIL' && parsed.status !== 'UNVERIFIED')
59
+ throw new Error('Invalid print status');
60
+ if (result.status !== 0 && parsed.status === 'PASS')
61
+ throw new Error('Print engine exited unsuccessfully');
62
+ return parsed;
63
+ }
@@ -1,23 +1,3 @@
1
1
  #!/usr/bin/env ts-node
2
- /**
3
- * KnowMe CareerForge — ATS Text Flow & Heading Hierarchy Inspector
4
- * 验证 HTML 简历中的关键文本可提取性、标头层级规范与 ATS 机器解析友好度。
5
- */
6
- interface AtsValidationResult {
7
- status: 'PASS' | 'WARN' | 'FAIL';
8
- candidateName: string | null;
9
- detectedContacts: {
10
- email: string | null;
11
- phone: string | null;
12
- };
13
- headingsFound: Array<{
14
- level: string;
15
- text: string;
16
- isStandard: boolean;
17
- }>;
18
- totalTextLength: number;
19
- warnings: string[];
20
- errors: string[];
21
- }
22
- export declare function validateAts(htmlPath: string): Promise<AtsValidationResult>;
23
- export {};
2
+ import type { EngineOptions, EngineResult } from '../rendering/browser-engine';
3
+ export declare function validateAts(htmlPath: string, expectedPages?: number, options?: EngineOptions): Promise<EngineResult>;