jd-skills 0.1.0 → 0.1.1

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.
@@ -1,2 +1,158 @@
1
- import { i as setBrokerUrl, n as getConfig, r as resetConfig, t as getBrokerUrl } from "./config2.mjs";
2
- export { getBrokerUrl };
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
2
+ import { dirname, join } from "path";
3
+ import { homedir } from "os";
4
+ const JD_INTRANET_DEFAULTS = {
5
+ skillApiUrl: "https://mkt-skill-manager.jd.com/api/skill/public/sorted-list",
6
+ brokerUrl: "https://cbroker.jd.com",
7
+ sdkPackage: "@jd/jd-cookie-broker",
8
+ gitlabHosts: ["coding.jd.com"],
9
+ npmRegistry: "http://registry.m.jd.com"
10
+ };
11
+ const PROBE_CACHE_PATH = join(homedir(), ".jd-skills", "intranet-probe.json");
12
+ const PROBE_TTL_MS = 3600 * 1e3;
13
+ const PROBE_TIMEOUT_MS = 3e3;
14
+ let memoryProbe = null;
15
+ let inFlightProbe = null;
16
+ function readDiskProbe() {
17
+ try {
18
+ if (!existsSync(PROBE_CACHE_PATH)) return null;
19
+ const parsed = JSON.parse(readFileSync(PROBE_CACHE_PATH, "utf-8"));
20
+ if (typeof parsed.available !== "boolean" || typeof parsed.checkedAt !== "number") return null;
21
+ if (Date.now() - parsed.checkedAt > PROBE_TTL_MS) return null;
22
+ return parsed;
23
+ } catch {
24
+ return null;
25
+ }
26
+ }
27
+ function writeDiskProbe(available) {
28
+ try {
29
+ mkdirSync(dirname(PROBE_CACHE_PATH), { recursive: true });
30
+ writeFileSync(PROBE_CACHE_PATH, JSON.stringify({
31
+ available,
32
+ checkedAt: Date.now()
33
+ }, null, 2), { mode: 384 });
34
+ } catch {}
35
+ }
36
+ function setProbeResult(available) {
37
+ memoryProbe = available;
38
+ writeDiskProbe(available);
39
+ return available;
40
+ }
41
+ function getJdIntranetProbeSync() {
42
+ if (memoryProbe !== null) return memoryProbe;
43
+ const cached = readDiskProbe();
44
+ if (!cached) return null;
45
+ memoryProbe = cached.available;
46
+ return cached.available;
47
+ }
48
+ async function headReachable(url) {
49
+ try {
50
+ return (await fetch(url, {
51
+ method: "HEAD",
52
+ signal: AbortSignal.timeout(PROBE_TIMEOUT_MS)
53
+ })).status < 500;
54
+ } catch {
55
+ return false;
56
+ }
57
+ }
58
+ async function probeJdIntranet(force = false) {
59
+ if (!force && memoryProbe !== null) return memoryProbe;
60
+ if (!force) {
61
+ const cached = readDiskProbe();
62
+ if (cached) {
63
+ memoryProbe = cached.available;
64
+ return cached.available;
65
+ }
66
+ }
67
+ if (!force && inFlightProbe) return inFlightProbe;
68
+ inFlightProbe = (async () => {
69
+ return setProbeResult(await headReachable((process.env.JD_SKILL_API_URL ?? "").trim() || JD_INTRANET_DEFAULTS.skillApiUrl));
70
+ })();
71
+ try {
72
+ return await inFlightProbe;
73
+ } finally {
74
+ inFlightProbe = null;
75
+ }
76
+ }
77
+ function isJdIntranetAvailable() {
78
+ return getJdIntranetProbeSync() === true;
79
+ }
80
+ async function resolveSkillApiUrl() {
81
+ const env = (process.env.JD_SKILL_API_URL ?? "").trim();
82
+ if (env) return env;
83
+ if (await probeJdIntranet()) return JD_INTRANET_DEFAULTS.skillApiUrl;
84
+ return "";
85
+ }
86
+ function resolveSkillApiUrlSync() {
87
+ const env = (process.env.JD_SKILL_API_URL ?? "").trim();
88
+ if (env) return env;
89
+ if (isJdIntranetAvailable()) return JD_INTRANET_DEFAULTS.skillApiUrl;
90
+ return "";
91
+ }
92
+ function resolveSdkPackageName() {
93
+ const env = (process.env.JD_BROKER_SDK_PACKAGE ?? "").trim();
94
+ if (env) return env;
95
+ if (isJdIntranetAvailable()) return JD_INTRANET_DEFAULTS.sdkPackage;
96
+ return "";
97
+ }
98
+ async function resolveSdkPackageNameAsync() {
99
+ const env = (process.env.JD_BROKER_SDK_PACKAGE ?? "").trim();
100
+ if (env) return env;
101
+ if (await probeJdIntranet()) return JD_INTRANET_DEFAULTS.sdkPackage;
102
+ return "";
103
+ }
104
+ function resolveBrokerUrlFromIntranet(fileBrokerUrl) {
105
+ const envUrl = (process.env.JD_BROKER_URL ?? "").trim();
106
+ if (envUrl) return envUrl.replace(/\/+$/, "");
107
+ if (fileBrokerUrl) return fileBrokerUrl;
108
+ if (isJdIntranetAvailable()) return JD_INTRANET_DEFAULTS.brokerUrl;
109
+ return "";
110
+ }
111
+ function resolveGitlabHosts() {
112
+ const fromEnv = (process.env.JD_GITLAB_HOSTS ?? "").split(",").map((h) => h.trim().toLowerCase()).filter((h) => h.length > 0).filter((h, i, arr) => arr.indexOf(h) === i);
113
+ if (fromEnv.length > 0) return fromEnv;
114
+ if (isJdIntranetAvailable()) return [...JD_INTRANET_DEFAULTS.gitlabHosts];
115
+ return [];
116
+ }
117
+ function resolveExpectedNpmRegistry() {
118
+ const env = (process.env.JD_NPM_REGISTRY ?? "").trim();
119
+ if (env) return env;
120
+ if (isJdIntranetAvailable()) return JD_INTRANET_DEFAULTS.npmRegistry;
121
+ return "";
122
+ }
123
+ const CONFIG_PATH = join(join(homedir(), ".jd-skills"), "config.json");
124
+ function readConfig() {
125
+ try {
126
+ if (!existsSync(CONFIG_PATH)) return {};
127
+ const raw = readFileSync(CONFIG_PATH, "utf-8");
128
+ const parsed = JSON.parse(raw);
129
+ if (typeof parsed !== "object" || parsed === null) return {};
130
+ return parsed;
131
+ } catch {
132
+ return {};
133
+ }
134
+ }
135
+ function writeConfig(config) {
136
+ mkdirSync(dirname(CONFIG_PATH), { recursive: true });
137
+ writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 384 });
138
+ }
139
+ function getBrokerUrl() {
140
+ const fileConfig = readConfig();
141
+ return resolveBrokerUrlFromIntranet(fileConfig.brokerUrl && fileConfig.brokerUrl.trim().length > 0 ? fileConfig.brokerUrl.trim().replace(/\/+$/, "") : "");
142
+ }
143
+ function setBrokerUrl(url) {
144
+ const config = readConfig();
145
+ if (url && url.trim().length > 0) config.brokerUrl = url.trim().replace(/\/+$/, "");
146
+ else delete config.brokerUrl;
147
+ config.version = 1;
148
+ writeConfig(config);
149
+ }
150
+ function resetConfig() {
151
+ try {
152
+ if (existsSync(CONFIG_PATH)) writeFileSync(CONFIG_PATH, "{}", { mode: 384 });
153
+ } catch {}
154
+ }
155
+ function getConfig() {
156
+ return readConfig();
157
+ }
158
+ export { JD_INTRANET_DEFAULTS as a, resolveExpectedNpmRegistry as c, resolveSdkPackageNameAsync as d, resolveSkillApiUrl as f, setBrokerUrl as i, resolveGitlabHosts as l, getConfig as n, isJdIntranetAvailable as o, resolveSkillApiUrlSync as p, resetConfig as r, probeJdIntranet as s, getBrokerUrl as t, resolveSdkPackageName as u };
@@ -1,42 +1,2 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
2
- import { dirname, join } from "path";
3
- import { homedir } from "os";
4
- const CONFIG_PATH = join(join(homedir(), ".jd-skills"), "config.json");
5
- function readConfig() {
6
- try {
7
- if (!existsSync(CONFIG_PATH)) return {};
8
- const raw = readFileSync(CONFIG_PATH, "utf-8");
9
- const parsed = JSON.parse(raw);
10
- if (typeof parsed !== "object" || parsed === null) return {};
11
- return parsed;
12
- } catch {
13
- return {};
14
- }
15
- }
16
- function writeConfig(config) {
17
- mkdirSync(dirname(CONFIG_PATH), { recursive: true });
18
- writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 384 });
19
- }
20
- function getBrokerUrl() {
21
- const envUrl = process.env.JD_BROKER_URL;
22
- if (envUrl && envUrl.trim().length > 0) return envUrl.trim().replace(/\/+$/, "");
23
- const fileConfig = readConfig();
24
- if (fileConfig.brokerUrl && fileConfig.brokerUrl.trim().length > 0) return fileConfig.brokerUrl.trim().replace(/\/+$/, "");
25
- return "";
26
- }
27
- function setBrokerUrl(url) {
28
- const config = readConfig();
29
- if (url && url.trim().length > 0) config.brokerUrl = url.trim().replace(/\/+$/, "");
30
- else delete config.brokerUrl;
31
- config.version = 1;
32
- writeConfig(config);
33
- }
34
- function resetConfig() {
35
- try {
36
- if (existsSync(CONFIG_PATH)) writeFileSync(CONFIG_PATH, "{}", { mode: 384 });
37
- } catch {}
38
- }
39
- function getConfig() {
40
- return readConfig();
41
- }
42
- export { setBrokerUrl as i, getConfig as n, resetConfig as r, getBrokerUrl as t };
1
+ import { i as setBrokerUrl, n as getConfig, r as resetConfig, t as getBrokerUrl } from "./config.mjs";
2
+ export { getBrokerUrl };
@@ -1,3 +1,3 @@
1
- import "./config2.mjs";
1
+ import "./config.mjs";
2
2
  import { a as getSdkPackageName, c as isBrokerSdkAvailable, i as getJdSourcePromptState, n as getCookieStatus, o as installSdkHint, r as getJdCookie, s as isBrokerReachable, t as clearJdCookie } from "./jd-cookie2.mjs";
3
3
  export { getJdCookie };
@@ -1,15 +1,17 @@
1
- import { t as getBrokerUrl } from "./config2.mjs";
1
+ import { d as resolveSdkPackageNameAsync, s as probeJdIntranet, t as getBrokerUrl, u as resolveSdkPackageName } from "./config.mjs";
2
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
3
3
  import { dirname, join } from "path";
4
4
  import { homedir } from "os";
5
5
  const CACHE_PATH = join(join(homedir(), ".jd-skills"), "cookies.json");
6
6
  const COOKIE_TTL_MS = 1440 * 60 * 1e3;
7
7
  function getSdkPackageName() {
8
- return (process.env.JD_BROKER_SDK_PACKAGE ?? "").trim();
8
+ return resolveSdkPackageName();
9
+ }
10
+ async function getSdkPackageNameResolved() {
11
+ return resolveSdkPackageNameAsync();
9
12
  }
10
13
  function installSdkHint() {
11
- const pkg = getSdkPackageName() || "<your-org>/<your-cookie-broker-sdk>";
12
- return `install ${pkg} from your private registry and set JD_BROKER_SDK_PACKAGE=${pkg.split("/")[0] + "/<sdk>"} in your env`;
14
+ return `install ${getSdkPackageName() || "@jd/jd-cookie-broker"} from your npm registry (on JD intranet: add registry = http://registry.m.jd.com to ~/.npmrc)`;
13
15
  }
14
16
  function readCache() {
15
17
  try {
@@ -33,7 +35,7 @@ async function getJdCookie(opts) {
33
35
  const cached = readCache();
34
36
  if (cached && cached.expiresAt > Date.now()) return cached.cookie;
35
37
  }
36
- const sdkPackage = getSdkPackageName();
38
+ const sdkPackage = await getSdkPackageNameResolved();
37
39
  if (!sdkPackage) return null;
38
40
  let loginFn = null;
39
41
  try {
@@ -73,7 +75,7 @@ function getCookieStatus() {
73
75
  };
74
76
  }
75
77
  async function isBrokerSdkAvailable() {
76
- const sdkPackage = getSdkPackageName();
78
+ const sdkPackage = await getSdkPackageNameResolved();
77
79
  if (!sdkPackage) return false;
78
80
  try {
79
81
  return typeof (await import(
@@ -95,10 +97,11 @@ async function isBrokerReachable(brokerUrl) {
95
97
  }
96
98
  }
97
99
  async function getJdSourcePromptState() {
100
+ if (!await probeJdIntranet()) return "unreachable";
98
101
  if (!await isBrokerSdkAvailable()) return "sdk_missing";
99
102
  const cookieStatus = getCookieStatus();
100
103
  if (cookieStatus.loggedIn && cookieStatus.remainingMs && cookieStatus.remainingMs > 0) return "logged_in";
101
- const { getBrokerUrl } = await import("./config.mjs");
104
+ const { getBrokerUrl } = await import("./config2.mjs");
102
105
  return await isBrokerReachable(getBrokerUrl()) ? "auth_required" : "unreachable";
103
106
  }
104
107
  function clearJdCookie() {
package/dist/cli.mjs CHANGED
@@ -2,13 +2,13 @@
2
2
  import { r as __toESM } from "./_chunks/rolldown-runtime.mjs";
3
3
  import { l as pD, u as require_picocolors } from "./_chunks/libs/@clack/core.mjs";
4
4
  import { a as Y, c as ve, i as Se, l as xe, n as M, o as be, r as Me, s as fe, t as Ie, u as ye } from "./_chunks/libs/@clack/prompts.mjs";
5
+ import { a as JD_INTRANET_DEFAULTS, c as resolveExpectedNpmRegistry, f as resolveSkillApiUrl, i as setBrokerUrl, l as resolveGitlabHosts, n as getConfig, o as isJdIntranetAvailable, p as resolveSkillApiUrlSync, r as resetConfig, s as probeJdIntranet, t as getBrokerUrl } from "./_chunks/config.mjs";
5
6
  import "./_chunks/libs/@kwsites/file-exists.mjs";
6
7
  import "./_chunks/libs/@kwsites/promise-deferred.mjs";
7
8
  import { t as esm_default } from "./_chunks/libs/simple-git.mjs";
8
9
  import { t as xdgConfig } from "./_chunks/libs/xdg-basedir.mjs";
9
10
  import { t as require_dist } from "./_chunks/libs/@vercel/detect-agent.mjs";
10
- import { i as setBrokerUrl, n as getConfig, r as resetConfig, t as getBrokerUrl } from "./_chunks/config2.mjs";
11
- import { c as isBrokerSdkAvailable, i as getJdSourcePromptState, n as getCookieStatus, o as installSdkHint, r as getJdCookie, t as clearJdCookie } from "./_chunks/jd-cookie2.mjs";
11
+ import { a as getSdkPackageName, c as isBrokerSdkAvailable, i as getJdSourcePromptState, n as getCookieStatus, o as installSdkHint, r as getJdCookie, t as clearJdCookie } from "./_chunks/jd-cookie2.mjs";
12
12
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "fs";
13
13
  import { execFile, execSync, spawn, spawnSync } from "child_process";
14
14
  import { basename, dirname, isAbsolute, join, normalize, relative, resolve, sep } from "path";
@@ -25,7 +25,7 @@ import { createHash as createHash$1 } from "node:crypto";
25
25
  import { gunzipSync, inflateRawSync } from "node:zlib";
26
26
  var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
27
27
  function getInternalGitlabHosts() {
28
- return (process.env.JD_GITLAB_HOSTS ?? "").split(",").map((h) => h.trim().toLowerCase()).filter((h) => h.length > 0).filter((h, i, arr) => arr.indexOf(h) === i);
28
+ return resolveGitlabHosts();
29
29
  }
30
30
  function getOwnerRepo(parsed) {
31
31
  if (parsed.type === "local") return null;
@@ -3046,7 +3046,7 @@ async function tryBlobInstall(ownerRepo, options = {}) {
3046
3046
  tree
3047
3047
  };
3048
3048
  }
3049
- var version$1 = "0.1.0";
3049
+ var version$1 = "0.1.1";
3050
3050
  const isCancelled$1 = (value) => typeof value === "symbol";
3051
3051
  async function isSourcePrivate(source) {
3052
3052
  const ownerRepo = parseOwnerRepo(source);
@@ -4061,13 +4061,16 @@ async function runAdd(args, options = {}) {
4061
4061
  if (error instanceof GitCloneError) {
4062
4062
  M.error(import_picocolors.default.red("Failed to clone repository"));
4063
4063
  for (const line of error.message.split("\n")) M.message(import_picocolors.default.dim(line));
4064
- if (parsed.type === "gitlab" && (process.env.JD_GITLAB_HOSTS ?? "").length > 0) {
4065
- const host = parsed.url.match(/^https?:\/\/([^/]+)/)?.[1] ?? "<host>";
4066
- M.message("");
4067
- M.message(import_picocolors.default.yellow(`Hint: search results may use account names that don't match the GitLab group on ${host}.`));
4068
- M.message(import_picocolors.default.yellow(`Try the full URL once you know the correct GitLab path:`));
4069
- M.message(import_picocolors.default.yellow(` jd-skills add https://${host}/<group>/<repo>`));
4070
- }
4064
+ try {
4065
+ const reparsed = parseSource(source);
4066
+ if (reparsed.type === "gitlab" && resolveGitlabHosts().length > 0) {
4067
+ const host = reparsed.url.match(/^https?:\/\/([^/]+)/)?.[1] ?? "<host>";
4068
+ M.message("");
4069
+ M.message(import_picocolors.default.yellow(`Hint: search results may use account names that don't match the GitLab group on ${host}.`));
4070
+ M.message(import_picocolors.default.yellow(`Try the full URL once you know the correct GitLab path:`));
4071
+ M.message(import_picocolors.default.yellow(` jd-skills add https://${host}/<group>/<repo>`));
4072
+ }
4073
+ } catch {}
4071
4074
  } else M.error(error instanceof Error ? error.message : "Unknown error occurred");
4072
4075
  showInstallTip();
4073
4076
  Se(import_picocolors.default.red("Installation failed"));
@@ -4159,9 +4162,6 @@ function parseAddOptions(args) {
4159
4162
  options
4160
4163
  };
4161
4164
  }
4162
- function getApiUrl() {
4163
- return (process.env.JD_SKILL_API_URL ?? "").trim();
4164
- }
4165
4165
  const REQUEST_TIMEOUT_MS = 5e3;
4166
4166
  const DEFAULT_PAGE_SIZE = 24;
4167
4167
  async function searchJdSkills(query, opts = {}) {
@@ -4172,7 +4172,7 @@ async function searchJdSkills(query, opts = {}) {
4172
4172
  cookie = null;
4173
4173
  }
4174
4174
  let res;
4175
- const apiUrl = getApiUrl();
4175
+ const apiUrl = await resolveSkillApiUrl();
4176
4176
  if (!apiUrl) return { kind: "unreachable" };
4177
4177
  try {
4178
4178
  res = await fetch(apiUrl, {
@@ -4260,6 +4260,7 @@ async function searchUpstreamSkills(query) {
4260
4260
  }
4261
4261
  }
4262
4262
  async function searchSkillsAPI(query) {
4263
+ await probeJdIntranet();
4263
4264
  const [upstream, jdResult] = await Promise.all([searchUpstreamSkills(query).catch(() => []), searchJdSkills(query).catch(() => ({ kind: "unreachable" }))]);
4264
4265
  const jdSkills = jdResult && jdResult.kind === "results" ? jdResult.skills.map((s) => ({
4265
4266
  name: sanitizeMetadata(s.nameEn || s.alias),
@@ -4280,13 +4281,14 @@ async function searchSkillsAPI(query) {
4280
4281
  }
4281
4282
  let _jdIssueLogged = null;
4282
4283
  function surfaceJdSourceIssue(jdResult) {
4284
+ if (!isJdIntranetAvailable()) return;
4283
4285
  if (!jdResult) return;
4284
4286
  if (jdResult.kind === "results") return;
4287
+ if (jdResult.kind === "unreachable") return;
4285
4288
  if (_jdIssueLogged && _jdIssueLogged !== jdIssueKind(jdResult)) {}
4286
4289
  if (_jdIssueLogged === jdIssueKind(jdResult)) return;
4287
4290
  _jdIssueLogged = jdIssueKind(jdResult);
4288
- if (jdResult.kind === "unreachable") process.stderr.write(`${DIM$3}┄${RESET$3} ${DIM$3}JD marketplace unreachable (running outside JD network?)${RESET$3}\n`);
4289
- else if (jdResult.kind === "auth_required") {
4291
+ if (jdResult.kind === "auth_required") {
4290
4292
  if (!process.stdin.isTTY) process.stderr.write(`${YELLOW$1}┄${RESET$3} ${YELLOW$1}JD marketplace requires login.${RESET$3} ${DIM$3}Run ${TEXT$2}jd-skills login${RESET$3}${DIM$3} to authenticate.${RESET$3}\n`);
4291
4293
  } else if (jdResult.kind === "error") process.stderr.write(`${RED}┄${RESET$3} ${RED}JD marketplace error: ${jdResult.message}${RESET$3}\n`);
4292
4294
  }
@@ -4430,6 +4432,30 @@ function getOwnerRepoFromString(pkg) {
4430
4432
  async function isRepoPublic(owner, repo) {
4431
4433
  return await isRepoPrivate(owner, repo) === false;
4432
4434
  }
4435
+ async function offerJdLoginPrompt(query) {
4436
+ if (!process.stdin.isTTY) return;
4437
+ if (!await probeJdIntranet()) return;
4438
+ if (await getJdSourcePromptState() !== "auth_required") return;
4439
+ console.log(`${YELLOW$1}┄${RESET$3} ${YELLOW$1}JD marketplace is reachable but you're not logged in.${RESET$3} ${DIM$3}Log in now to also see internal skills?${RESET$3}`);
4440
+ if (!await promptYesNo(" Log in? [Y/n]: ")) return;
4441
+ const { getJdCookie } = await import("./_chunks/jd-cookie.mjs");
4442
+ if (!!!await getJdCookie({ forceRefresh: true })) {
4443
+ console.log(`${DIM$3}Login cancelled or failed.${RESET$3} You can retry with: jd-skills login`);
4444
+ return;
4445
+ }
4446
+ console.log(`${TEXT$2}✓${RESET$3} Logged in.${query ? " Re-running search with JD results..." : ""}`);
4447
+ if (!query) return;
4448
+ const jdOnly = (await searchSkillsAPI(query)).filter((s) => s.origin === "jd");
4449
+ if (jdOnly.length > 0) {
4450
+ console.log();
4451
+ console.log(`${YELLOW$1}JD results:${RESET$3}`);
4452
+ for (const skill of jdOnly.slice(0, 6)) {
4453
+ const installs = formatInstalls(skill.installs);
4454
+ console.log(`${YELLOW$1}[jd]${RESET$3} ${TEXT$2}${skill.ownerErp}@${skill.name}${RESET$3}${installs ? ` ${CYAN$1}${installs}${RESET$3}` : ""}`);
4455
+ console.log(`${DIM$3}└ ★${skill.starScore?.toFixed(2) ?? "—"} ${skill.category1Name ?? ""}${RESET$3}`);
4456
+ }
4457
+ } else console.log(`${DIM$3}No JD results for "${query}".${RESET$3}`);
4458
+ }
4433
4459
  async function runFind(args) {
4434
4460
  const query = args.join(" ");
4435
4461
  const isNonInteractive = !process.stdin.isTTY;
@@ -4445,6 +4471,7 @@ ${DIM$3} 2) npx jd-skills add <owner/repo@skill>${RESET$3}`;
4445
4471
  });
4446
4472
  if (results.length === 0) {
4447
4473
  console.log(`${DIM$3}No skills found for "${query}"${RESET$3}`);
4474
+ await offerJdLoginPrompt(query);
4448
4475
  return;
4449
4476
  }
4450
4477
  if (results.some((s) => s.origin === "jd")) console.log(`${DIM$3}Legend:${RESET$3} ${YELLOW$1}[jd]${RESET$3} ${DIM$3}= JD internal marketplace${RESET$3}`);
@@ -4463,27 +4490,7 @@ ${DIM$3} 2) npx jd-skills add <owner/repo@skill>${RESET$3}`;
4463
4490
  }
4464
4491
  console.log();
4465
4492
  }
4466
- if (process.stdin.isTTY) {
4467
- if (await getJdSourcePromptState() === "auth_required") {
4468
- console.log(`${YELLOW$1}┄${RESET$3} ${YELLOW$1}JD marketplace is reachable but you're not logged in.${RESET$3} ${DIM$3}Log in now to also see internal skills?${RESET$3}`);
4469
- if (await promptYesNo(" Log in? [Y/n]: ")) {
4470
- const { getJdCookie } = await import("./_chunks/jd-cookie.mjs");
4471
- if (!!await getJdCookie({ forceRefresh: true })) {
4472
- console.log(`${TEXT$2}✓${RESET$3} Logged in. Re-running search with JD results...`);
4473
- const jdOnly = (await searchSkillsAPI(query)).filter((s) => s.origin === "jd");
4474
- if (jdOnly.length > 0) {
4475
- console.log();
4476
- console.log(`${YELLOW$1}JD results:${RESET$3}`);
4477
- for (const skill of jdOnly.slice(0, 6)) {
4478
- const installs = formatInstalls(skill.installs);
4479
- console.log(`${YELLOW$1}[jd]${RESET$3} ${TEXT$2}${skill.ownerErp}@${skill.name}${RESET$3}${installs ? ` ${CYAN$1}${installs}${RESET$3}` : ""}`);
4480
- console.log(`${DIM$3}└ ★${skill.starScore?.toFixed(2) ?? "—"} ${skill.category1Name ?? ""}${RESET$3}`);
4481
- }
4482
- } else console.log(`${DIM$3}No JD results for "${query}".${RESET$3}`);
4483
- } else console.log(`${DIM$3}Login cancelled or failed.${RESET$3} You can retry with: jd-skills login`);
4484
- }
4485
- }
4486
- }
4493
+ await offerJdLoginPrompt(query);
4487
4494
  return;
4488
4495
  }
4489
4496
  if (isNonInteractive || await isRunningInAgent()) {
@@ -4492,6 +4499,7 @@ ${DIM$3} 2) npx jd-skills add <owner/repo@skill>${RESET$3}`;
4492
4499
  console.log(`${DIM$3}Usage: npx jd-skills find <query>${RESET$3}`);
4493
4500
  return;
4494
4501
  }
4502
+ await offerJdLoginPrompt();
4495
4503
  const selected = await runSearchPrompt();
4496
4504
  track({
4497
4505
  event: "find",
@@ -4539,7 +4547,7 @@ async function showJdDetailsAndInstall(selected) {
4539
4547
  }
4540
4548
  console.log();
4541
4549
  const installCmd = `jd:${d.owner}/${selected.name}`;
4542
- const apiUrl = process.env.JD_SKILL_API_URL ?? "";
4550
+ const apiUrl = resolveSkillApiUrlSync();
4543
4551
  const webUiUrl = apiUrl ? apiUrl.replace(/\/api\/.*$/, `/skill/${d.skillCode}`) : "";
4544
4552
  console.log(`${DIM$3}To install (best-effort: account name may not match the GitLab group):${RESET$3}\n npx jd-skills add ${installCmd}`);
4545
4553
  if (webUiUrl) console.log(`${DIM$3}Or open in browser:${RESET$3}\n ${webUiUrl}`);
@@ -6117,12 +6125,12 @@ const BOLD = "\x1B[1m";
6117
6125
  const DIM = "\x1B[38;5;102m";
6118
6126
  const TEXT = "\x1B[38;5;145m";
6119
6127
  const LOGO_LINES = [
6120
- "███████╗██╗ ██╗██╗██╗ ██╗ ███████╗",
6121
- "██╔════╝██║ ██╔╝██║██║ ██║ ██╔════╝",
6122
- "███████╗█████╔╝ ██║██║ ██║ ███████╗",
6123
- "╚════██║██╔═██╗ ██║██║ ██║ ╚════██║",
6124
- "███████║██║ ██╗██║███████╗███████╗███████║",
6125
- "╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚══════╝"
6128
+ " ██╗██████╗ ███████╗██╗ ██╗██╗██╗ ██╗ ███████╗",
6129
+ " ██║██╔══██╗ ██╔════╝██║ ██╔╝██║██║ ██║ ██╔════╝",
6130
+ " ██║██║ ██║█████╗███████╗█████╔╝ ██║██║ ██║ ███████╗",
6131
+ "██ ██║██║ ██║╚════╝╚════██║██╔═██╗ ██║██║ ██║ ╚════██║",
6132
+ "╚█████╔╝██████╔╝ ███████║██║ ██╗██║███████╗███████╗███████║",
6133
+ " ╚════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚══════╝"
6126
6134
  ];
6127
6135
  const GRAYS = [
6128
6136
  "\x1B[38;5;250m",
@@ -6406,21 +6414,53 @@ async function runDoctor() {
6406
6414
  console.log(`${BOLD}jd-skills doctor${RESET}`);
6407
6415
  console.log(`${DIM}JD marketplace setup diagnostic (read-only, no installs)${RESET}`);
6408
6416
  console.log();
6417
+ if (!await probeJdIntranet()) {
6418
+ console.log(`${DIM}JD intranet not detected${RESET} — marketplace probe to ${JD_INTRANET_DEFAULTS.skillApiUrl} failed.`);
6419
+ console.log(`${DIM}Upstream skills (skills.sh) still work. Connect to JD VPN/network and re-run doctor, or set JD_SKILL_API_URL to override.${RESET}`);
6420
+ console.log();
6421
+ return;
6422
+ }
6409
6423
  const checks = [];
6410
- const npmRegistry = await getNpmRegistry();
6411
- const registryOk = npmRegistry.replace(/\/+$/, "") === JD_BROKER_SDK_REGISTRY.replace(/\/+$/, "");
6424
+ const skillApiUrl = await resolveSkillApiUrl();
6425
+ const sdkPackage = getSdkPackageName();
6426
+ const expectedRegistry = resolveExpectedNpmRegistry();
6412
6427
  checks.push({
6413
- label: "npm registry configured",
6414
- ok: registryOk,
6415
- detail: registryOk ? `registry = ${npmRegistry}` : `registry = ${npmRegistry} ${DIM}(expected ${JD_BROKER_SDK_REGISTRY})${RESET}`,
6416
- fix: registryOk ? void 0 : `Add this line to ~/.npmrc:\n registry = ${JD_BROKER_SDK_REGISTRY}\n Then re-run npx jd-skills.`
6428
+ label: "JD intranet detected",
6429
+ ok: true,
6430
+ detail: `marketplace reachable (auto: ${JD_INTRANET_DEFAULTS.skillApiUrl})`
6417
6431
  });
6418
- const sdkOk = await isBrokerSdkAvailable();
6419
6432
  checks.push({
6420
- label: `${JD_BROKER_SDK_PACKAGE} SDK loadable`,
6433
+ label: "JD skill search API",
6434
+ ok: skillApiUrl.length > 0,
6435
+ detail: skillApiUrl || "unavailable after probe",
6436
+ fix: skillApiUrl.length > 0 ? void 0 : `Set JD_SKILL_API_URL only if the default marketplace URL is wrong for your environment.`
6437
+ });
6438
+ checks.push({
6439
+ label: "cookie-broker SDK package",
6440
+ ok: sdkPackage.length > 0,
6441
+ detail: sdkPackage || "not resolved (unexpected on intranet)",
6442
+ fix: sdkPackage.length > 0 ? void 0 : `Set JD_BROKER_SDK_PACKAGE only if you use a forked SDK name.`
6443
+ });
6444
+ const npmRegistry = await getNpmRegistry();
6445
+ if (expectedRegistry) {
6446
+ const registryOk = npmRegistry.replace(/\/+$/, "") === expectedRegistry.replace(/\/+$/, "");
6447
+ checks.push({
6448
+ label: "npm registry configured",
6449
+ ok: registryOk,
6450
+ detail: registryOk ? `registry = ${npmRegistry}` : `registry = ${npmRegistry} ${DIM}(expected ${expectedRegistry})${RESET}`,
6451
+ fix: registryOk ? void 0 : `Add this line to ~/.npmrc:\n registry = ${expectedRegistry}\n Or export JD_NPM_REGISTRY=${expectedRegistry} and re-run jd-skills doctor.`
6452
+ });
6453
+ } else checks.push({
6454
+ label: "npm registry (informational)",
6455
+ ok: true,
6456
+ detail: `registry = ${npmRegistry} ${DIM}(intranet default: ${JD_INTRANET_DEFAULTS.npmRegistry})${RESET}`
6457
+ });
6458
+ const sdkOk = sdkPackage.length > 0 ? await isBrokerSdkAvailable() : false;
6459
+ checks.push({
6460
+ label: sdkPackage ? `${sdkPackage} SDK loadable` : "cookie-broker SDK loadable",
6421
6461
  ok: sdkOk,
6422
- detail: sdkOk ? `dynamic import() succeeded` : `${JD_BROKER_SDK_PACKAGE} not found in this run's node_modules`,
6423
- fix: sdkOk ? void 0 : `This package is on JD's private registry. After fixing #1 above, run npx jd-skills again npm will install the optional dep into the npx cache.`
6462
+ detail: sdkOk ? `dynamic import() succeeded` : sdkPackage ? `${sdkPackage} not found in this run's node_modules` : "skipped (SDK package not resolved)",
6463
+ fix: sdkOk ? void 0 : sdkPackage ? `${installSdkHint()}. After fixing ~/.npmrc, re-run npx jd-skills.` : `Unexpected on intranet contact your platform team.`
6424
6464
  });
6425
6465
  const cookieStatus = getCookieStatus();
6426
6466
  if (!sdkOk) checks.push({
@@ -6443,13 +6483,21 @@ async function runDoctor() {
6443
6483
  fix: `Run jd-skills login to authenticate.`
6444
6484
  });
6445
6485
  const broker = getBrokerUrl();
6446
- const brokerOk = await isUrlReachable(broker);
6447
- checks.push({
6448
- label: "broker reachable",
6449
- ok: brokerOk,
6450
- detail: brokerOk ? `HEAD ${broker} 2xx/3xx` : `HEAD ${broker} unreachable (network or DNS)`,
6451
- fix: brokerOk ? void 0 : `Check your network. If you're outside JD's intranet, JD source is expected to be unreachable — jd-skills will still work for upstream skills.`
6486
+ if (!broker) checks.push({
6487
+ label: "SSO broker URL",
6488
+ ok: false,
6489
+ detail: "not resolved (unexpected on intranet)",
6490
+ fix: `Run jd-skills config set-broker <url> or set JD_BROKER_URL to override the default.`
6452
6491
  });
6492
+ else {
6493
+ const brokerOk = await isUrlReachable(broker);
6494
+ checks.push({
6495
+ label: "SSO broker reachable",
6496
+ ok: brokerOk,
6497
+ detail: brokerOk ? `${broker} (auto-detected on intranet)` : `HEAD ${broker} → unreachable (network or DNS)`,
6498
+ fix: brokerOk ? void 0 : `Check VPN/network, or jd-skills config set-broker <url> if your broker host differs.`
6499
+ });
6500
+ }
6453
6501
  let allOk = true;
6454
6502
  for (const c of checks) {
6455
6503
  const mark = c.ok ? `${TEXT}✓${RESET}` : `${TEXT}✗${RESET}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jd-skills",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "CLI for the agent skills ecosystem (JD fork of vercel-labs/skills)",
5
5
  "type": "module",
6
6
  "bin": {