vskill 1.0.16 → 1.0.19

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 (225) hide show
  1. package/README.md +27 -3
  2. package/agents.json +3 -1
  3. package/dist/agents/agents-registry.d.ts +61 -0
  4. package/dist/agents/agents-registry.js +203 -0
  5. package/dist/agents/agents-registry.js.map +1 -1
  6. package/dist/api/client.d.ts +85 -0
  7. package/dist/api/client.js +193 -24
  8. package/dist/api/client.js.map +1 -1
  9. package/dist/bin.js +0 -0
  10. package/dist/commands/add.d.ts +7 -0
  11. package/dist/commands/add.js +94 -1
  12. package/dist/commands/add.js.map +1 -1
  13. package/dist/commands/auth.d.ts +23 -0
  14. package/dist/commands/auth.js +136 -12
  15. package/dist/commands/auth.js.map +1 -1
  16. package/dist/commands/eval/serve.d.ts +2 -0
  17. package/dist/commands/eval/serve.js +126 -4
  18. package/dist/commands/eval/serve.js.map +1 -1
  19. package/dist/commands/orgs.d.ts +21 -0
  20. package/dist/commands/orgs.js +164 -0
  21. package/dist/commands/orgs.js.map +1 -0
  22. package/dist/commands/skill.js +14 -1
  23. package/dist/commands/skill.js.map +1 -1
  24. package/dist/commands/whoami.d.ts +29 -0
  25. package/dist/commands/whoami.js +119 -0
  26. package/dist/commands/whoami.js.map +1 -0
  27. package/dist/eval/anthropic-catalog.js +32 -2
  28. package/dist/eval/anthropic-catalog.js.map +1 -1
  29. package/dist/eval/batch-judge.js +1 -0
  30. package/dist/eval/batch-judge.js.map +1 -1
  31. package/dist/eval/llm.d.ts +1 -1
  32. package/dist/eval/llm.js +104 -2
  33. package/dist/eval/llm.js.map +1 -1
  34. package/dist/eval-server/__tests__/helpers/studio-token-test-helpers.d.ts +2 -0
  35. package/dist/eval-server/__tests__/helpers/studio-token-test-helpers.js +20 -0
  36. package/dist/eval-server/__tests__/helpers/studio-token-test-helpers.js.map +1 -0
  37. package/dist/eval-server/active-root-store.d.ts +19 -0
  38. package/dist/eval-server/active-root-store.js +50 -0
  39. package/dist/eval-server/active-root-store.js.map +1 -0
  40. package/dist/eval-server/active-tenant-routes.d.ts +15 -0
  41. package/dist/eval-server/active-tenant-routes.js +101 -0
  42. package/dist/eval-server/active-tenant-routes.js.map +1 -0
  43. package/dist/eval-server/api-routes.d.ts +1 -1
  44. package/dist/eval-server/api-routes.js +60 -7
  45. package/dist/eval-server/api-routes.js.map +1 -1
  46. package/dist/eval-server/authoring-routes.d.ts +1 -1
  47. package/dist/eval-server/authoring-routes.js +9 -7
  48. package/dist/eval-server/authoring-routes.js.map +1 -1
  49. package/dist/eval-server/desktop-open-routes.d.ts +8 -0
  50. package/dist/eval-server/desktop-open-routes.js +64 -0
  51. package/dist/eval-server/desktop-open-routes.js.map +1 -0
  52. package/dist/eval-server/detect-engines-route.d.ts +1 -1
  53. package/dist/eval-server/detect-engines-route.js +3 -1
  54. package/dist/eval-server/detect-engines-route.js.map +1 -1
  55. package/dist/eval-server/eval-server.js +108 -29
  56. package/dist/eval-server/eval-server.js.map +1 -1
  57. package/dist/eval-server/export-skill-routes.d.ts +9 -0
  58. package/dist/eval-server/export-skill-routes.js +81 -0
  59. package/dist/eval-server/export-skill-routes.js.map +1 -0
  60. package/dist/eval-server/git-routes.d.ts +7 -6
  61. package/dist/eval-server/git-routes.js +123 -15
  62. package/dist/eval-server/git-routes.js.map +1 -1
  63. package/dist/eval-server/improve-routes.d.ts +1 -1
  64. package/dist/eval-server/improve-routes.js +4 -1
  65. package/dist/eval-server/improve-routes.js.map +1 -1
  66. package/dist/eval-server/install-engine-routes.d.ts +4 -17
  67. package/dist/eval-server/install-engine-routes.js +10 -125
  68. package/dist/eval-server/install-engine-routes.js.map +1 -1
  69. package/dist/eval-server/install-jobs.d.ts +41 -0
  70. package/dist/eval-server/install-jobs.js +161 -0
  71. package/dist/eval-server/install-jobs.js.map +1 -0
  72. package/dist/eval-server/install-skill-routes.d.ts +74 -11
  73. package/dist/eval-server/install-skill-routes.js +508 -79
  74. package/dist/eval-server/install-skill-routes.js.map +1 -1
  75. package/dist/eval-server/install-state-routes.d.ts +5 -1
  76. package/dist/eval-server/install-state-routes.js +18 -2
  77. package/dist/eval-server/install-state-routes.js.map +1 -1
  78. package/dist/eval-server/integration-routes.d.ts +1 -1
  79. package/dist/eval-server/integration-routes.js +6 -1
  80. package/dist/eval-server/integration-routes.js.map +1 -1
  81. package/dist/eval-server/model-compare-routes.d.ts +1 -1
  82. package/dist/eval-server/model-compare-routes.js +3 -1
  83. package/dist/eval-server/model-compare-routes.js.map +1 -1
  84. package/dist/eval-server/oauth-github-routes.d.ts +2 -0
  85. package/dist/eval-server/oauth-github-routes.js +505 -0
  86. package/dist/eval-server/oauth-github-routes.js.map +1 -0
  87. package/dist/eval-server/platform-proxy.d.ts +22 -1
  88. package/dist/eval-server/platform-proxy.js +183 -22
  89. package/dist/eval-server/platform-proxy.js.map +1 -1
  90. package/dist/eval-server/plugin-cli-routes.d.ts +1 -1
  91. package/dist/eval-server/plugin-cli-routes.js +19 -10
  92. package/dist/eval-server/plugin-cli-routes.js.map +1 -1
  93. package/dist/eval-server/remove-skill-routes.d.ts +18 -0
  94. package/dist/eval-server/remove-skill-routes.js +147 -0
  95. package/dist/eval-server/remove-skill-routes.js.map +1 -0
  96. package/dist/eval-server/router.d.ts +17 -3
  97. package/dist/eval-server/router.js +166 -9
  98. package/dist/eval-server/router.js.map +1 -1
  99. package/dist/eval-server/settings-store.js +1 -1
  100. package/dist/eval-server/settings-store.js.map +1 -1
  101. package/dist/eval-server/skill-create-routes.d.ts +1 -1
  102. package/dist/eval-server/skill-create-routes.js +8 -1
  103. package/dist/eval-server/skill-create-routes.js.map +1 -1
  104. package/dist/eval-server/supported-agents-routes.d.ts +6 -0
  105. package/dist/eval-server/supported-agents-routes.js +41 -0
  106. package/dist/eval-server/supported-agents-routes.js.map +1 -0
  107. package/dist/eval-server/sweep-routes.d.ts +1 -1
  108. package/dist/eval-server/sweep-routes.js +5 -1
  109. package/dist/eval-server/sweep-routes.js.map +1 -1
  110. package/dist/eval-server/utils/spawn-env.d.ts +1 -0
  111. package/dist/eval-server/utils/spawn-env.js +47 -0
  112. package/dist/eval-server/utils/spawn-env.js.map +1 -0
  113. package/dist/eval-server/workspace-routes.d.ts +12 -0
  114. package/dist/eval-server/workspace-routes.js +57 -2
  115. package/dist/eval-server/workspace-routes.js.map +1 -1
  116. package/dist/eval-ui/assets/AdvancedTab-DOgbx7u0.js +1 -0
  117. package/dist/eval-ui/assets/{CreateSkillPage-CvdYq8Rr.js → CreateSkillPage-Cv93Croj.js} +3 -3
  118. package/dist/eval-ui/assets/FindSkillsPalette-BY9DAhHh.js +2 -0
  119. package/dist/eval-ui/assets/GeneralTab-AwK9sIkP.js +1 -0
  120. package/dist/eval-ui/assets/PrivacyTab-BtNrxpVV.js +1 -0
  121. package/dist/eval-ui/assets/{SearchPaletteCore-Bf3PBC64.js → SearchPaletteCore-DMVcq7UB.js} +2 -2
  122. package/dist/eval-ui/assets/SkillDetailPanel-B_lbhK6q.js +1 -0
  123. package/dist/eval-ui/assets/UpdateDropdown-4AbjZLpq.js +1 -0
  124. package/dist/eval-ui/assets/UpdatesTab-DTmo-vVb.js +1 -0
  125. package/dist/eval-ui/assets/core-DZjBCfjp.js +1 -0
  126. package/dist/eval-ui/assets/event-QtOCMXAv.js +1 -0
  127. package/dist/eval-ui/assets/globals-Dpf9KmYH.css +1 -0
  128. package/dist/eval-ui/assets/globals-hm1COkXX.js +49 -0
  129. package/dist/eval-ui/assets/index-CUEYzTVL.js +1 -0
  130. package/dist/eval-ui/assets/index-DDNzcrhv.js +1 -0
  131. package/dist/eval-ui/assets/index-DhhmQddr.js +1 -0
  132. package/dist/eval-ui/assets/lifecycle-d1Sm9Hts.css +1 -0
  133. package/dist/eval-ui/assets/lifecycle-o_IRibOa.js +1 -0
  134. package/dist/eval-ui/assets/main-tpOyw9SC.js +87 -0
  135. package/dist/eval-ui/assets/preferences-BHZXB5dL.css +1 -0
  136. package/dist/eval-ui/assets/preferences-DCdw0Kvu.js +2 -0
  137. package/dist/eval-ui/assets/useDesktopBridge-9oZFQsrw.js +2 -0
  138. package/dist/eval-ui/index.html +4 -2
  139. package/dist/eval-ui/lifecycle.html +33 -0
  140. package/dist/eval-ui/preferences.html +34 -0
  141. package/dist/index.js +47 -1
  142. package/dist/index.js.map +1 -1
  143. package/dist/installer/bundle-files.d.ts +4 -0
  144. package/dist/installer/bundle-files.js +97 -0
  145. package/dist/installer/bundle-files.js.map +1 -0
  146. package/dist/installer/canonical.d.ts +31 -6
  147. package/dist/installer/canonical.js +48 -12
  148. package/dist/installer/canonical.js.map +1 -1
  149. package/dist/installer/clipboard-export.d.ts +19 -0
  150. package/dist/installer/clipboard-export.js +88 -0
  151. package/dist/installer/clipboard-export.js.map +1 -0
  152. package/dist/installer/multi-install.d.ts +43 -0
  153. package/dist/installer/multi-install.js +237 -0
  154. package/dist/installer/multi-install.js.map +1 -0
  155. package/dist/installer/transformers/aider.d.ts +2 -0
  156. package/dist/installer/transformers/aider.js +32 -0
  157. package/dist/installer/transformers/aider.js.map +1 -0
  158. package/dist/installer/transformers/continue-dev.d.ts +2 -0
  159. package/dist/installer/transformers/continue-dev.js +6 -0
  160. package/dist/installer/transformers/continue-dev.js.map +1 -0
  161. package/dist/installer/transformers/cursor.d.ts +2 -0
  162. package/dist/installer/transformers/cursor.js +24 -0
  163. package/dist/installer/transformers/cursor.js.map +1 -0
  164. package/dist/installer/transformers/github-copilot.d.ts +2 -0
  165. package/dist/installer/transformers/github-copilot.js +17 -0
  166. package/dist/installer/transformers/github-copilot.js.map +1 -0
  167. package/dist/installer/transformers/index.d.ts +78 -0
  168. package/dist/installer/transformers/index.js +13 -0
  169. package/dist/installer/transformers/index.js.map +1 -0
  170. package/dist/installer/transformers/junie.d.ts +2 -0
  171. package/dist/installer/transformers/junie.js +6 -0
  172. package/dist/installer/transformers/junie.js.map +1 -0
  173. package/dist/installer/transformers/kiro.d.ts +2 -0
  174. package/dist/installer/transformers/kiro.js +6 -0
  175. package/dist/installer/transformers/kiro.js.map +1 -0
  176. package/dist/installer/transformers/trae.d.ts +2 -0
  177. package/dist/installer/transformers/trae.js +6 -0
  178. package/dist/installer/transformers/trae.js.map +1 -0
  179. package/dist/installer/transformers/windsurf.d.ts +2 -0
  180. package/dist/installer/transformers/windsurf.js +12 -0
  181. package/dist/installer/transformers/windsurf.js.map +1 -0
  182. package/dist/installer/yaml-safe-mutate.d.ts +19 -0
  183. package/dist/installer/yaml-safe-mutate.js +184 -0
  184. package/dist/installer/yaml-safe-mutate.js.map +1 -0
  185. package/dist/lib/active-tenant.d.ts +36 -0
  186. package/dist/lib/active-tenant.js +120 -0
  187. package/dist/lib/active-tenant.js.map +1 -0
  188. package/dist/lib/keychain.d.ts +15 -2
  189. package/dist/lib/keychain.js +173 -8
  190. package/dist/lib/keychain.js.map +1 -1
  191. package/dist/lib/migration/keychain-migration.d.ts +35 -0
  192. package/dist/lib/migration/keychain-migration.js +189 -0
  193. package/dist/lib/migration/keychain-migration.js.map +1 -0
  194. package/dist/lib/tenant-resolver.d.ts +38 -0
  195. package/dist/lib/tenant-resolver.js +79 -0
  196. package/dist/lib/tenant-resolver.js.map +1 -0
  197. package/dist/studio/lib/ops-log.js +140 -57
  198. package/dist/studio/lib/ops-log.js.map +1 -1
  199. package/dist/studio/lib/scope-transfer.d.ts +11 -1
  200. package/dist/studio/lib/scope-transfer.js +48 -24
  201. package/dist/studio/lib/scope-transfer.js.map +1 -1
  202. package/dist/studio/routes/index.d.ts +1 -1
  203. package/dist/studio/routes/index.js +18 -8
  204. package/dist/studio/routes/index.js.map +1 -1
  205. package/dist/studio/routes/ops.js +31 -7
  206. package/dist/studio/routes/ops.js.map +1 -1
  207. package/dist/studio/routes/promote.d.ts +1 -1
  208. package/dist/studio/routes/promote.js +18 -9
  209. package/dist/studio/routes/promote.js.map +1 -1
  210. package/dist/studio/routes/revert.d.ts +1 -1
  211. package/dist/studio/routes/revert.js +15 -2
  212. package/dist/studio/routes/revert.js.map +1 -1
  213. package/dist/studio/routes/test-install.d.ts +1 -1
  214. package/dist/studio/routes/test-install.js +16 -9
  215. package/dist/studio/routes/test-install.js.map +1 -1
  216. package/dist/studio-runtime/lockfile.d.ts +51 -0
  217. package/dist/studio-runtime/lockfile.js +216 -0
  218. package/dist/studio-runtime/lockfile.js.map +1 -0
  219. package/package.json +18 -1
  220. package/dist/eval-ui/assets/FindSkillsPalette-DsSgotS9.js +0 -2
  221. package/dist/eval-ui/assets/SkillDetailPanel-DAD2yJO-.js +0 -1
  222. package/dist/eval-ui/assets/UpdateDropdown-h5Hg3h7Z.js +0 -1
  223. package/dist/eval-ui/assets/index-CKLqBL52.css +0 -1
  224. package/dist/eval-ui/assets/index-JaDg6FlU.js +0 -124
  225. package/dist/eval-ui/assets/skill-studio-logo-CRyKgIrg.png +0 -0
@@ -14,15 +14,38 @@
14
14
  // Tokens are NEVER logged. Callers should redact via `redactToken()` before
15
15
  // any user-facing output.
16
16
  //
17
- // Service identity:
18
- // - service: "vskill-github"
19
- // - account: "github_token"
17
+ // Service identity (0836 US-006 — canonical, shared with the Rust desktop):
18
+ // - service: "com.verifiedskill.desktop" (was "vskill-github")
19
+ // - account: "github-oauth-token" (was "github_token")
20
+ //
21
+ // On first construction we run a one-time migration that moves any token
22
+ // from the legacy slot into the canonical slot. The legacy fallback in
23
+ // `getGitHubToken` covers users who haven't yet booted a process that ran
24
+ // the migration (e.g., the Rust desktop wrote the canonical slot, but a
25
+ // vintage CLI install reads from the old one). Both paths are scheduled
26
+ // for removal AFTER vskill 1.1.x — see keychain-migration.ts for the
27
+ // removal target.
20
28
  // ---------------------------------------------------------------------------
21
29
  import * as nodeFs from "node:fs";
22
30
  import * as nodePath from "node:path";
23
31
  import * as nodeOs from "node:os";
24
- export const SERVICE_NAME = "vskill-github";
25
- export const GITHUB_TOKEN_KEY = "github_token";
32
+ import { runKeychainMigration } from "./migration/keychain-migration.js";
33
+ export const SERVICE_NAME = "com.verifiedskill.desktop";
34
+ export const GITHUB_TOKEN_KEY = "github-oauth-token";
35
+ // 0839 US-005: verified-skill API token (`vsk_*`) lives in a parallel
36
+ // keychain slot so `gho_*` (GitHub OAuth, used for direct GitHub API calls)
37
+ // and `vsk_*` (our minted API token, used for verified-skill.com calls)
38
+ // coexist. See ADR-001 in 0839/plan.md. Distinct slots keep keychain
39
+ // lookups O(1) and avoid prefix-sniffing every read.
40
+ export const VSKILL_TOKEN_SERVICE = "vskill-token";
41
+ export const VSKILL_TOKEN_KEY = "vskill-api-token";
42
+ // 0836 US-006: legacy slot — read-only fallback during the one-release
43
+ // compat window. Remove after vskill 1.1.x ships.
44
+ // TODO(0836-followup): drop LEGACY_SERVICE_NAME + LEGACY_TOKEN_KEY + the
45
+ // fallback branch in getGitHubToken once 1.1.x has had one full release
46
+ // cycle to migrate users.
47
+ const LEGACY_SERVICE_NAME = "vskill-github";
48
+ const LEGACY_TOKEN_KEY = "github_token";
26
49
  const DEFAULT_FALLBACK = nodePath.join(nodeOs.homedir(), ".vskill", "keys.env");
27
50
  const defaultFs = {
28
51
  readFileSync: (p) => nodeFs.readFileSync(p, { encoding: "utf8" }),
@@ -32,6 +55,14 @@ const defaultFs = {
32
55
  mkdirSync: (p) => nodeFs.mkdirSync(p, { recursive: true, mode: 0o700 }),
33
56
  unlinkSync: (p) => nodeFs.unlinkSync(p),
34
57
  };
58
+ // 0836 US-006: per-process flag so the one-time migration runs exactly
59
+ // once even if multiple keychains are constructed (the test suite does
60
+ // this; production has a single default keychain).
61
+ let _migrationRun = false;
62
+ /** Test-only — reset the migration-once flag so test factories can re-run it. */
63
+ export function _resetMigrationFlagForTests() {
64
+ _migrationRun = false;
65
+ }
35
66
  function loadDefaultKeyring() {
36
67
  // The native module is loaded lazily so the CLI still boots in environments
37
68
  // where the binary isn't available (rare, since @napi-rs/keyring ships
@@ -102,6 +133,21 @@ export function createKeychain(opts = {}) {
102
133
  keyring = opts.keyring;
103
134
  else
104
135
  keyring = loadDefaultKeyring();
136
+ // 0836 US-006: run the one-time legacy-slot → canonical-slot migration
137
+ // exactly once per process. The helper is idempotent (skip-flag +
138
+ // mutex), so calling it on every createKeychain construction is safe;
139
+ // the per-process flag is only an optimization to avoid the cheap
140
+ // file-stat check on every test factory.
141
+ if (!_migrationRun) {
142
+ _migrationRun = true;
143
+ try {
144
+ runKeychainMigration({ keyring });
145
+ }
146
+ catch {
147
+ // Best-effort — migration failure leaves the legacy fallback path
148
+ // intact; no user-visible regression.
149
+ }
150
+ }
105
151
  let warnedFallback = false;
106
152
  let fallbackInUse = false;
107
153
  function tryKeyring(fn) {
@@ -153,18 +199,51 @@ export function createKeychain(opts = {}) {
153
199
  },
154
200
  getGitHubToken() {
155
201
  const r = tryKeyring((kr) => kr.getPassword(SERVICE_NAME, GITHUB_TOKEN_KEY));
156
- if (r.ok && r.value)
202
+ if (r.ok && r.value) {
203
+ // 0836 hardening (F-008 follow-up): if BOTH the canonical and the
204
+ // legacy slots are populated, log a WARN. This catches the
205
+ // dual-writer drift case where a vintage `vskill@<old>` install
206
+ // wrote to legacy after migration's done-flag was set. Canonical
207
+ // wins (current return), but operators get a signal the user has
208
+ // two copies and should re-authenticate.
209
+ try {
210
+ const legacy = tryKeyring((kr) => kr.getPassword(LEGACY_SERVICE_NAME, LEGACY_TOKEN_KEY));
211
+ if (legacy.ok && legacy.value && legacy.value !== r.value) {
212
+ // Avoid logging the token values themselves — only the fact of drift.
213
+ // eslint-disable-next-line no-console
214
+ console.warn("[vskill keychain] both canonical and legacy slots are populated; canonical wins. Run `vskill auth login` to clear drift.");
215
+ }
216
+ }
217
+ catch {
218
+ // Non-fatal: drift detection is best-effort.
219
+ }
157
220
  return r.value;
221
+ }
158
222
  if (r.ok && r.value === null) {
223
+ // 0836 US-006 legacy fallback: a vintage CLI install that hasn't
224
+ // booted post-migration may still hold the token in the old slot.
225
+ // Honor it for one release window. The migration helper will move
226
+ // this on the next process boot; until then we read from where it
227
+ // lives.
228
+ // TODO(0836-followup): remove after vskill 1.1.x ships.
229
+ const legacy = tryKeyring((kr) => kr.getPassword(LEGACY_SERVICE_NAME, LEGACY_TOKEN_KEY));
230
+ if (legacy.ok && legacy.value)
231
+ return legacy.value;
159
232
  // keyring works but slot is empty — also peek at fallback in case the
160
233
  // user set a token before keyring became available, but DO NOT warn
161
234
  // because keyring is fine.
162
235
  const map = readFallback();
163
- return map.get(GITHUB_TOKEN_KEY) ?? null;
236
+ if (map.has(GITHUB_TOKEN_KEY))
237
+ return map.get(GITHUB_TOKEN_KEY) ?? null;
238
+ // 0836 US-006: legacy file-fallback key, kept for the same
239
+ // one-release window as the legacy keyring service.
240
+ return map.get(LEGACY_TOKEN_KEY) ?? null;
164
241
  }
165
242
  ensureFallbackWarned();
166
243
  const map = readFallback();
167
- return map.get(GITHUB_TOKEN_KEY) ?? null;
244
+ if (map.has(GITHUB_TOKEN_KEY))
245
+ return map.get(GITHUB_TOKEN_KEY) ?? null;
246
+ return map.get(LEGACY_TOKEN_KEY) ?? null;
168
247
  },
169
248
  clearGitHubToken() {
170
249
  let removed = false;
@@ -192,6 +271,81 @@ export function createKeychain(opts = {}) {
192
271
  }
193
272
  return removed;
194
273
  },
274
+ // -----------------------------------------------------------------
275
+ // 0839 US-005: verified-skill API token (`vsk_*`).
276
+ //
277
+ // Same storage contract as the GitHub token (keyring preferred,
278
+ // 0600 file fallback) but a distinct service/account so the two
279
+ // tokens never collide. Public surface mirrors the GitHub helpers.
280
+ // -----------------------------------------------------------------
281
+ setVskillToken(token) {
282
+ if (!token || typeof token !== "string") {
283
+ throw new Error("setVskillToken: token must be a non-empty string");
284
+ }
285
+ // 0855 — DUAL-WRITE: unlike the GitHub token, the vsk_ token must ALSO
286
+ // land in the keys.env fallback even when the keyring write succeeds.
287
+ // Rationale: a headless / CLI-spawned `vskill studio` process often
288
+ // cannot read the macOS login Keychain (no GUI session), so the
289
+ // eval-server proxy — which injects vsk_ for /api/v1/submissions —
290
+ // would otherwise get null and return 401. The 0600 file is readable
291
+ // from any spawned process, so it's the reliable cross-process channel.
292
+ // We attempt the keyring (best-effort, for tools that CAN read it) and
293
+ // unconditionally also write the fallback. Reads stay keyring-first via
294
+ // getVskillToken, so the keyring copy still wins when both are present.
295
+ const r = tryKeyring((kr) => kr.setPassword(VSKILL_TOKEN_SERVICE, VSKILL_TOKEN_KEY, token));
296
+ if (!r.ok) {
297
+ // Keyring genuinely unavailable — surface the one-time fallback warning.
298
+ ensureFallbackWarned();
299
+ }
300
+ else {
301
+ // Keyring worked, but we still mirror to the file for headless readers.
302
+ // Mark the fallback as in-use WITHOUT emitting the "keychain
303
+ // unavailable" warning, which would be misleading here.
304
+ fallbackInUse = true;
305
+ }
306
+ const map = readFallback();
307
+ map.set(VSKILL_TOKEN_KEY, token);
308
+ writeFallback(map);
309
+ },
310
+ getVskillToken() {
311
+ const r = tryKeyring((kr) => kr.getPassword(VSKILL_TOKEN_SERVICE, VSKILL_TOKEN_KEY));
312
+ if (r.ok && r.value)
313
+ return r.value;
314
+ if (r.ok && r.value === null) {
315
+ // Keyring works but slot is empty — peek at fallback in case the
316
+ // user wrote a token before keyring became available. Don't warn:
317
+ // the keyring path is healthy.
318
+ const map = readFallback();
319
+ return map.get(VSKILL_TOKEN_KEY) ?? null;
320
+ }
321
+ ensureFallbackWarned();
322
+ const map = readFallback();
323
+ return map.get(VSKILL_TOKEN_KEY) ?? null;
324
+ },
325
+ clearVskillToken() {
326
+ let removed = false;
327
+ const r = tryKeyring((kr) => kr.deletePassword(VSKILL_TOKEN_SERVICE, VSKILL_TOKEN_KEY));
328
+ if (r.ok && r.value)
329
+ removed = true;
330
+ if (fs.existsSync(fallbackPath)) {
331
+ const map = readFallback();
332
+ if (map.delete(VSKILL_TOKEN_KEY)) {
333
+ if (map.size === 0) {
334
+ try {
335
+ fs.unlinkSync(fallbackPath);
336
+ }
337
+ catch {
338
+ writeFallback(map);
339
+ }
340
+ }
341
+ else {
342
+ writeFallback(map);
343
+ }
344
+ removed = true;
345
+ }
346
+ }
347
+ return removed;
348
+ },
195
349
  usingFallback() {
196
350
  return fallbackInUse || keyring === null;
197
351
  },
@@ -221,6 +375,17 @@ export function setGitHubToken(token) {
221
375
  export function clearGitHubToken() {
222
376
  return getDefaultKeychain().clearGitHubToken();
223
377
  }
378
+ // 0839 US-005: module-level convenience accessors for the verified-skill
379
+ // API token. Mirror the GitHub helpers above for parity.
380
+ export function getVskillToken() {
381
+ return getDefaultKeychain().getVskillToken();
382
+ }
383
+ export function setVskillToken(token) {
384
+ getDefaultKeychain().setVskillToken(token);
385
+ }
386
+ export function clearVskillToken() {
387
+ return getDefaultKeychain().clearVskillToken();
388
+ }
224
389
  /** Last-4 redaction for log-safe output. */
225
390
  export function redactToken(token) {
226
391
  if (!token)
@@ -1 +1 @@
1
- {"version":3,"file":"keychain.js","sourceRoot":"","sources":["../../src/lib/keychain.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"keychain.js","sourceRoot":"","sources":["../../src/lib/keychain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ export type MigrationResult = "migrated" | "noop" | "skipped";
2
+ export interface KeyringBackend {
3
+ setPassword(service: string, account: string, password: string): void;
4
+ getPassword(service: string, account: string): string | null;
5
+ deletePassword(service: string, account: string): boolean;
6
+ }
7
+ export interface MigrationFsAdapter {
8
+ existsSync: (p: string) => boolean;
9
+ readFileSync: (p: string) => string;
10
+ writeFileSync: (p: string, content: string) => void;
11
+ mkdirSync: (p: string) => void;
12
+ unlinkSync: (p: string) => void;
13
+ statSync: (p: string) => {
14
+ mtimeMs: number;
15
+ };
16
+ }
17
+ export interface MigrationDeps {
18
+ keyring: KeyringBackend | null;
19
+ fs?: MigrationFsAdapter;
20
+ now?: () => number;
21
+ homeDir?: string;
22
+ }
23
+ /**
24
+ * Runs the legacy → canonical migration with mutex serialization.
25
+ *
26
+ * Returns:
27
+ * - 'migrated' — token moved (or both slots cleaned up)
28
+ * - 'noop' — nothing to migrate; done flag written
29
+ * - 'skipped' — environment opt-out, missing keyring, done flag, or
30
+ * another runner holds a fresh lock
31
+ *
32
+ * Idempotent — running twice is safe (the second call sees the done flag
33
+ * and returns 'skipped').
34
+ */
35
+ export declare function runKeychainMigration(deps: MigrationDeps): MigrationResult;
@@ -0,0 +1,189 @@
1
+ // ---------------------------------------------------------------------------
2
+ // 0836 US-006 — keychain migration: legacy slot → canonical slot.
3
+ //
4
+ // Pre-0836: Node CLI used `vskill-github::github_token` (legacy)
5
+ // Post-0836: Node CLI uses `com.verifiedskill.desktop::github-oauth-token`
6
+ // (canonical — also the Rust desktop's slot per
7
+ // ADR-0836-03)
8
+ //
9
+ // This module runs ONCE on Node-side boot (via `keychain.ts::createKeychain`)
10
+ // and migrates any token from the legacy slot to the canonical slot. The
11
+ // move is idempotent + race-safe via a 5s-TTL file mutex at
12
+ // `~/.vskill/locks/keychain-migration.lock`. A done-flag at
13
+ // `~/.vskill/keychain-migration.done` short-circuits subsequent boots.
14
+ //
15
+ // Rust does NOT participate — `src-tauri/src/auth/token_store.rs` is already
16
+ // on the canonical slot (locked by a constant test there).
17
+ //
18
+ // Removal target: drop this whole module + the legacy fallback in
19
+ // keychain.ts AFTER vskill 1.1.x. Anton: remember to bump.
20
+ import * as nodeFs from "node:fs";
21
+ import * as nodePath from "node:path";
22
+ import * as nodeOs from "node:os";
23
+ const LEGACY_SERVICE = "vskill-github";
24
+ const LEGACY_ACCOUNT = "github_token";
25
+ const CANONICAL_SERVICE = "com.verifiedskill.desktop";
26
+ const CANONICAL_ACCOUNT = "github-oauth-token";
27
+ const LOCK_TTL_MS = 5_000;
28
+ const defaultFs = {
29
+ existsSync: (p) => nodeFs.existsSync(p),
30
+ readFileSync: (p) => nodeFs.readFileSync(p, { encoding: "utf8" }),
31
+ writeFileSync: (p, c) => nodeFs.writeFileSync(p, c, { encoding: "utf8", mode: 0o600 }),
32
+ mkdirSync: (p) => {
33
+ nodeFs.mkdirSync(p, { recursive: true, mode: 0o700 });
34
+ },
35
+ unlinkSync: (p) => nodeFs.unlinkSync(p),
36
+ statSync: (p) => {
37
+ const s = nodeFs.statSync(p);
38
+ return { mtimeMs: s.mtimeMs };
39
+ },
40
+ };
41
+ function paths(homeDir) {
42
+ const root = nodePath.join(homeDir, ".vskill");
43
+ return {
44
+ doneFlag: nodePath.join(root, "keychain-migration.done"),
45
+ lockFile: nodePath.join(root, "locks", "keychain-migration.lock"),
46
+ lockDir: nodePath.join(root, "locks"),
47
+ };
48
+ }
49
+ /**
50
+ * Runs the legacy → canonical migration with mutex serialization.
51
+ *
52
+ * Returns:
53
+ * - 'migrated' — token moved (or both slots cleaned up)
54
+ * - 'noop' — nothing to migrate; done flag written
55
+ * - 'skipped' — environment opt-out, missing keyring, done flag, or
56
+ * another runner holds a fresh lock
57
+ *
58
+ * Idempotent — running twice is safe (the second call sees the done flag
59
+ * and returns 'skipped').
60
+ */
61
+ export function runKeychainMigration(deps) {
62
+ // Env opt-out — power users / CI can set VSKILL_KEYCHAIN_MIGRATE=0.
63
+ if (process.env.VSKILL_KEYCHAIN_MIGRATE === "0") {
64
+ return "skipped";
65
+ }
66
+ if (!deps.keyring)
67
+ return "skipped";
68
+ const fs = deps.fs ?? defaultFs;
69
+ const now = deps.now ?? Date.now;
70
+ const home = deps.homeDir ?? nodeOs.homedir();
71
+ const p = paths(home);
72
+ // Done-flag short-circuit — prior boot already migrated.
73
+ if (fs.existsSync(p.doneFlag))
74
+ return "skipped";
75
+ // Acquire lock.
76
+ if (!acquireLock(fs, p, now)) {
77
+ return "skipped";
78
+ }
79
+ try {
80
+ return migrateUnderLock(deps.keyring, fs, p, now);
81
+ }
82
+ finally {
83
+ releaseLock(fs, p);
84
+ }
85
+ }
86
+ function acquireLock(fs, p, now) {
87
+ // Ensure parent dir exists.
88
+ try {
89
+ fs.mkdirSync(p.lockDir);
90
+ }
91
+ catch {
92
+ // ignore — parent may already exist
93
+ }
94
+ if (fs.existsSync(p.lockFile)) {
95
+ // Check staleness.
96
+ let stale = false;
97
+ try {
98
+ const stat = fs.statSync(p.lockFile);
99
+ stale = now() - stat.mtimeMs > LOCK_TTL_MS;
100
+ }
101
+ catch {
102
+ stale = true; // can't stat → treat as stale and steal
103
+ }
104
+ if (!stale) {
105
+ // Another runner holds a fresh lock — back off.
106
+ return false;
107
+ }
108
+ // Steal.
109
+ try {
110
+ fs.unlinkSync(p.lockFile);
111
+ }
112
+ catch {
113
+ // ignore — race with the other runner releasing it
114
+ }
115
+ }
116
+ try {
117
+ fs.writeFileSync(p.lockFile, String(process.pid));
118
+ }
119
+ catch {
120
+ return false;
121
+ }
122
+ return true;
123
+ }
124
+ function releaseLock(fs, p) {
125
+ try {
126
+ fs.unlinkSync(p.lockFile);
127
+ }
128
+ catch {
129
+ // ignore
130
+ }
131
+ }
132
+ function migrateUnderLock(keyring, fs, p, _now) {
133
+ const old = safeGet(keyring, LEGACY_SERVICE, LEGACY_ACCOUNT);
134
+ const canonical = safeGet(keyring, CANONICAL_SERVICE, CANONICAL_ACCOUNT);
135
+ if (old == null && canonical == null) {
136
+ writeDoneFlag(fs, p);
137
+ return "noop";
138
+ }
139
+ if (old != null && canonical == null) {
140
+ // Promote old → canonical, then drop old.
141
+ safeSet(keyring, CANONICAL_SERVICE, CANONICAL_ACCOUNT, old);
142
+ safeDelete(keyring, LEGACY_SERVICE, LEGACY_ACCOUNT);
143
+ writeDoneFlag(fs, p);
144
+ return "migrated";
145
+ }
146
+ if (old != null && canonical != null) {
147
+ // Both populated — keep canonical (newer), delete old.
148
+ safeDelete(keyring, LEGACY_SERVICE, LEGACY_ACCOUNT);
149
+ writeDoneFlag(fs, p);
150
+ return "migrated";
151
+ }
152
+ // canonical-only: nothing to do; mark done so we don't re-check.
153
+ writeDoneFlag(fs, p);
154
+ return "noop";
155
+ }
156
+ function writeDoneFlag(fs, p) {
157
+ try {
158
+ fs.writeFileSync(p.doneFlag, "1");
159
+ }
160
+ catch {
161
+ // Best-effort — if the flag can't be written, the migration just
162
+ // re-runs next boot; harmless because each step is idempotent.
163
+ }
164
+ }
165
+ function safeGet(kr, service, account) {
166
+ try {
167
+ return kr.getPassword(service, account);
168
+ }
169
+ catch {
170
+ return null;
171
+ }
172
+ }
173
+ function safeSet(kr, service, account, value) {
174
+ try {
175
+ kr.setPassword(service, account, value);
176
+ }
177
+ catch {
178
+ // ignore — failure is logged elsewhere; migration continues
179
+ }
180
+ }
181
+ function safeDelete(kr, service, account) {
182
+ try {
183
+ kr.deletePassword(service, account);
184
+ }
185
+ catch {
186
+ // ignore
187
+ }
188
+ }
189
+ //# sourceMappingURL=keychain-migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keychain-migration.js","sourceRoot":"","sources":["../../../src/lib/migration/keychain-migration.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { type ActiveTenantOptions } from "./active-tenant.js";
2
+ import { type TenantSummary } from "../api/client.js";
3
+ export interface ResolveTenantOptions {
4
+ /** Highest priority — usually the CLI `--tenant` flag. */
5
+ flag?: string | null;
6
+ /** Override env reader (tests). Defaults to `process.env.VSKILL_TENANT`. */
7
+ envValue?: string | null;
8
+ /** Override config-dir resolution (tests). */
9
+ activeTenantOptions?: ActiveTenantOptions;
10
+ /** Override tenants fetcher (tests / offline mode). */
11
+ listTenants?: () => Promise<TenantSummary[]>;
12
+ /**
13
+ * When true, the resolver may make a network call to /account/tenants for
14
+ * the N=1 auto-pick fallback. Defaults to true. Setting false skips
15
+ * step (4) — useful for offline-first commands where the caller would
16
+ * rather error than block on the network.
17
+ */
18
+ enableAutoPick?: boolean;
19
+ }
20
+ export type ResolvedTenant = {
21
+ kind: "flag" | "env" | "config" | "auto-pick";
22
+ slug: string;
23
+ } | {
24
+ kind: "none";
25
+ /** Why no tenant was resolved (for caller-side messaging). */
26
+ reason: "anonymous" | "no-tenants" | "multiple-tenants-no-default" | "fetch-failed";
27
+ /** Available tenants when reason === "multiple-tenants-no-default". */
28
+ tenants?: TenantSummary[];
29
+ /** Network error string when reason === "fetch-failed". */
30
+ error?: string;
31
+ };
32
+ export declare function resolveTenant(opts?: ResolveTenantOptions): Promise<ResolvedTenant>;
33
+ /**
34
+ * Helper for callers that just want the slug (or null) without inspecting
35
+ * the resolution kind. The caller is responsible for handling the null
36
+ * case (typically by surfacing a clear error message).
37
+ */
38
+ export declare function resolveTenantSlug(opts?: ResolveTenantOptions): Promise<string | null>;
@@ -0,0 +1,79 @@
1
+ // ---------------------------------------------------------------------------
2
+ // tenant-resolver.ts — 0839 ADR-002 priority-ordered resolution.
3
+ //
4
+ // Order:
5
+ // 1. Explicit --tenant flag (highest)
6
+ // 2. VSKILL_TENANT env var
7
+ // 3. ~/.vskill/config.json `currentTenant`
8
+ // 4. Auto-pick when the user has exactly N=1 tenant
9
+ // 5. Error — caller decides whether to surface a multi-tenant prompt
10
+ //
11
+ // `resolveTenant` is intentionally async: step (4) requires a network
12
+ // call to /api/v1/account/tenants. We short-circuit before that for the
13
+ // common-case (flag/env/config). The fetcher is dependency-injected so
14
+ // tests don't hit the network.
15
+ //
16
+ // The resolver does NOT mutate any state (no env writes, no config
17
+ // writes). Callers pass the result to subsequent API calls via
18
+ // `apiRequest({ tenantOverride })` or by calling the returned context.
19
+ // ---------------------------------------------------------------------------
20
+ import { getActiveTenant, } from "./active-tenant.js";
21
+ import { listTenants as defaultListTenants, } from "../api/client.js";
22
+ export async function resolveTenant(opts = {}) {
23
+ // 1. Explicit flag.
24
+ if (opts.flag && opts.flag.length > 0) {
25
+ return { kind: "flag", slug: opts.flag };
26
+ }
27
+ // 2. Env var.
28
+ const env = opts.envValue !== undefined ? opts.envValue : process.env.VSKILL_TENANT;
29
+ if (env && env.length > 0) {
30
+ return { kind: "env", slug: env };
31
+ }
32
+ // 3. Config file.
33
+ const fromConfig = getActiveTenant(opts.activeTenantOptions);
34
+ if (fromConfig) {
35
+ return { kind: "config", slug: fromConfig };
36
+ }
37
+ // 4. Auto-pick when N=1 — only if the caller opted in.
38
+ if (opts.enableAutoPick === false) {
39
+ return { kind: "none", reason: "multiple-tenants-no-default" };
40
+ }
41
+ let tenants;
42
+ try {
43
+ tenants = await (opts.listTenants ?? defaultListTenants)();
44
+ }
45
+ catch (err) {
46
+ const e = err;
47
+ // 401 → caller is anonymous — bubble that up so the CLI can hint
48
+ // `vskill auth login` instead of "no tenants".
49
+ if (e.status === 401) {
50
+ return { kind: "none", reason: "anonymous" };
51
+ }
52
+ return {
53
+ kind: "none",
54
+ reason: "fetch-failed",
55
+ error: e.message ?? String(err),
56
+ };
57
+ }
58
+ if (tenants.length === 0) {
59
+ return { kind: "none", reason: "no-tenants" };
60
+ }
61
+ if (tenants.length === 1) {
62
+ return { kind: "auto-pick", slug: tenants[0].slug };
63
+ }
64
+ return {
65
+ kind: "none",
66
+ reason: "multiple-tenants-no-default",
67
+ tenants,
68
+ };
69
+ }
70
+ /**
71
+ * Helper for callers that just want the slug (or null) without inspecting
72
+ * the resolution kind. The caller is responsible for handling the null
73
+ * case (typically by surfacing a clear error message).
74
+ */
75
+ export async function resolveTenantSlug(opts = {}) {
76
+ const r = await resolveTenant(opts);
77
+ return r.kind === "none" ? null : r.slug;
78
+ }
79
+ //# sourceMappingURL=tenant-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-resolver.js","sourceRoot":"","sources":["../../src/lib/tenant-resolver.ts"],"names":[],"mappings":"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"}