@namewta/speculo 2.0.5 → 2.1.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.
Files changed (283) hide show
  1. package/README.md +3 -0
  2. package/THIRD-PARTY-NOTICES.md +4 -0
  3. package/dist/src/agent-skills.d.ts +5 -0
  4. package/dist/src/agent-skills.js +10 -7
  5. package/dist/src/agent-skills.js.map +1 -1
  6. package/dist/src/cli.js +17 -4
  7. package/dist/src/cli.js.map +1 -1
  8. package/dist/src/coordination.d.ts +3 -3
  9. package/dist/src/coordination.js +21 -4
  10. package/dist/src/coordination.js.map +1 -1
  11. package/dist/src/doctor.js +8 -1
  12. package/dist/src/doctor.js.map +1 -1
  13. package/dist/src/external-files.d.ts +4 -2
  14. package/dist/src/external-files.js +4 -4
  15. package/dist/src/external-files.js.map +1 -1
  16. package/dist/src/hub-catalog.d.ts +11 -0
  17. package/dist/src/hub-catalog.js +91 -0
  18. package/dist/src/hub-catalog.js.map +1 -0
  19. package/dist/src/hub-resources.json +1 -0
  20. package/dist/src/hub-skills.d.ts +53 -0
  21. package/dist/src/hub-skills.js +157 -0
  22. package/dist/src/hub-skills.js.map +1 -0
  23. package/dist/src/index.d.ts +6 -0
  24. package/dist/src/index.js +48 -47
  25. package/dist/src/index.js.map +1 -1
  26. package/dist/src/install-ui.d.ts +16 -0
  27. package/dist/src/install-ui.js +67 -11
  28. package/dist/src/install-ui.js.map +1 -1
  29. package/dist/src/manifest.d.ts +2 -0
  30. package/dist/src/manifest.js +2 -0
  31. package/dist/src/manifest.js.map +1 -1
  32. package/dist/src/refresh.d.ts +1 -0
  33. package/dist/src/refresh.js +13 -10
  34. package/dist/src/refresh.js.map +1 -1
  35. package/dist/src/retained-workflows.d.ts +10 -0
  36. package/dist/src/retained-workflows.js +25 -0
  37. package/dist/src/retained-workflows.js.map +1 -0
  38. package/dist/src/runtime-entry.d.ts +1 -0
  39. package/dist/src/runtime-entry.js +1 -0
  40. package/dist/src/runtime-entry.js.map +1 -1
  41. package/dist/src/skill-trees.d.ts +27 -0
  42. package/dist/src/skill-trees.js +118 -0
  43. package/dist/src/skill-trees.js.map +1 -0
  44. package/dist/src/transaction.d.ts +3 -14
  45. package/dist/src/transaction.js +20 -36
  46. package/dist/src/transaction.js.map +1 -1
  47. package/dist/src/workflow-install.d.ts +15 -0
  48. package/dist/src/workflow-install.js +104 -0
  49. package/dist/src/workflow-install.js.map +1 -0
  50. package/package.json +4 -2
  51. package/skills-hub/automation/grok-bot-team-steward/CHEATSHEET.md +17 -0
  52. package/skills-hub/automation/grok-bot-team-steward/INSTALL.md +23 -0
  53. package/skills-hub/automation/grok-bot-team-steward/LICENSE +21 -0
  54. package/skills-hub/automation/grok-bot-team-steward/README.md +9 -0
  55. package/skills-hub/automation/grok-bot-team-steward/SKILL.md +52 -0
  56. package/skills-hub/automation/grok-bot-team-steward/agents/openai.yaml +4 -0
  57. package/skills-hub/automation/grok-bot-team-steward/references/00-hard-rules.md +50 -0
  58. package/skills-hub/automation/grok-bot-team-steward/references/01-snapshot-schema.md +84 -0
  59. package/skills-hub/automation/grok-bot-team-steward/references/02-export-protocol.md +57 -0
  60. package/skills-hub/automation/grok-bot-team-steward/references/03-restore-protocol.md +64 -0
  61. package/skills-hub/automation/grok-bot-team-steward/references/04-inventory.md +37 -0
  62. package/skills-hub/automation/grok-bot-team-steward/references/05-conversations.md +71 -0
  63. package/skills-hub/automation/grok-bot-team-steward/references/06-sanitizer.md +39 -0
  64. package/skills-hub/automation/grok-bot-team-steward/references/07-prompts.md +87 -0
  65. package/skills-hub/automation/grok-bot-team-steward/references/08-verification.md +30 -0
  66. package/skills-hub/automation/grok-bot-team-steward/references/09-sources.md +31 -0
  67. package/skills-hub/automation/grok-bot-team-steward/scripts/scrub.sh +17 -0
  68. package/skills-hub/automation/grok-bot-team-steward/scripts/snapshot-name.sh +18 -0
  69. package/skills-hub/automation/grok-bot-team-steward/scripts/validate-snapshot.sh +62 -0
  70. package/skills-hub/automation/grok-bot-team-steward/steward/ACTIVATE.md +58 -0
  71. package/skills-hub/automation/grok-bot-team-steward/steward/SETUP-INSTRUCTIONS.md +33 -0
  72. package/skills-hub/automation/grok-bot-team-steward/steward/STEWARD-PROFILE.md +28 -0
  73. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/CHANGELOG.md +3 -0
  74. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/CHARTER.md +27 -0
  75. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/DROP-LIST.md +10 -0
  76. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/GAPS.md +6 -0
  77. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/INIT.md +14 -0
  78. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/MANIFEST.md +30 -0
  79. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/MANIFEST.yaml +20 -0
  80. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/ORG.md +15 -0
  81. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/README.md +8 -0
  82. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/RESTORE.md +13 -0
  83. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/ROSTER.md +11 -0
  84. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/bots/_SLUG/GAPS.md +7 -0
  85. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/bots/_SLUG/MEMORY.md +9 -0
  86. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/bots/_SLUG/PROFILE.md +27 -0
  87. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/bots/_SLUG/agent-spec.md +9 -0
  88. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/bots/_SLUG/conversations/INDEX.md +5 -0
  89. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/bots/_SLUG/conversations/main.md +9 -0
  90. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/bots/_SLUG/routines.md +5 -0
  91. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/bots/_SLUG/skills.md +5 -0
  92. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/connectors.md +7 -0
  93. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/meta/COMPLETED.md +6 -0
  94. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/meta/CREATED.md +6 -0
  95. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/meta/RESTORE-NOTES.md +13 -0
  96. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/meta/SANITIZER.md +7 -0
  97. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/meta/SOURCE.md +8 -0
  98. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/rooms/_ROOM.md +8 -0
  99. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/routines/_ROUTINE.md +12 -0
  100. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/shared/shared-memory.md +5 -0
  101. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/shared/workspace-map.md +5 -0
  102. package/skills-hub/automation/grok-bot-team-steward/templates/snapshot/skills/_SKILL/SKILL.md +18 -0
  103. package/skills-hub/automation/herdr/SKILL.md +246 -0
  104. package/skills-hub/automation/orca/SKILL.md +328 -0
  105. package/skills-hub/coding/gitea-repo/LICENSE +21 -0
  106. package/skills-hub/coding/gitea-repo/SKILL.md +50 -0
  107. package/skills-hub/coding/gitea-repo/agents/openai.yaml +4 -0
  108. package/skills-hub/coding/gitea-repo/references/auth-and-scopes.md +58 -0
  109. package/skills-hub/coding/gitea-repo/references/endpoint-map.md +80 -0
  110. package/skills-hub/coding/gitea-repo/references/pagination-and-errors.md +34 -0
  111. package/skills-hub/coding/gitea-repo/scripts/gitea_api.py +814 -0
  112. package/skills-hub/coding/github-repo-steward/LICENSE +21 -0
  113. package/skills-hub/coding/github-repo-steward/SKILL.md +48 -0
  114. package/skills-hub/coding/github-repo-steward/agents/openai.yaml +4 -0
  115. package/skills-hub/coding/github-repo-steward/references/00-auth-and-tokens.md +73 -0
  116. package/skills-hub/coding/github-repo-steward/references/01-inventory.md +55 -0
  117. package/skills-hub/coding/github-repo-steward/references/02-lifecycle.md +57 -0
  118. package/skills-hub/coding/github-repo-steward/references/03-stars.md +42 -0
  119. package/skills-hub/coding/github-repo-steward/references/04-hygiene.md +40 -0
  120. package/skills-hub/coding/github-repo-steward/references/05-sources.md +42 -0
  121. package/skills-hub/coding/github-repo-steward/scripts/inventory.sh +64 -0
  122. package/skills-hub/coding/vscode-fullstack/LICENSE +21 -0
  123. package/skills-hub/coding/vscode-fullstack/SKILL.md +47 -0
  124. package/skills-hub/coding/vscode-fullstack/agents/openai.yaml +4 -0
  125. package/skills-hub/coding/vscode-fullstack/references/extensions-and-settings.md +181 -0
  126. package/skills-hub/coding/vscode-fullstack/references/profiles-and-validation.md +62 -0
  127. package/skills-hub/coding/vscode-fullstack/references/runtime-reuse.md +52 -0
  128. package/skills-hub/design/photo-retouch/LICENSE +21 -0
  129. package/skills-hub/design/photo-retouch/SKILL.md +50 -0
  130. package/skills-hub/design/photo-retouch/agents/openai.yaml +4 -0
  131. package/skills-hub/design/photo-retouch/references/basic-retouch.md +58 -0
  132. package/skills-hub/design/photo-retouch/references/formal-portrait.md +57 -0
  133. package/skills-hub/design/photo-retouch/references/object-and-canvas.md +82 -0
  134. package/skills-hub/design/photo-retouch/references/product-photo.md +41 -0
  135. package/skills-hub/design/photo-retouch/references/repair-and-look.md +61 -0
  136. package/skills-hub/design/photo-retouch/references/social-effects.md +55 -0
  137. package/skills-hub/design/photo-retouch/references/travel-creative.md +79 -0
  138. package/skills-hub/system/clash-client-profile/LICENSE +21 -0
  139. package/skills-hub/system/clash-client-profile/SKILL.md +79 -0
  140. package/skills-hub/system/clash-client-profile/agents/openai.yaml +4 -0
  141. package/skills-hub/system/clash-client-profile/references/acceptance.md +81 -0
  142. package/skills-hub/system/clash-client-profile/references/browser-privacy.md +35 -0
  143. package/skills-hub/system/clash-client-profile/references/clash-verge.md +40 -0
  144. package/skills-hub/system/clash-client-profile/references/dns-workflow.md +147 -0
  145. package/skills-hub/system/clash-client-profile/references/flclash.md +24 -0
  146. package/skills-hub/system/clash-client-profile/references/network-performance.md +25 -0
  147. package/skills-hub/system/clash-client-profile/references/platform-dns.md +109 -0
  148. package/skills-hub/system/clash-client-profile/references/sources.md +46 -0
  149. package/skills-hub/system/clash-client-profile/references/troubleshooting.md +82 -0
  150. package/skills-hub/system/clash-client-profile/scripts/dns_guard.py +650 -0
  151. package/skills-hub/system/clash-client-profile/scripts/proxy_doctor.py +213 -0
  152. package/skills-hub/system/clash-client-profile/scripts/render_rules.py +34 -0
  153. package/skills-hub/system/clash-client-profile/templates/ai-rules.yaml +18 -0
  154. package/skills-hub/system/clash-client-profile/templates/dns-request.example.json +9 -0
  155. package/skills-hub/system/clash-client-profile/templates/dns.yaml +8 -0
  156. package/skills-hub/system/linux-dev-disk-cleanup/LICENSE +21 -0
  157. package/skills-hub/system/linux-dev-disk-cleanup/SKILL.md +42 -0
  158. package/skills-hub/system/linux-dev-disk-cleanup/agents/openai.yaml +4 -0
  159. package/skills-hub/system/linux-dev-disk-cleanup/references/linux-cleanup-workflow.md +145 -0
  160. package/skills-hub/system/optimize-codex-config/LICENSE +21 -0
  161. package/skills-hub/system/optimize-codex-config/SKILL.md +101 -0
  162. package/skills-hub/system/optimize-codex-config/agents/openai.yaml +4 -0
  163. package/skills-hub/system/optimize-codex-config/assets/capabilities.example.json +22 -0
  164. package/skills-hub/system/optimize-codex-config/references/cli.md +35 -0
  165. package/skills-hub/system/optimize-codex-config/references/configuration-contract.md +33 -0
  166. package/skills-hub/system/optimize-codex-config/references/optimization-method.md +38 -0
  167. package/skills-hub/system/optimize-codex-config/references/privacy.md +41 -0
  168. package/skills-hub/system/optimize-codex-config/references/sources.md +24 -0
  169. package/skills-hub/system/optimize-codex-config/references/statusline.md +31 -0
  170. package/skills-hub/system/optimize-codex-config/references/transactions.md +32 -0
  171. package/skills-hub/system/optimize-codex-config/references/troubleshooting.md +95 -0
  172. package/skills-hub/system/optimize-codex-config/scripts/adapters/claude.mjs +24 -0
  173. package/skills-hub/system/optimize-codex-config/scripts/adapters/codex.mjs +10 -0
  174. package/skills-hub/system/optimize-codex-config/scripts/ai-cli-config.mjs +67 -0
  175. package/skills-hub/system/optimize-codex-config/scripts/audit-codex-config.mjs +762 -0
  176. package/skills-hub/system/optimize-codex-config/scripts/lib/document.mjs +166 -0
  177. package/skills-hub/system/optimize-codex-config/scripts/lib/inspect.mjs +211 -0
  178. package/skills-hub/system/optimize-codex-config/scripts/lib/io.mjs +104 -0
  179. package/skills-hub/system/optimize-codex-config/scripts/lib/plan.mjs +79 -0
  180. package/skills-hub/system/optimize-codex-config/scripts/lib/transaction.mjs +205 -0
  181. package/skills-hub/system/optimize-codex-config/scripts/lib/writers.mjs +46 -0
  182. package/skills-hub/system/optimize-codex-config/scripts/statusline/claude-statusline.mjs +94 -0
  183. package/skills-hub/system/optimize-codex-config/scripts/vendor/THIRD-PARTY-NOTICES.txt +250 -0
  184. package/skills-hub/system/optimize-codex-config/scripts/vendor/build-package-lock.json +488 -0
  185. package/skills-hub/system/optimize-codex-config/scripts/vendor/manifest.json +14 -0
  186. package/skills-hub/system/optimize-codex-config/scripts/vendor/parsers.mjs +16 -0
  187. package/skills-hub/system/proxy-region-locale/LICENSE +21 -0
  188. package/skills-hub/system/proxy-region-locale/SKILL.md +42 -0
  189. package/skills-hub/system/proxy-region-locale/agents/openai.yaml +4 -0
  190. package/skills-hub/system/proxy-region-locale/references/linux.md +35 -0
  191. package/skills-hub/system/proxy-region-locale/references/macos.md +31 -0
  192. package/skills-hub/system/proxy-region-locale/references/windows.md +45 -0
  193. package/skills-hub/system/system-health-audit/LICENSE +21 -0
  194. package/skills-hub/system/system-health-audit/SKILL.md +41 -0
  195. package/skills-hub/system/system-health-audit/agents/openai.yaml +4 -0
  196. package/skills-hub/system/system-health-audit/references/platforms.md +37 -0
  197. package/skills-hub/system/system-health-audit/scripts/system_audit.py +41 -0
  198. package/skills-hub/system/windows-dev-disk-cleanup/LICENSE +21 -0
  199. package/skills-hub/system/windows-dev-disk-cleanup/SKILL.md +40 -0
  200. package/skills-hub/system/windows-dev-disk-cleanup/agents/openai.yaml +4 -0
  201. package/skills-hub/system/windows-dev-disk-cleanup/references/windows-cleanup-workflow.md +121 -0
  202. package/skills-hub/writing/.gitkeep +0 -0
  203. package/skills-hub/writing/job-application/LICENSE +21 -0
  204. package/skills-hub/writing/job-application/SKILL.md +160 -0
  205. package/skills-hub/writing/job-application/agents/openai.yaml +4 -0
  206. package/skills-hub/writing/job-application/assets/resume.css +10 -0
  207. package/skills-hub/writing/job-application/config.example.json +9 -0
  208. package/skills-hub/writing/job-application/references/company-research.md +7 -0
  209. package/skills-hub/writing/job-application/references/corpus-schema.md +33 -0
  210. package/skills-hub/writing/job-application/references/honesty-gate.md +29 -0
  211. package/skills-hub/writing/job-application/references/improvement-plan.md +15 -0
  212. package/skills-hub/writing/job-application/references/ingest-protocol.md +18 -0
  213. package/skills-hub/writing/job-application/references/interview-speech.md +16 -0
  214. package/skills-hub/writing/job-application/references/jd-parse.md +18 -0
  215. package/skills-hub/writing/job-application/references/persist-paths.md +34 -0
  216. package/skills-hub/writing/job-application/references/question-bank.md +19 -0
  217. package/skills-hub/writing/job-application/references/rendering.md +9 -0
  218. package/skills-hub/writing/job-application/references/resume-playbook.md +30 -0
  219. package/skills-hub/writing/job-application/scripts/README.md +12 -0
  220. package/skills-hub/writing/job-application/scripts/ingest_kb.py +188 -0
  221. package/skills-hub/writing/job-application/scripts/render_resume.py +144 -0
  222. package/skills-hub/writing/job-application/scripts/validate_claims.py +52 -0
  223. package/skills-hub/writing/job-application/scripts/write_config.py +72 -0
  224. package/skills-hub/writing/job-application/templates/application-index.md +10 -0
  225. package/skills-hub/writing/job-application/templates/brief.md +16 -0
  226. package/skills-hub/writing/job-application/templates/changelog.md +6 -0
  227. package/skills-hub/writing/job-application/templates/company-research.md +15 -0
  228. package/skills-hub/writing/job-application/templates/corpus.md +11 -0
  229. package/skills-hub/writing/job-application/templates/evidence-map.md +5 -0
  230. package/skills-hub/writing/job-application/templates/framings.md +6 -0
  231. package/skills-hub/writing/job-application/templates/improvement-plan.md +16 -0
  232. package/skills-hub/writing/job-application/templates/ingest-log.md +4 -0
  233. package/skills-hub/writing/job-application/templates/known-gaps.md +4 -0
  234. package/skills-hub/writing/job-application/templates/match-report.md +21 -0
  235. package/skills-hub/writing/job-application/templates/methodology-cache.md +10 -0
  236. package/skills-hub/writing/job-application/templates/persist-index.md +11 -0
  237. package/skills-hub/writing/job-application/templates/profile.md +21 -0
  238. package/skills-hub/writing/job-application/templates/questions.md +22 -0
  239. package/skills-hub/writing/job-application/templates/resume-original.md +10 -0
  240. package/skills-hub/writing/job-application/templates/resume-tailored.md +21 -0
  241. package/skills-hub/writing/job-application/templates/sources-index.md +6 -0
  242. package/skills-hub/writing/job-application/templates/speech.md +19 -0
  243. package/skills-hub/writing/job-application/templates/stories.md +9 -0
  244. package/skills-hub/writing/job-application/templates/story-bank.md +11 -0
  245. package/skills-hub/writing/job-application/templates/strengths.md +4 -0
  246. package/skills-hub/writing/job-application/templates/style-memory.md +7 -0
  247. package/skills-hub/writing/ste-zh/LICENSE +21 -0
  248. package/skills-hub/writing/ste-zh/NOTICE.md +9 -0
  249. package/skills-hub/writing/ste-zh/SKILL.md +130 -0
  250. package/skills-hub/writing/ste-zh/agents/openai.yaml +6 -0
  251. package/skills-hub/writing/ste-zh/examples/zh-report.md +23 -0
  252. package/skills-hub/writing/ste-zh/references/english-modes.md +13 -0
  253. package/skills-hub/writing/ste-zh/references/terminology.md +13 -0
  254. package/skills-hub/writing/ste-zh/references/zh-rules.md +29 -0
  255. package/template/.speculo/refresh-contract.json +2 -0
  256. package/template/canonical/canonical-specdev-goal-plan.md +170 -101
  257. package/template/canonical/canonical-specdev-grill-with-docs.md +346 -277
  258. package/template/canonical/canonical-specdev-spec.md +346 -277
  259. package/template/canonical/canonical-specdev-tickets.md +346 -277
  260. package/template/canonical/canonical-specdev-wayfinder.md +346 -277
  261. package/template/lib/speculo-runtime.mjs +183 -8
  262. package/template/references/coordination/coordination-contract.md +12 -4
  263. package/template/references/coordination/modes/cli.md +3 -3
  264. package/template/references/coordination/modes/herdr.md +11 -11
  265. package/template/references/coordination/modes/orca.md +14 -14
  266. package/template/references/coordination/project-facts.schema.json +1 -0
  267. package/template/references/coordination/report-template.md +18 -0
  268. package/template/references/coordination/result-and-recovery.md +3 -3
  269. package/template/references/coordination/session-files.md +49 -56
  270. package/template/references/coordination/task-brief.md +3 -3
  271. package/template/references/coordination/task-template.md +25 -0
  272. package/template/workflows/specdev/common/rules/path-reference-contract.md +1 -1
  273. package/template/workflows/specdev/common/rules/workflow-state-and-lifecycle.md +1 -1
  274. package/template/workflows/specdev/common/schemas/session-locator.schema.json +15 -0
  275. package/template/workflows/specdev/common/skills/code-review/references/review-evidence.md +1 -1
  276. package/template/workflows/specdev/common/tools/README.md +6 -0
  277. package/template/workflows/specdev/common/tools/delivery-artifacts.mjs +1 -1
  278. package/template/workflows/specdev/common/tools/validate-handoff.mjs +108 -0
  279. package/template/workflows/specdev/specdev-i-implement/assets/evidence-template.md +2 -2
  280. package/template/workflows/specdev/specdev-i-implement/references/implementation-procedure.md +1 -1
  281. package/template/workflows/specdev/specdev-i-init-setup/SKILL.md +7 -6
  282. package/template/workflows/specdev/specdev-i-init-setup/references/first-setup.md +30 -1
  283. package/template/workflows/specdev/specdev-p-goal-plan/references/lead-orchestration.md +1 -1
@@ -0,0 +1,160 @@
1
+ ---
2
+ name: job-application
3
+ description: "扫描指定知识库建成经历原件,再按岗位派生投递简历(md/docx/pdf)、3–4分钟自我介绍、经历绑定的预测题与提升计划。用户说求职、改简历、投递、JD定制、自我介绍、面试题、提升计划、经历库、知识库扫盘、/job-application 时使用。不编造知识库里没有的数字、职级或技能。"
4
+ license: MIT
5
+ ---
6
+
7
+ # 岗位投递与面试准备
8
+
9
+ 经历原件是资产,每次投递是衍生品。本文件足够开工;细则按需读 `references/`。不要把用户笔记、简历正文或电话邮箱写进本技能目录。
10
+
11
+ ## 强制入口
12
+
13
+ `$SKILL_DIR` 是本 `SKILL.md` 所在文件夹(安装后常见 `~/.agents/skills/job-application`、`~/.claude/skills/job-application`,或项目里的对应目录)。运行根是当前会话的工作区,不是技能仓,也不是用户家目录。
14
+
15
+ 每次激活先解析路径,再选模式。解析顺序(高 → 低),`persist_root` 与 `kb_root` 分开取:
16
+
17
+ 1. 用户本轮明确给出的路径
18
+ 2. 已能定位的 `$persist_root/config.json`
19
+ 3. `$SKILL_DIR/config.json`
20
+ 4. 停下来问。**禁止猜测**,禁止默默写到 `$HOME` 或技能仓库根
21
+
22
+ 用户说「就用当前目录」时,`persist_root` = `<cwd>/job-application`。第一次运行必须确认 `kb_root` 和 `persist_root`,写完 JSON 再扫盘。
23
+
24
+ 确认后双写指针(只含路径和偏好,不含经历):
25
+
26
+ ```bash
27
+ python3 "$SKILL_DIR/scripts/write_config.py" \
28
+ --skill-dir "$SKILL_DIR" \
29
+ --persist-root "<abs>" \
30
+ --kb-root "<abs>" \
31
+ --locale zh \
32
+ --page-budget 2
33
+ ```
34
+
35
+ `python3` 不可用时改 `python`。脚本把路径展开成绝对路径,写入 `$SKILL_DIR/config.json` 和 `$persist_root/config.json`。前者被技能内 `.gitignore` 忽略,不要提交。
36
+
37
+ ## 模式路由
38
+
39
+ | 本轮输入 | 模式 |
40
+ |---|---|
41
+ | 只有知识库路径 | `ingest` 然后 `master`,停下来问岗位 |
42
+ | 已有 corpus,给了 JD / 岗位 | `pack` |
43
+ | 两者都有,且 manifest 里的 hash 变了 | 先 `ingest` + `master`,再 `pack` |
44
+ | 只要自我介绍,但本轮还没有 tailored | 先 `apply` 再 `pitch` |
45
+ | 点名只要题或只要提升计划 | `questions` 或 `improve`;没有 match-report 就先 `apply` |
46
+
47
+ 没有 corpus 不准 `apply`。没有 `claim_id` 的数字、职级、技术名不准进投递稿或自我介绍。
48
+
49
+ ## 产物布局
50
+
51
+ 只写在 `persist_root`。默认是 `<cwd>/job-application/`。
52
+
53
+ ```text
54
+ <persist_root>/
55
+ INDEX.md
56
+ config.json
57
+ corpus/
58
+ corpus.md profile.md evidence-map.md stories.md
59
+ strengths.md known-gaps.md framings.md style-memory.md
60
+ methodology-cache.md ingest-log.md
61
+ sources/manifest.json
62
+ sources/excerpts/
63
+ applications/YYYY-MM-DD-<company>-<role>/
64
+ INDEX.md brief.md company-research.md match-report.md
65
+ resume-original.md resume-tailored.md
66
+ resume-tailored.docx resume-tailored.pdf resume-tailored.html
67
+ changelog.md speech.md questions.md story-bank.md
68
+ improvement-plan.md
69
+ ```
70
+
71
+ 同日同公司同岗位已存在时追加 `-01`,不覆盖。知识库只读:不移动、不改写用户笔记,也不把整库复制进 `persist_root`。
72
+
73
+ ## 模式
74
+
75
+ ### ingest
76
+
77
+ 1. `kb_root` 必须是已存在的目录,否则 `blocked-input`。
78
+ 2. 跑 `scripts/ingest_kb.py --kb-root ... --out "$persist_root/corpus/sources/manifest.json"`。
79
+ 3. 先读 manifest 和 `sources/INDEX.md`,再按关键词回读少量原文。单文件文本超过约 200KB 只摘头尾,摘录放 `sources/excerpts/`。禁止把整个知识库灌进上下文。
80
+
81
+ ### master
82
+
83
+ 从 manifest 选源,按 [templates/](templates/) 写出 `corpus.md`、`profile.md`(19 节标题必须齐全)、`evidence-map.md`、`stories.md`、`known-gaps.md`、`framings.md`。成就库每条有 `C-xxx`。同一事实两个数字时写入缺口并问用户一次,不取较大的那个。用户明确要求时才上网刷新 `methodology-cache.md`;网搜结果不得变成个人成就。冲突以源文件和 evidence-map 为准,不以写得更顺的句子为准。
84
+
85
+ ### apply
86
+
87
+ 冻结 JD 到 `brief.md`。先写 `resume-original.md`(本轮选用的原件切片),再写 `resume-tailored.md`。每条子弹行尾加 `<!-- claim:C-012 -->`。`changelog.md` 写原句、新句、理由、claim_id。`match-report.md` 四表:已覆盖、翻译后覆盖、诚实缺口、明确不写入。然后:
88
+
89
+ ```bash
90
+ python3 "$SKILL_DIR/scripts/render_resume.py" \
91
+ --md "$APP/resume-tailored.md" \
92
+ --css "$SKILL_DIR/assets/resume.css" \
93
+ --out-dir "$APP"
94
+ python3 "$SKILL_DIR/scripts/validate_claims.py" \
95
+ --evidence "$persist_root/corpus/evidence-map.md" \
96
+ --files "$APP/resume-tailored.md"
97
+ ```
98
+
99
+ 渲染缺依赖时 HTML/md 仍算内容完成,在回复里写降级,不要编一版「看起来像 PDF」的假文件。
100
+
101
+ ### pitch
102
+
103
+ 读本轮 tailored、brief、story-bank,不按公司文化凭空写通用稿。`speech.md` 含 180–240 秒正本、60–90 秒短版、被打断时的接法、数字对照表、不要讲的内容。数字必须和投递稿同一 claim。
104
+
105
+ ### questions
106
+
107
+ 题从四条交叉来:JD 必须项、本轮每条 bullet、被压缩但库里有的项目、诚实缺口。每题绑定 `story-id`,或明确写「无法作答」。缺口题只给诚实口径,不编故事。
108
+
109
+ ### improve
110
+
111
+ A 呈现层:本周和 7 天内能改的口径、要补的证据。B 能力层:30/60/90 天可验证出口。禁止建议伪造证书、改在职时间、把他人成果写成独立完成。
112
+
113
+ ### pack
114
+
115
+ 顺序固定:`research`(写入 `company-research.md`)→ `apply` → 渲染 → `pitch` → `questions` → `improve` → `validate_claims.py`。中途失败停在当前步,不删已通过的上游文件。只有岗位名、没有 JD 原文时,可以有限检索补 JD,并在 brief 里标明「非官方原文」。
116
+
117
+ ## 硬规则
118
+
119
+ 1. 指针只写两份 `config.json`。简历、语料、PDF 只写 `persist_root`。
120
+ 2. 无 `claim_id` 不得出口数字、职级、技术名。缺数字就定性或标 `needs_proof`。
121
+ 3. 四层语言:事实 / 估计 / 解释 / 呈现选择。投递稿只用事实和已标记的估计。
122
+ 4. 翻译不是造假。把「写过内部工具」说成「交付过平台」需要语料里真有平台级范围。
123
+ 5. 背调红线不可改:学历、在职时间、公司名、正式职级、论文署名、开源仓库所有权。
124
+ 6. JD 有、库无 → 缺口表,不进技能栏。
125
+ 7. 新事实可以回写 corpus,但必须新增 source 和 claim,并在 changelog 说明。不得在 tailor 时偷偷改原件数字。
126
+ 8. 公司新闻不是用户的个人成就。
127
+ 9. 不自动调用本仓库其它 skill。不把 `config.json` 或用户笔记提交进 git。
128
+
129
+ 完整口径见 [references/honesty-gate.md](references/honesty-gate.md)。简历句式、ATS、中文页数见 [references/resume-playbook.md](references/resume-playbook.md)。口播结构见 [references/interview-speech.md](references/interview-speech.md)。
130
+
131
+ ## 回复格式
132
+
133
+ 每次返回:
134
+
135
+ - 模式
136
+ - `persist_root` 与 `kb_root`(绝对路径)
137
+ - 已写文件
138
+ - 跑过的脚本和退出码
139
+ - 未关闭的 `needs_proof`
140
+ - 下一步:继续本技能的哪个模式,或结束
141
+
142
+ 只有 `pack` 完成门全过才能说这套投递包做完了。只跑 `pitch` 时,完成只表示自我介绍写完。
143
+
144
+ ## 资源
145
+
146
+ | 文件 | 何时读 |
147
+ |---|---|
148
+ | [references/persist-paths.md](references/persist-paths.md) | 路径、JSON 字段、第一次激活 |
149
+ | [references/honesty-gate.md](references/honesty-gate.md) | 写任何对外句子之前 |
150
+ | [references/ingest-protocol.md](references/ingest-protocol.md) | ingest |
151
+ | [references/corpus-schema.md](references/corpus-schema.md) | master / profile 19 节 |
152
+ | [references/resume-playbook.md](references/resume-playbook.md) | apply |
153
+ | [references/jd-parse.md](references/jd-parse.md) | 拆 JD |
154
+ | [references/interview-speech.md](references/interview-speech.md) | pitch |
155
+ | [references/question-bank.md](references/question-bank.md) | questions |
156
+ | [references/improvement-plan.md](references/improvement-plan.md) | improve |
157
+ | [references/rendering.md](references/rendering.md) | 渲染降级 |
158
+ | [references/company-research.md](references/company-research.md) | pack 里的公司调研 |
159
+ | [scripts/](scripts/) | 扫盘、写指针、渲染、校验主张 |
160
+ | [templates/](templates/) | 每个产物的标题骨架 |
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Job application"
3
+ short_description: "从知识库生成经历原件,再按岗位派生简历、自我介绍、面试题和提升计划"
4
+ default_prompt: "Use $job-application to scan my knowledge base into a career corpus, then tailor a resume, 3-4 minute pitch, interview questions, and an improvement plan for a specific job. Do not invent metrics."
@@ -0,0 +1,10 @@
1
+ @page { size: A4; margin: 14mm; }
2
+ html, body { margin: 0; padding: 0; background: #fff; color: #111; }
3
+ body { font-family: "Segoe UI", "PingFang SC", "Noto Sans CJK SC", "Source Han Sans SC", sans-serif; font-size: 11pt; line-height: 1.35; }
4
+ main.sheet { max-width: 180mm; margin: 0 auto; }
5
+ h1 { font-size: 18pt; margin: 0 0 4pt; font-weight: 650; }
6
+ h2 { font-size: 12pt; margin: 12pt 0 4pt; border-bottom: 0.4pt solid #222; padding-bottom: 2pt; }
7
+ h3 { font-size: 11pt; margin: 8pt 0 2pt; }
8
+ p, li { margin: 0 0 3pt; }
9
+ ul { margin: 0 0 6pt 1.1em; padding: 0; }
10
+ a { color: inherit; text-decoration: none; }
@@ -0,0 +1,9 @@
1
+ {
2
+ "schema_version": 1,
3
+ "skill": "job-application",
4
+ "persist_root": "/absolute/path/to/job-application",
5
+ "kb_root": "/absolute/path/to/knowledge-base",
6
+ "locale": "zh",
7
+ "page_budget": 2,
8
+ "updated_at": "2026-09-21T00:00:00.000Z"
9
+ }
@@ -0,0 +1,7 @@
1
+ # 公司调研
2
+
3
+ `company-research.md` 只记录公开事实:产品、团队公开岗位、近期发布、和 JD 直接相关的技术栈。每条带来源 URL 和日期。
4
+
5
+ 这些事实可以用于自我介绍的「为何此司」,不能写进用户的经历子弹。
6
+
7
+ 不确定的市场传闻标「未核实」,不进口播稿。
@@ -0,0 +1,33 @@
1
+ # 原件
2
+
3
+ `corpus.md` 是长文。`profile.md` 是给 tailor 用的稳定索引。两者冲突时,以 `evidence-map.md` 和源文件为准。
4
+
5
+ ## profile 19 节
6
+
7
+ 空节保留标题,不要删号。
8
+
9
+ 1. 身份
10
+ 2. 头条与目标岗位
11
+ 3. 摘要候选
12
+ 4. 经历快照
13
+ 5. 经历深挖
14
+ 6. 教育
15
+ 7. 证书与考试
16
+ 8. 技术技能(只收语料里出现过的)
17
+ 9. 领域经验
18
+ 10. 带人与协作
19
+ 11. 公开产物
20
+ 12. 语言
21
+ 13. 奖项
22
+ 14. 志愿与社团
23
+ 15. 兴趣(默认不进投递稿)
24
+ 16. 到岗与工作许可(敏感,只在 framings 批准后使用)
25
+ 17. 成就库(每条 `C-xxx`)
26
+ 18. 已知缺口
27
+ 19. 预批准表述
28
+
29
+ ## evidence-map
30
+
31
+ 表格列:`claim_id`、陈述、源 `src-id`、摘录、层级(事实/估计)。
32
+
33
+ 成就库里的每一条都必须在这张表出现。没有行,就不能被投递稿引用。
@@ -0,0 +1,29 @@
1
+ # 诚实门
2
+
3
+ 这是导出硬门,不是写作风格建议。
4
+
5
+ ## 主张
6
+
7
+ - 每条可对外使用的数字、职级、时间、技术名都要有 `C-xxx`。
8
+ - 投递稿用 HTML 注释:`<!-- claim:C-012 -->`。
9
+ - `validate_claims.py` 对不上 evidence-map 时,不得把该文件当成品交付。
10
+ - 找不到数字就写定性描述,或标 `needs_proof` 并向用户要来源。不要编一个看起来合理的百分比。
11
+
12
+ ## 四层
13
+
14
+ | 层 | 含义 | 能否进投递稿 |
15
+ |---|---|---|
16
+ | 事实 | 知识库或用户确认的原句 | 可以 |
17
+ | 估计 | 用户标过「约 / 量级」 | 可以,必须保留「约」 |
18
+ | 解释 | 你对动机、能力的归纳 | 只能进自我介绍,不能改写成事实 |
19
+ | 呈现选择 | 详略、顺序、用哪个同义词 | 可以,但不得升级范围 |
20
+
21
+ ## 红线
22
+
23
+ 不可改:学历、在职起止、公司法定名、正式职级、论文署名、仓库所有权。
24
+
25
+ JD 里有、语料里没有的技能,只出现在 match-report 的缺口表。
26
+
27
+ 翻译是换角度讲真事。没有平台级证据,就不要写成平台。
28
+
29
+ 提升计划里的未来完成时,不得写进「过去已经做到」。
@@ -0,0 +1,15 @@
1
+ # 提升计划
2
+
3
+ 两栏,不要第三栏。
4
+
5
+ ## A. 呈现
6
+
7
+ 本周就能改的口径:顺序、动词、把项目翻译成 JD 的词。7 天内可补的证据:找回数字、补公开说明、向当事人核对范围。这些可以进下一版投递稿,但补到之前仍标 `needs_proof`。
8
+
9
+ ## B. 能力
10
+
11
+ 30 / 60 / 90 天。每项有一个可验证出口:一个小项目、一篇笔记、一次能演示的结果。未做完之前不写进简历。
12
+
13
+ ## 不要做
14
+
15
+ 买假证、改在职时间、把协作成果写成独立完成、用未来计划冒充过去业绩。
@@ -0,0 +1,18 @@
1
+ # 扫盘
2
+
3
+ `ingest_kb.py` 递归读取 `kb_root`,不改源文件,不访问网络。
4
+
5
+ 跳过目录名以 `.` 开头的路径(含 `.git`、`.venv`、`.obsidian`),以及 `node_modules`、`__pycache__`、`dist`、`build`、`.idea`、`.vscode`。跳过 `.DS_Store`。不读隐藏目录里的文件。
6
+
7
+ `sources/manifest.json` 每条:
8
+
9
+ - `id`:首次按路径排序从 `src-0001` 编号。再次扫描时同一 `relpath` 保留原 `id`,新文件取尚未使用的下一个号
10
+ - `relpath` 是稳定键。编号会因插入新文件而不再等于「当前排序第几」,主张要绑 `relpath` 或当次 `id`,不要凭记忆里的旧序号
11
+ - `relpath`、`sha256`、`mtime`、`bytes`
12
+ - `kind`:`text` 或 `binary`
13
+ - `status`:`indexed`、`truncated`(大于 256KB)、`skipped-binary`
14
+ - `summary`:第一段非标题正文,最多约 180 字
15
+
16
+ hash 未变时保留旧 summary。二进制只记账,不解析。v1 不做 OCR。
17
+
18
+ Agent 读完 manifest,按 [templates/sources-index.md](../templates/sources-index.md) 写 `sources/INDEX.md`,再按 `id` 回读少量原文。不要把清单外的整文件贴进上下文。超过约 200KB 的文本只摘头尾到 `sources/excerpts/`,摘录文件名用 `src-0001.md`。扫盘摘要写 `ingest-log.md`。
@@ -0,0 +1,16 @@
1
+ # 自我介绍
2
+
3
+ 正本 180–240 秒。短版 60–90 秒,只留一个 STAR。
4
+
5
+ | 时间 | 内容 |
6
+ |---|---|
7
+ | 0:00–0:20 | 姓名、当前身份、一句话标签(年限 / 领域 / 一个可核对成果) |
8
+ | 0:20–2:40 | 两段与本岗和本轮投递稿相同项目的 STAR |
9
+ | 2:40–3:20 | 为何是这家、此刻能上手的一件事。只用公司公开事实加自己的 claim |
10
+ | 3:20–3:40 | 收束,留一个可追问的钩子 |
11
+
12
+ 稿是重点顺序加关键数字,不是背诵台词。`speech.md` 要写「被打断时从哪一段接」。
13
+
14
+ 禁止:复读简历、从爱好开场、发明数字、把提升计划里的「还不会」说成「已经精通」。
15
+
16
+ 每个数字旁写对应的 `claim_id`,并在文末做对照表。
@@ -0,0 +1,18 @@
1
+ # 拆 JD
2
+
3
+ `brief.md` 冻结原文。拆成三列:
4
+
5
+ - 硬门槛:年限、学历、语言、工作许可、必须到岗的城市
6
+ - 核心:反复出现的职责和技能
7
+ - 加分:出现一次的工具或行业
8
+
9
+ 只有岗位名、没有 JD 时,可以检索公开招聘页补一份,并在 brief 顶部写「非官方原文」和 URL。检索不到就停,让用户粘贴,不要用通用岗位描述冒充这家公司的 JD。
10
+
11
+ 匹配表用四格,不要只用一个百分比:
12
+
13
+ | 格 | 含义 |
14
+ |---|---|
15
+ | 已覆盖 | 语料里有直接证据 |
16
+ | 翻译后覆盖 | 真事换了岗位用词,claim 仍在 |
17
+ | 诚实缺口 | JD 有、库无 |
18
+ | 不写入 | 真实但和本岗无关,或用户标记不公开 |
@@ -0,0 +1,34 @@
1
+ # 路径与 config.json
2
+
3
+ `$SKILL_DIR` 是含 `SKILL.md` 的目录。`persist_root` 是产物根。`kb_root` 是用户知识库,只读。
4
+
5
+ ## 解析
6
+
7
+ 1. 本轮用户给出的路径优先。
8
+ 2. 其次读已存在的 `$persist_root/config.json`。
9
+ 3. 再读 `$SKILL_DIR/config.json`。
10
+ 4. 都没有就问。不要猜。
11
+
12
+ 「就用当前目录」= `<cwd>/job-application`。相对路径先展开成绝对路径再写入。
13
+
14
+ ## JSON
15
+
16
+ 两份文件字段相同。技能目录那份是指针,产物根那份是自描述。重装技能后,若用户还指向旧产物根,可从产物根把 JSON 抄回技能目录。
17
+
18
+ ```json
19
+ {
20
+ "schema_version": 1,
21
+ "skill": "job-application",
22
+ "persist_root": "/abs/job-application",
23
+ "kb_root": "/abs/notes",
24
+ "locale": "zh",
25
+ "page_budget": 2,
26
+ "updated_at": "2026-09-21T00:00:00.000Z"
27
+ }
28
+ ```
29
+
30
+ 禁止写入 token、简历正文、电话、邮箱、成就数字。
31
+
32
+ 改路径只重写 JSON,不自动搬家。用户要求搬家时,复制 `corpus/` 与 `applications/` 后再改指针。
33
+
34
+ `persist_root` 不得落在 `$SKILL_DIR` 里面。`write_config.py` 会拒绝。
@@ -0,0 +1,19 @@
1
+ # 预测题
2
+
3
+ 不要从网上抄一份通用 50 题。交叉这四类:
4
+
5
+ 1. JD 硬门槛和核心项
6
+ 2. 本轮投递稿的每一条 bullet
7
+ 3. 语料里与岗位相关、但本轮被压缩掉的项目
8
+ 4. 诚实缺口
9
+
10
+ 每题记录:
11
+
12
+ - 题干
13
+ - 为什么会被问(JD 原句或 bullet)
14
+ - `story-id`,或「无法作答」
15
+ - 30 秒口径和 2 分钟口径
16
+ - 两到三个追问
17
+ - 不会时的诚实降级
18
+
19
+ 缺口题不得带具体业绩。追问只挖投递稿和语料里已经有的决策、范围、失败和权衡。
@@ -0,0 +1,9 @@
1
+ # 渲染
2
+
3
+ `render_resume.py` 始终写 `resume-tailored.html` 和 `render-status.json`。
4
+
5
+ - 装了 `python-docx` 才写 docx
6
+ - 装了 `weasyprint` 才写可选中文字的 PDF
7
+ - 两者都没有时退出码 3。HTML 仍可用浏览器打印
8
+
9
+ 不要用截图冒充 PDF。CSS 是单栏、无图标、无表格。联系方式必须在 Markdown 正文里,不要放进 CSS 页眉。
@@ -0,0 +1,30 @@
1
+ # 投递稿
2
+
3
+ ## 句式
4
+
5
+ 简历子弹用 XYZ,不要把 STAR 整段塞进一行。
6
+
7
+ > 做成了 X,用 Y 衡量,靠 Z。
8
+
9
+ 例:把月结从 12 天收到 5 天,靠在 SAP 里自动做公司间对账。`<!-- claim:C-014 -->`
10
+
11
+ 自我介绍和面试答纲再用 STAR,压成两三句。
12
+
13
+ 量化只从语料里已有的六类里取:速度、规模、可靠性、业务、团队与过程、范围。没有数就不要造。
14
+
15
+ ## ATS
16
+
17
+ - 单栏。标准标题:经历、项目、技能、教育。
18
+ - 不用表格、文本框、图标、多栏、页眉页脚里的联系方式。
19
+ - 联系方式在正文顶部。
20
+ - PDF 必须是可选中的文字。渲染失败就交 HTML,不要交整页截图。
21
+ - 关键词放三层:标题或摘要、技能分组、带工具和结果的子弹。
22
+ - 缩写和全称成对出现一次。
23
+ - JD 高频词取 3–5 个核,分别落在标题、摘要、子弹。不堆砌。
24
+ - 不把 JD 有而库无的词写进技能栏。
25
+
26
+ ## 中文页数
27
+
28
+ `page_budget` 默认 2。校招或实习可收成 1。超过预算时在 match-report 解释,而不是把字号压到不可读。
29
+
30
+ 互联网岗默认无照片、无政治面貌。JD 明确要求时才加。自我评价可省略;写了必须带 claim。
@@ -0,0 +1,12 @@
1
+ # scripts
2
+
3
+ 只依赖 Python 3 标准库,外加可选的 `python-docx` 与 `weasyprint`。缺可选库时简历仍会写出 HTML,进程以退出码 3 表示二进制降级,内容不算失败。
4
+
5
+ ```bash
6
+ python3 scripts/write_config.py --skill-dir "$SKILL_DIR" --persist-root ./job-application --kb-root /path/to/notes
7
+ python3 scripts/ingest_kb.py --kb-root /path/to/notes --out ./job-application/corpus/sources/manifest.json
8
+ python3 scripts/render_resume.py --md ./app/resume-tailored.md --css assets/resume.css --out-dir ./app
9
+ python3 scripts/validate_claims.py --evidence ./job-application/corpus/evidence-map.md --files ./app/resume-tailored.md
10
+ ```
11
+
12
+ 不要把真实 `config.json`、知识库或生成的 PDF 提交进本仓库。
@@ -0,0 +1,188 @@
1
+ #!/usr/bin/env python3
2
+ """Scan a knowledge-base directory into sources/manifest.json. Read-only on sources."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import hashlib
8
+ import json
9
+ import sys
10
+ from datetime import datetime, timezone
11
+ from pathlib import Path
12
+
13
+ SKIP_DIRS = {
14
+ ".git",
15
+ ".hg",
16
+ ".svn",
17
+ "node_modules",
18
+ "__pycache__",
19
+ ".venv",
20
+ "venv",
21
+ "dist",
22
+ "build",
23
+ ".next",
24
+ ".idea",
25
+ ".vscode",
26
+ }
27
+ SKIP_FILES = {".DS_Store", "Thumbs.db"}
28
+ TEXT_SUFFIXES = {
29
+ ".md",
30
+ ".txt",
31
+ ".html",
32
+ ".htm",
33
+ ".json",
34
+ ".yml",
35
+ ".yaml",
36
+ ".rst",
37
+ ".csv",
38
+ ".tsv",
39
+ ".py",
40
+ ".js",
41
+ ".mjs",
42
+ ".ts",
43
+ ".tsx",
44
+ ".jsx",
45
+ ".java",
46
+ ".go",
47
+ ".rs",
48
+ ".css",
49
+ ".xml",
50
+ ".toml",
51
+ }
52
+ MAX_READ = 256 * 1024
53
+ SUMMARY_CHARS = 180
54
+
55
+
56
+ def summary_of(text: str) -> str:
57
+ chunk = []
58
+ for line in text.splitlines():
59
+ stripped = line.strip()
60
+ if not stripped or stripped.startswith("#"):
61
+ if chunk:
62
+ break
63
+ continue
64
+ chunk.append(stripped)
65
+ if sum(len(part) for part in chunk) >= SUMMARY_CHARS:
66
+ break
67
+ blob = " ".join(chunk).strip()
68
+ if len(blob) > SUMMARY_CHARS:
69
+ blob = blob[: SUMMARY_CHARS - 1].rstrip() + "…"
70
+ return blob
71
+
72
+
73
+ def file_id(previous: dict, rel: str, used: set[str]) -> str:
74
+ prior = previous.get(rel) or {}
75
+ existing = prior.get("id")
76
+ if isinstance(existing, str) and existing.startswith("src-"):
77
+ return existing
78
+ number = 1
79
+ while True:
80
+ candidate = f"src-{number:04d}"
81
+ if candidate not in used:
82
+ used.add(candidate)
83
+ return candidate
84
+ number += 1
85
+
86
+
87
+ def sha256_and_size(path: Path) -> tuple[str, int]:
88
+ digest = hashlib.sha256()
89
+ size = 0
90
+ with path.open("rb") as handle:
91
+ while True:
92
+ chunk = handle.read(1024 * 1024)
93
+ if not chunk:
94
+ break
95
+ size += len(chunk)
96
+ digest.update(chunk)
97
+ return digest.hexdigest(), size
98
+
99
+
100
+ def main() -> None:
101
+ parser = argparse.ArgumentParser(description=__doc__)
102
+ parser.add_argument("--kb-root", required=True)
103
+ parser.add_argument("--out", required=True)
104
+ args = parser.parse_args()
105
+
106
+ root = Path(args.kb_root).expanduser().resolve()
107
+ if not root.is_dir():
108
+ print(f"kb-root is not a directory: {root}", file=sys.stderr)
109
+ raise SystemExit(2)
110
+ out = Path(args.out).expanduser().resolve()
111
+ previous: dict[str, dict] = {}
112
+ if out.is_file():
113
+ try:
114
+ old = json.loads(out.read_text(encoding="utf-8"))
115
+ for item in old.get("files", []):
116
+ rel = item.get("relpath")
117
+ if rel:
118
+ previous[rel] = item
119
+ except (OSError, json.JSONDecodeError):
120
+ previous = {}
121
+
122
+ files = []
123
+ used_ids: set[str] = set()
124
+ for item in previous.values():
125
+ existing = item.get("id")
126
+ if isinstance(existing, str) and existing.startswith("src-"):
127
+ used_ids.add(existing)
128
+ for path in sorted(root.rglob("*")):
129
+ if not path.is_file():
130
+ continue
131
+ parts = path.relative_to(root).parts
132
+ if any(part in SKIP_DIRS or part.startswith(".") for part in parts):
133
+ continue
134
+ if path.name in SKIP_FILES:
135
+ continue
136
+ rel = path.relative_to(root).as_posix()
137
+ digest, size = sha256_and_size(path)
138
+ mtime = datetime.fromtimestamp(path.stat().st_mtime, timezone.utc).strftime(
139
+ "%Y-%m-%dT%H:%M:%S.000Z"
140
+ )
141
+ kind = "text" if path.suffix.lower() in TEXT_SUFFIXES else "binary"
142
+ status = "indexed"
143
+ file_summary = ""
144
+ if kind == "binary":
145
+ status = "skipped-binary"
146
+ elif size > MAX_READ:
147
+ status = "truncated"
148
+ with path.open("rb") as handle:
149
+ file_summary = summary_of(handle.read(8192).decode("utf-8", errors="replace"))
150
+ else:
151
+ text = path.read_text(encoding="utf-8", errors="replace")
152
+ if "\x00" in text:
153
+ kind = "binary"
154
+ status = "skipped-binary"
155
+ else:
156
+ file_summary = summary_of(text)
157
+ prior = previous.get(rel)
158
+ if prior and prior.get("sha256") == digest and prior.get("summary"):
159
+ file_summary = prior["summary"]
160
+ if status == "indexed":
161
+ status = prior.get("status", status)
162
+ files.append(
163
+ {
164
+ "id": file_id(previous, rel, used_ids),
165
+ "relpath": rel,
166
+ "sha256": digest,
167
+ "mtime": mtime,
168
+ "bytes": size,
169
+ "kind": kind,
170
+ "summary": file_summary,
171
+ "status": status,
172
+ }
173
+ )
174
+
175
+ out.parent.mkdir(parents=True, exist_ok=True)
176
+ payload = {
177
+ "schema_version": 1,
178
+ "kb_root": str(root),
179
+ "scanned_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.000Z"),
180
+ "file_count": len(files),
181
+ "files": files,
182
+ }
183
+ out.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
184
+ print(f"{out} files={len(files)}")
185
+
186
+
187
+ if __name__ == "__main__":
188
+ main()