hirify-cli 0.6.1 → 0.6.2

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.
@@ -204,6 +204,14 @@ function detailRows(pairs) {
204
204
  .map(([label, text]) => `${(label + ':').padEnd(10)}${text}`)
205
205
  }
206
206
 
207
+ /**
208
+ * The word that names a vacancy, offered under both names a manifest may use for the path
209
+ * slot. Hirify moved vacancies.read and vacancies.reveal from `{slug}` to `{vacancy_id}` on
210
+ * 2026-09-30 and reads a non-numeric value in that slot as the slug, so one set of params
211
+ * serves the old manifest, the new one, a slug and a numeric id alike.
212
+ */
213
+ const vacancyRef = (word) => ({ slug: word, vacancy_id: word })
214
+
207
215
  /**
208
216
  * One vacancy in full, with the text a person reads on the site. This is the command an
209
217
  * agent shortlists with, so it is deliberately the cheap one: it counts against the day's
@@ -218,7 +226,7 @@ async function cmdVacancyRead(args, words) {
218
226
  '\n Slugs come from hirify vacancy search or hirify feed show.')
219
227
  }
220
228
 
221
- const res = await callCapability('vacancies.read', { params: { slug }, allow: [200, 404] })
229
+ const res = await callCapability('vacancies.read', { params: vacancyRef(slug), allow: [200, 404] })
222
230
  if (res.status === 404) die('there is no vacancy with that slug.')
223
231
 
224
232
  const d = res.body?.data ?? {}
@@ -276,7 +284,7 @@ function contactLine(c) {
276
284
  async function cmdVacancyReveal(args, words) {
277
285
  const [slug] = words
278
286
  if (!slug) die('a vacancy slug is required: hirify vacancy reveal <slug>')
279
- const body = await callCapability('vacancies.reveal', { params: { slug } })
287
+ const body = await callCapability('vacancies.reveal', { params: vacancyRef(slug) })
280
288
  const d = body?.data ?? {}
281
289
  out(body, () => {
282
290
  console.log(`company: ${d.company ?? '-'}`)
package/bin/lib/setup.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { existsSync, mkdirSync, cpSync, rmSync, symlinkSync, realpathSync, readFileSync } from 'node:fs'
2
2
  import { homedir } from 'node:os'
3
- import { join, relative } from 'node:path'
3
+ import { dirname, join, relative } from 'node:path'
4
4
  import semver from 'semver'
5
5
  import { CliError } from './errors.js'
6
6
  import { PACKAGE_NAME, runProcess } from './update.js'
@@ -31,12 +31,19 @@ const remove = path => rmSync(path, { recursive: true, force: true })
31
31
  // OS messages may carry private paths, so only the code is reported.
32
32
  const reason = error => ['EACCES', 'EPERM', 'EROFS', 'ENOSPC', 'EDQUOT', 'ENOTDIR', 'ENOENT', 'EEXIST', 'ELOOP'].includes(error?.code) ? error.code : 'unknown'
33
33
 
34
+ // A junction needs no elevated rights on Windows; elsewhere the link stays relative.
35
+ const linkSkill = (path, target, platform) => (platform === 'win32'
36
+ ? symlinkSync(realpathSync(path), target, 'junction')
37
+ : symlinkSync(relative(dirname(target), realpathSync(path)), target, 'dir'))
38
+
34
39
  /**
35
40
  * Install the skill carried by this package: one shared copy under `~/.agents/skills`, linked into
36
41
  * every agent found here. The skill comes from the package of the CLI it is for, so the two match.
37
- * An agent that cannot be written to is reported and does not stop the others.
42
+ * An agent that cannot be written to is reported and does not stop the others. An agent that
43
+ * cannot take a link gets a copy, and the result says so: a copy does not follow the shared one
44
+ * when the CLI updates, so the person knows to run `hirify skill` again.
38
45
  */
39
- export function installSkill({ packageRoot, env = process.env, home = homedir(), platform = process.platform } = {}) {
46
+ export function installSkill({ packageRoot, env = process.env, home = homedir(), platform = process.platform, link = linkSkill } = {}) {
40
47
  const source = join(packageRoot, 'skills', SKILL_NAME)
41
48
  if (!existsSync(join(source, 'SKILL.md'))) throw new CliError('skill_missing', 'This installation does not carry the skill. Install it with: npx skills add hirifyme/hirify-cli')
42
49
  const shared = join(home, '.agents', 'skills')
@@ -56,12 +63,9 @@ export function installSkill({ packageRoot, env = process.env, home = homedir(),
56
63
  if (parent === realpathSync(shared)) { agents.push({ agent: agent.name, installed: true }); continue }
57
64
  const target = join(parent, SKILL_NAME)
58
65
  remove(target)
59
- try {
60
- // A junction needs no elevated rights on Windows; elsewhere the link stays relative.
61
- if (platform === 'win32') symlinkSync(realpathSync(path), target, 'junction')
62
- else symlinkSync(relative(parent, realpathSync(path)), target, 'dir')
63
- } catch { cpSync(source, target, { recursive: true }) }
64
- agents.push({ agent: agent.name, installed: true })
66
+ let copied = false
67
+ try { link(path, target, platform) } catch { cpSync(source, target, { recursive: true }); copied = true }
68
+ agents.push(copied ? { agent: agent.name, installed: true, copied: true } : { agent: agent.name, installed: true })
65
69
  } catch (error) { agents.push({ agent: agent.name, installed: false, reason: reason(error) }) }
66
70
  }
67
71
  return { skill: SKILL_NAME, path, agents }
@@ -104,5 +108,7 @@ export function describeSkill(result) {
104
108
  const failed = result.agents.filter(item => !item.installed).map(item => `${item.agent} (${item.reason})`)
105
109
  const lines = [done.length ? `The skill is installed for ${done.join(', ')}.` : `The skill is saved in ${result.path}. No supported agent was found on this computer.`]
106
110
  if (failed.length) lines.push(`It could not be installed for ${failed.join(', ')}. Check that the agent's skills directory is a folder you can write to, then run hirify skill.`)
111
+ const copies = result.agents.filter(item => item.copied).map(item => item.agent)
112
+ if (copies.length) lines.push(`For ${copies.join(', ')} the skill is a copy, not a link: after the CLI updates, run hirify skill to refresh it.`)
107
113
  return lines
108
114
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "hirify-cli",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "hirify-cli",
9
- "version": "0.6.1",
9
+ "version": "0.6.2",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "cross-spawn": "7.0.6",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hirify-cli",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "Hirify CLI for AI agents: browser sign-in, job feeds, search, reading a vacancy in full, contacts to apply to, and applying on Hirify.",
5
5
  "bin": {
6
6
  "hirify": "bin/hirify.js"