jd-skills 0.1.0 → 0.1.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.
- package/dist/_chunks/libs/@clack/core.mjs +1 -1
- package/dist/_chunks/libs/@clack/prompts.mjs +1 -1
- package/dist/_chunks/libs/@kwsites/file-exists.mjs +1 -1
- package/dist/_chunks/libs/@vercel/detect-agent.mjs +1 -1
- package/dist/_chunks/libs/simple-git.mjs +1 -1
- package/dist/_chunks/rolldown-runtime.mjs +10 -1
- package/dist/cli.mjs +448 -115
- package/package.json +2 -1
- package/dist/_chunks/config.mjs +0 -2
- package/dist/_chunks/config2.mjs +0 -42
- package/dist/_chunks/jd-cookie.mjs +0 -3
- package/dist/_chunks/jd-cookie2.mjs +0 -109
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as __toESM, t as __commonJSMin } from "../../rolldown-runtime.mjs";
|
|
2
2
|
import { stdin, stdout } from "node:process";
|
|
3
3
|
import * as g from "node:readline";
|
|
4
4
|
import O from "node:readline";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as __toESM } from "../../rolldown-runtime.mjs";
|
|
2
2
|
import { a as SD, c as fD, d as require_src, i as RD, l as pD, n as LD, o as _D, r as MD, s as dD, t as ID, u as require_picocolors } from "./core.mjs";
|
|
3
3
|
import { stripVTControlCharacters } from "node:util";
|
|
4
4
|
import y from "node:process";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { r as __require, t as __commonJSMin } from "../../rolldown-runtime.mjs";
|
|
2
2
|
var require_dist = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as __toESM } from "../rolldown-runtime.mjs";
|
|
2
2
|
import { n as require_src, t as require_dist } from "./@kwsites/file-exists.mjs";
|
|
3
3
|
import { t as require_dist$1 } from "./@kwsites/promise-deferred.mjs";
|
|
4
4
|
import { spawn } from "child_process";
|
|
@@ -6,6 +6,15 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
8
|
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
9
|
+
var __exportAll = (all, symbols) => {
|
|
10
|
+
let target = {};
|
|
11
|
+
for (var name in all) __defProp(target, name, {
|
|
12
|
+
get: all[name],
|
|
13
|
+
enumerable: true
|
|
14
|
+
});
|
|
15
|
+
if (symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
16
|
+
return target;
|
|
17
|
+
};
|
|
9
18
|
var __copyProps = (to, from, except, desc) => {
|
|
10
19
|
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
20
|
key = keys[i];
|
|
@@ -21,4 +30,4 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
30
|
enumerable: true
|
|
22
31
|
}) : target, mod));
|
|
23
32
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
24
|
-
export {
|
|
33
|
+
export { __toESM as i, __exportAll as n, __require as r, __commonJSMin as t };
|
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { i as __toESM, n as __exportAll } 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
5
|
import "./_chunks/libs/@kwsites/file-exists.mjs";
|
|
@@ -7,8 +7,6 @@ import "./_chunks/libs/@kwsites/promise-deferred.mjs";
|
|
|
7
7
|
import { t as esm_default } from "./_chunks/libs/simple-git.mjs";
|
|
8
8
|
import { t as xdgConfig } from "./_chunks/libs/xdg-basedir.mjs";
|
|
9
9
|
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";
|
|
12
10
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "fs";
|
|
13
11
|
import { execFile, execSync, spawn, spawnSync } from "child_process";
|
|
14
12
|
import { basename, dirname, isAbsolute, join, normalize, relative, resolve, sep } from "path";
|
|
@@ -24,8 +22,120 @@ import { createHash } from "crypto";
|
|
|
24
22
|
import { createHash as createHash$1 } from "node:crypto";
|
|
25
23
|
import { gunzipSync, inflateRawSync } from "node:zlib";
|
|
26
24
|
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
25
|
+
const JD_INTRANET_DEFAULTS = {
|
|
26
|
+
skillApiUrl: "https://mkt-skill-manager.jd.com/api/skill/public/sorted-list",
|
|
27
|
+
brokerUrl: "https://cbroker.jd.com",
|
|
28
|
+
sdkPackage: "@jd/jd-cookie-broker",
|
|
29
|
+
gitlabHosts: ["coding.jd.com"],
|
|
30
|
+
npmRegistry: "http://registry.m.jd.com"
|
|
31
|
+
};
|
|
32
|
+
const PROBE_CACHE_PATH = join(homedir(), ".jd-skills", "intranet-probe.json");
|
|
33
|
+
const PROBE_TTL_MS = 3600 * 1e3;
|
|
34
|
+
const PROBE_NEGATIVE_TTL_MS = 300 * 1e3;
|
|
35
|
+
const PROBE_TIMEOUT_MS = 5e3;
|
|
36
|
+
let memoryProbe = null;
|
|
37
|
+
let inFlightProbe = null;
|
|
38
|
+
function readDiskProbe() {
|
|
39
|
+
try {
|
|
40
|
+
if (!existsSync(PROBE_CACHE_PATH)) return null;
|
|
41
|
+
const parsed = JSON.parse(readFileSync(PROBE_CACHE_PATH, "utf-8"));
|
|
42
|
+
if (typeof parsed.available !== "boolean" || typeof parsed.checkedAt !== "number") return null;
|
|
43
|
+
if (Date.now() - parsed.checkedAt > (parsed.available ? PROBE_TTL_MS : PROBE_NEGATIVE_TTL_MS)) return null;
|
|
44
|
+
return parsed;
|
|
45
|
+
} catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function writeDiskProbe(available) {
|
|
50
|
+
try {
|
|
51
|
+
mkdirSync(dirname(PROBE_CACHE_PATH), { recursive: true });
|
|
52
|
+
writeFileSync(PROBE_CACHE_PATH, JSON.stringify({
|
|
53
|
+
available,
|
|
54
|
+
checkedAt: Date.now()
|
|
55
|
+
}, null, 2), { mode: 384 });
|
|
56
|
+
} catch {}
|
|
57
|
+
}
|
|
58
|
+
function setProbeResult(available) {
|
|
59
|
+
memoryProbe = available;
|
|
60
|
+
writeDiskProbe(available);
|
|
61
|
+
return available;
|
|
62
|
+
}
|
|
63
|
+
function getJdIntranetProbeSync() {
|
|
64
|
+
if (memoryProbe !== null) return memoryProbe;
|
|
65
|
+
const cached = readDiskProbe();
|
|
66
|
+
if (!cached) return null;
|
|
67
|
+
memoryProbe = cached.available;
|
|
68
|
+
return cached.available;
|
|
69
|
+
}
|
|
70
|
+
async function urlReachable(url, method) {
|
|
71
|
+
try {
|
|
72
|
+
return (await fetch(url, {
|
|
73
|
+
method,
|
|
74
|
+
signal: AbortSignal.timeout(PROBE_TIMEOUT_MS)
|
|
75
|
+
})).status < 500;
|
|
76
|
+
} catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function probeMarketplaceReachable(apiUrl) {
|
|
81
|
+
if (await urlReachable(apiUrl, "HEAD")) return true;
|
|
82
|
+
if (await urlReachable(apiUrl, "GET")) return true;
|
|
83
|
+
if (await urlReachable(JD_INTRANET_DEFAULTS.brokerUrl, "HEAD")) return true;
|
|
84
|
+
try {
|
|
85
|
+
const origin = new URL(apiUrl).origin;
|
|
86
|
+
if (await urlReachable(origin, "HEAD")) return true;
|
|
87
|
+
} catch {}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
async function probeJdIntranet(force = false) {
|
|
91
|
+
if (!force && memoryProbe !== null) return memoryProbe;
|
|
92
|
+
if (!force) {
|
|
93
|
+
const cached = readDiskProbe();
|
|
94
|
+
if (cached) {
|
|
95
|
+
memoryProbe = cached.available;
|
|
96
|
+
return cached.available;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (!force && inFlightProbe) return inFlightProbe;
|
|
100
|
+
inFlightProbe = (async () => {
|
|
101
|
+
return setProbeResult(await probeMarketplaceReachable((process.env.JD_SKILL_API_URL ?? "").trim() || JD_INTRANET_DEFAULTS.skillApiUrl));
|
|
102
|
+
})();
|
|
103
|
+
try {
|
|
104
|
+
return await inFlightProbe;
|
|
105
|
+
} finally {
|
|
106
|
+
inFlightProbe = null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function isJdIntranetAvailable() {
|
|
110
|
+
return getJdIntranetProbeSync() === true;
|
|
111
|
+
}
|
|
112
|
+
async function resolveSkillApiUrl() {
|
|
113
|
+
const env = (process.env.JD_SKILL_API_URL ?? "").trim();
|
|
114
|
+
if (env) return env;
|
|
115
|
+
if (await probeJdIntranet()) return JD_INTRANET_DEFAULTS.skillApiUrl;
|
|
116
|
+
return "";
|
|
117
|
+
}
|
|
118
|
+
function resolveSkillApiUrlSync() {
|
|
119
|
+
const env = (process.env.JD_SKILL_API_URL ?? "").trim();
|
|
120
|
+
if (env) return env;
|
|
121
|
+
if (isJdIntranetAvailable()) return JD_INTRANET_DEFAULTS.skillApiUrl;
|
|
122
|
+
return "";
|
|
123
|
+
}
|
|
124
|
+
function resolveBrokerUrlFromIntranet(fileBrokerUrl) {
|
|
125
|
+
const envUrl = (process.env.JD_BROKER_URL ?? "").trim();
|
|
126
|
+
if (envUrl) return envUrl.replace(/\/+$/, "");
|
|
127
|
+
if (fileBrokerUrl) return fileBrokerUrl;
|
|
128
|
+
if (isJdIntranetAvailable()) return JD_INTRANET_DEFAULTS.brokerUrl;
|
|
129
|
+
return "";
|
|
130
|
+
}
|
|
131
|
+
function resolveGitlabHosts() {
|
|
132
|
+
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);
|
|
133
|
+
if (fromEnv.length > 0) return fromEnv;
|
|
134
|
+
if (isJdIntranetAvailable()) return [...JD_INTRANET_DEFAULTS.gitlabHosts];
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
27
137
|
function getInternalGitlabHosts() {
|
|
28
|
-
return (
|
|
138
|
+
return resolveGitlabHosts();
|
|
29
139
|
}
|
|
30
140
|
function getOwnerRepo(parsed) {
|
|
31
141
|
if (parsed.type === "local") return null;
|
|
@@ -3046,7 +3156,7 @@ async function tryBlobInstall(ownerRepo, options = {}) {
|
|
|
3046
3156
|
tree
|
|
3047
3157
|
};
|
|
3048
3158
|
}
|
|
3049
|
-
var version$1 = "0.1.
|
|
3159
|
+
var version$1 = "0.1.2";
|
|
3050
3160
|
const isCancelled$1 = (value) => typeof value === "symbol";
|
|
3051
3161
|
async function isSourcePrivate(source) {
|
|
3052
3162
|
const ownerRepo = parseOwnerRepo(source);
|
|
@@ -4061,13 +4171,16 @@ async function runAdd(args, options = {}) {
|
|
|
4061
4171
|
if (error instanceof GitCloneError) {
|
|
4062
4172
|
M.error(import_picocolors.default.red("Failed to clone repository"));
|
|
4063
4173
|
for (const line of error.message.split("\n")) M.message(import_picocolors.default.dim(line));
|
|
4064
|
-
|
|
4065
|
-
const
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4174
|
+
try {
|
|
4175
|
+
const reparsed = parseSource(source);
|
|
4176
|
+
if (reparsed.type === "gitlab" && resolveGitlabHosts().length > 0) {
|
|
4177
|
+
const host = reparsed.url.match(/^https?:\/\/([^/]+)/)?.[1] ?? "<host>";
|
|
4178
|
+
M.message("");
|
|
4179
|
+
M.message(import_picocolors.default.yellow(`Hint: search results may use account names that don't match the GitLab group on ${host}.`));
|
|
4180
|
+
M.message(import_picocolors.default.yellow(`Try the full URL once you know the correct GitLab path:`));
|
|
4181
|
+
M.message(import_picocolors.default.yellow(` jd-skills add https://${host}/<group>/<repo>`));
|
|
4182
|
+
}
|
|
4183
|
+
} catch {}
|
|
4071
4184
|
} else M.error(error instanceof Error ? error.message : "Unknown error occurred");
|
|
4072
4185
|
showInstallTip();
|
|
4073
4186
|
Se(import_picocolors.default.red("Installation failed"));
|
|
@@ -4159,8 +4272,189 @@ function parseAddOptions(args) {
|
|
|
4159
4272
|
options
|
|
4160
4273
|
};
|
|
4161
4274
|
}
|
|
4162
|
-
|
|
4163
|
-
|
|
4275
|
+
const CONFIG_PATH = join(join(homedir(), ".jd-skills"), "config.json");
|
|
4276
|
+
function readConfig() {
|
|
4277
|
+
try {
|
|
4278
|
+
if (!existsSync(CONFIG_PATH)) return {};
|
|
4279
|
+
const raw = readFileSync(CONFIG_PATH, "utf-8");
|
|
4280
|
+
const parsed = JSON.parse(raw);
|
|
4281
|
+
if (typeof parsed !== "object" || parsed === null) return {};
|
|
4282
|
+
return parsed;
|
|
4283
|
+
} catch {
|
|
4284
|
+
return {};
|
|
4285
|
+
}
|
|
4286
|
+
}
|
|
4287
|
+
function writeConfig(config) {
|
|
4288
|
+
mkdirSync(dirname(CONFIG_PATH), { recursive: true });
|
|
4289
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 384 });
|
|
4290
|
+
}
|
|
4291
|
+
function getBrokerUrl() {
|
|
4292
|
+
const fileConfig = readConfig();
|
|
4293
|
+
return resolveBrokerUrlFromIntranet(fileConfig.brokerUrl && fileConfig.brokerUrl.trim().length > 0 ? fileConfig.brokerUrl.trim().replace(/\/+$/, "") : "");
|
|
4294
|
+
}
|
|
4295
|
+
function setBrokerUrl(url) {
|
|
4296
|
+
const config = readConfig();
|
|
4297
|
+
if (url && url.trim().length > 0) config.brokerUrl = url.trim().replace(/\/+$/, "");
|
|
4298
|
+
else delete config.brokerUrl;
|
|
4299
|
+
config.version = 1;
|
|
4300
|
+
writeConfig(config);
|
|
4301
|
+
}
|
|
4302
|
+
function resetConfig() {
|
|
4303
|
+
try {
|
|
4304
|
+
if (existsSync(CONFIG_PATH)) writeFileSync(CONFIG_PATH, "{}", { mode: 384 });
|
|
4305
|
+
} catch {}
|
|
4306
|
+
}
|
|
4307
|
+
function getConfig() {
|
|
4308
|
+
return readConfig();
|
|
4309
|
+
}
|
|
4310
|
+
const DEFAULT_BROKER_URL = "https://cbroker.jd.com";
|
|
4311
|
+
function normUrl(url) {
|
|
4312
|
+
return String(url || DEFAULT_BROKER_URL).replace(/\/+$/, "");
|
|
4313
|
+
}
|
|
4314
|
+
async function httpJson(url, init = {}) {
|
|
4315
|
+
const response = await fetch(url, init);
|
|
4316
|
+
const payload = (response.headers.get("content-type") || "").includes("application/json") ? await response.json() : await response.text();
|
|
4317
|
+
if (!response.ok) {
|
|
4318
|
+
const message = typeof payload === "string" ? payload : payload.message || JSON.stringify(payload);
|
|
4319
|
+
throw new Error(`HTTP ${response.status}: ${message}`);
|
|
4320
|
+
}
|
|
4321
|
+
return payload;
|
|
4322
|
+
}
|
|
4323
|
+
async function createSession({ brokerUrl, appId } = {}) {
|
|
4324
|
+
const base = normUrl(brokerUrl);
|
|
4325
|
+
const id = appId || `jd-skills-${Date.now()}`;
|
|
4326
|
+
return httpJson(`${base}/v1/sessions/create?appId=${encodeURIComponent(id)}`);
|
|
4327
|
+
}
|
|
4328
|
+
async function getSession({ brokerUrl, sessionId }) {
|
|
4329
|
+
return httpJson(`${normUrl(brokerUrl)}/v1/sessions/${encodeURIComponent(sessionId)}`);
|
|
4330
|
+
}
|
|
4331
|
+
async function claimCookie({ brokerUrl, sessionId, claimToken }) {
|
|
4332
|
+
return httpJson(`${normUrl(brokerUrl)}/v1/sessions/${encodeURIComponent(sessionId)}/claim?claimToken=${encodeURIComponent(claimToken)}`);
|
|
4333
|
+
}
|
|
4334
|
+
async function waitUntilReady({ brokerUrl, sessionId, timeoutMs = 18e4, intervalMs = 1500 }) {
|
|
4335
|
+
const started = Date.now();
|
|
4336
|
+
while (Date.now() - started < timeoutMs) {
|
|
4337
|
+
const session = await getSession({
|
|
4338
|
+
brokerUrl,
|
|
4339
|
+
sessionId
|
|
4340
|
+
});
|
|
4341
|
+
if (session.status === "READY") {
|
|
4342
|
+
if (!session.claimToken) throw new Error("会话 READY 但缺少 claimToken");
|
|
4343
|
+
return {
|
|
4344
|
+
...session,
|
|
4345
|
+
claimToken: session.claimToken
|
|
4346
|
+
};
|
|
4347
|
+
}
|
|
4348
|
+
if (session.status === "EXPIRED" || session.status === "CLAIMED") throw new Error(`会话不可用,当前状态: ${session.status}`);
|
|
4349
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
4350
|
+
}
|
|
4351
|
+
throw new Error("等待超时,请重新发起登录流程");
|
|
4352
|
+
}
|
|
4353
|
+
async function login(opts = {}) {
|
|
4354
|
+
const { brokerUrl, appId, open: autoOpen = true, timeoutMs, intervalMs, onLoginUrl } = opts;
|
|
4355
|
+
const created = await createSession({
|
|
4356
|
+
brokerUrl,
|
|
4357
|
+
appId
|
|
4358
|
+
});
|
|
4359
|
+
onLoginUrl?.(created.loginUrl);
|
|
4360
|
+
if (autoOpen) {
|
|
4361
|
+
const { default: openBrowser } = await import("open");
|
|
4362
|
+
await openBrowser(created.loginUrl);
|
|
4363
|
+
}
|
|
4364
|
+
const ready = await waitUntilReady({
|
|
4365
|
+
brokerUrl,
|
|
4366
|
+
sessionId: created.sessionId,
|
|
4367
|
+
timeoutMs,
|
|
4368
|
+
intervalMs
|
|
4369
|
+
});
|
|
4370
|
+
return (await claimCookie({
|
|
4371
|
+
brokerUrl,
|
|
4372
|
+
sessionId: created.sessionId,
|
|
4373
|
+
claimToken: ready.claimToken
|
|
4374
|
+
})).cookie;
|
|
4375
|
+
}
|
|
4376
|
+
var jd_cookie_exports = /* @__PURE__ */ __exportAll({
|
|
4377
|
+
clearJdCookie: () => clearJdCookie,
|
|
4378
|
+
getCookieStatus: () => getCookieStatus,
|
|
4379
|
+
getJdCookie: () => getJdCookie,
|
|
4380
|
+
getJdSourcePromptState: () => getJdSourcePromptState,
|
|
4381
|
+
isBrokerReachable: () => isBrokerReachable
|
|
4382
|
+
});
|
|
4383
|
+
const CACHE_PATH = join(join(homedir(), ".jd-skills"), "cookies.json");
|
|
4384
|
+
const COOKIE_TTL_MS = 1440 * 60 * 1e3;
|
|
4385
|
+
function readCache() {
|
|
4386
|
+
try {
|
|
4387
|
+
if (!existsSync(CACHE_PATH)) return null;
|
|
4388
|
+
const raw = readFileSync(CACHE_PATH, "utf-8");
|
|
4389
|
+
const parsed = JSON.parse(raw);
|
|
4390
|
+
if (typeof parsed.cookie !== "string" || typeof parsed.expiresAt !== "number") return null;
|
|
4391
|
+
return parsed;
|
|
4392
|
+
} catch {
|
|
4393
|
+
return null;
|
|
4394
|
+
}
|
|
4395
|
+
}
|
|
4396
|
+
function writeCache(entry) {
|
|
4397
|
+
try {
|
|
4398
|
+
mkdirSync(dirname(CACHE_PATH), { recursive: true });
|
|
4399
|
+
writeFileSync(CACHE_PATH, JSON.stringify(entry, null, 2), { mode: 384 });
|
|
4400
|
+
} catch {}
|
|
4401
|
+
}
|
|
4402
|
+
async function getJdCookie(opts) {
|
|
4403
|
+
if (!opts?.forceRefresh) {
|
|
4404
|
+
const cached = readCache();
|
|
4405
|
+
if (cached && cached.expiresAt > Date.now()) return cached.cookie;
|
|
4406
|
+
}
|
|
4407
|
+
if (!await probeJdIntranet()) return null;
|
|
4408
|
+
const brokerUrl = getBrokerUrl();
|
|
4409
|
+
if (!brokerUrl) return null;
|
|
4410
|
+
try {
|
|
4411
|
+
const cookie = await login({
|
|
4412
|
+
brokerUrl,
|
|
4413
|
+
open: true
|
|
4414
|
+
});
|
|
4415
|
+
if (typeof cookie === "string" && cookie.length > 0) {
|
|
4416
|
+
writeCache({
|
|
4417
|
+
cookie,
|
|
4418
|
+
expiresAt: Date.now() + COOKIE_TTL_MS,
|
|
4419
|
+
cachedAt: Date.now()
|
|
4420
|
+
});
|
|
4421
|
+
return cookie;
|
|
4422
|
+
}
|
|
4423
|
+
return null;
|
|
4424
|
+
} catch {
|
|
4425
|
+
return null;
|
|
4426
|
+
}
|
|
4427
|
+
}
|
|
4428
|
+
function getCookieStatus() {
|
|
4429
|
+
const cached = readCache();
|
|
4430
|
+
if (!cached) return { loggedIn: false };
|
|
4431
|
+
return {
|
|
4432
|
+
loggedIn: true,
|
|
4433
|
+
expiresAt: cached.expiresAt,
|
|
4434
|
+
remainingMs: cached.expiresAt - Date.now()
|
|
4435
|
+
};
|
|
4436
|
+
}
|
|
4437
|
+
async function isBrokerReachable(brokerUrl) {
|
|
4438
|
+
if (!brokerUrl) return false;
|
|
4439
|
+
try {
|
|
4440
|
+
return (await fetch(brokerUrl, {
|
|
4441
|
+
method: "HEAD",
|
|
4442
|
+
signal: AbortSignal.timeout(3e3)
|
|
4443
|
+
})).status < 500;
|
|
4444
|
+
} catch {
|
|
4445
|
+
return false;
|
|
4446
|
+
}
|
|
4447
|
+
}
|
|
4448
|
+
async function getJdSourcePromptState() {
|
|
4449
|
+
if (!await probeJdIntranet()) return "unreachable";
|
|
4450
|
+
const cookieStatus = getCookieStatus();
|
|
4451
|
+
if (cookieStatus.loggedIn && cookieStatus.remainingMs && cookieStatus.remainingMs > 0) return "logged_in";
|
|
4452
|
+
return await isBrokerReachable(getBrokerUrl()) ? "auth_required" : "unreachable";
|
|
4453
|
+
}
|
|
4454
|
+
function clearJdCookie() {
|
|
4455
|
+
try {
|
|
4456
|
+
if (existsSync(CACHE_PATH)) writeFileSync(CACHE_PATH, "", { mode: 384 });
|
|
4457
|
+
} catch {}
|
|
4164
4458
|
}
|
|
4165
4459
|
const REQUEST_TIMEOUT_MS = 5e3;
|
|
4166
4460
|
const DEFAULT_PAGE_SIZE = 24;
|
|
@@ -4172,7 +4466,7 @@ async function searchJdSkills(query, opts = {}) {
|
|
|
4172
4466
|
cookie = null;
|
|
4173
4467
|
}
|
|
4174
4468
|
let res;
|
|
4175
|
-
const apiUrl =
|
|
4469
|
+
const apiUrl = await resolveSkillApiUrl();
|
|
4176
4470
|
if (!apiUrl) return { kind: "unreachable" };
|
|
4177
4471
|
try {
|
|
4178
4472
|
res = await fetch(apiUrl, {
|
|
@@ -4243,6 +4537,27 @@ function formatInstalls(count) {
|
|
|
4243
4537
|
if (count >= 1e3) return `${(count / 1e3).toFixed(1).replace(/\.0$/, "")}K installs`;
|
|
4244
4538
|
return `${count} install${count === 1 ? "" : "s"}`;
|
|
4245
4539
|
}
|
|
4540
|
+
function isSearchableQuery(q) {
|
|
4541
|
+
const trimmed = q.trim();
|
|
4542
|
+
if (!trimmed) return false;
|
|
4543
|
+
if (/[^\u0000-\u007f]/.test(trimmed)) return trimmed.length >= 1;
|
|
4544
|
+
return trimmed.length >= 2;
|
|
4545
|
+
}
|
|
4546
|
+
function searchMinHint() {
|
|
4547
|
+
return `${DIM$3}Start typing to search (中文 1 字起,英文 2 字母起)${RESET$3}`;
|
|
4548
|
+
}
|
|
4549
|
+
function isPrintableInput(seq) {
|
|
4550
|
+
if (!seq || seq.length === 0) return false;
|
|
4551
|
+
if (seq.length === 1) {
|
|
4552
|
+
const code = seq.charCodeAt(0);
|
|
4553
|
+
if (code < 32 || code === 127) return false;
|
|
4554
|
+
}
|
|
4555
|
+
return true;
|
|
4556
|
+
}
|
|
4557
|
+
let _lastJdSearchKind = null;
|
|
4558
|
+
function getLastJdSearchKind() {
|
|
4559
|
+
return _lastJdSearchKind;
|
|
4560
|
+
}
|
|
4246
4561
|
async function searchUpstreamSkills(query) {
|
|
4247
4562
|
try {
|
|
4248
4563
|
const url = `${SEARCH_API_BASE}/api/search?q=${encodeURIComponent(query)}&limit=10`;
|
|
@@ -4260,6 +4575,7 @@ async function searchUpstreamSkills(query) {
|
|
|
4260
4575
|
}
|
|
4261
4576
|
}
|
|
4262
4577
|
async function searchSkillsAPI(query) {
|
|
4578
|
+
await probeJdIntranet();
|
|
4263
4579
|
const [upstream, jdResult] = await Promise.all([searchUpstreamSkills(query).catch(() => []), searchJdSkills(query).catch(() => ({ kind: "unreachable" }))]);
|
|
4264
4580
|
const jdSkills = jdResult && jdResult.kind === "results" ? jdResult.skills.map((s) => ({
|
|
4265
4581
|
name: sanitizeMetadata(s.nameEn || s.alias),
|
|
@@ -4275,18 +4591,20 @@ async function searchSkillsAPI(query) {
|
|
|
4275
4591
|
category1Name: s.category1Name,
|
|
4276
4592
|
jdDetail: s
|
|
4277
4593
|
})) : [];
|
|
4594
|
+
_lastJdSearchKind = jdResult?.kind ?? null;
|
|
4278
4595
|
surfaceJdSourceIssue(jdResult);
|
|
4279
4596
|
return [...upstream, ...jdSkills].sort((a, b) => (b.installs || 0) - (a.installs || 0));
|
|
4280
4597
|
}
|
|
4281
4598
|
let _jdIssueLogged = null;
|
|
4282
4599
|
function surfaceJdSourceIssue(jdResult) {
|
|
4600
|
+
if (!isJdIntranetAvailable()) return;
|
|
4283
4601
|
if (!jdResult) return;
|
|
4284
4602
|
if (jdResult.kind === "results") return;
|
|
4603
|
+
if (jdResult.kind === "unreachable") return;
|
|
4285
4604
|
if (_jdIssueLogged && _jdIssueLogged !== jdIssueKind(jdResult)) {}
|
|
4286
4605
|
if (_jdIssueLogged === jdIssueKind(jdResult)) return;
|
|
4287
4606
|
_jdIssueLogged = jdIssueKind(jdResult);
|
|
4288
|
-
if (jdResult.kind === "
|
|
4289
|
-
else if (jdResult.kind === "auth_required") {
|
|
4607
|
+
if (jdResult.kind === "auth_required") {
|
|
4290
4608
|
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
4609
|
} else if (jdResult.kind === "error") process.stderr.write(`${RED}┄${RESET$3} ${RED}JD marketplace error: ${jdResult.message}${RESET$3}\n`);
|
|
4292
4610
|
}
|
|
@@ -4307,6 +4625,7 @@ async function runSearchPrompt(initialQuery = "") {
|
|
|
4307
4625
|
let loading = false;
|
|
4308
4626
|
let debounceTimer = null;
|
|
4309
4627
|
let lastRenderedLines = 0;
|
|
4628
|
+
let jdNeedsLogin = false;
|
|
4310
4629
|
if (process.stdin.isTTY) process.stdin.setRawMode(true);
|
|
4311
4630
|
readline.emitKeypressEvents(process.stdin);
|
|
4312
4631
|
process.stdin.resume();
|
|
@@ -4318,7 +4637,7 @@ async function runSearchPrompt(initialQuery = "") {
|
|
|
4318
4637
|
const cursor = `${BOLD$3}_${RESET$3}`;
|
|
4319
4638
|
lines.push(`${TEXT$2}Search skills:${RESET$3} ${query}${cursor}`);
|
|
4320
4639
|
lines.push("");
|
|
4321
|
-
if (!query || query
|
|
4640
|
+
if (!query || !isSearchableQuery(query)) lines.push(searchMinHint());
|
|
4322
4641
|
else if (results.length === 0 && loading) lines.push(`${DIM$3}Searching...${RESET$3}`);
|
|
4323
4642
|
else if (results.length === 0) lines.push(`${DIM$3}No skills found${RESET$3}`);
|
|
4324
4643
|
else {
|
|
@@ -4336,8 +4655,13 @@ async function runSearchPrompt(initialQuery = "") {
|
|
|
4336
4655
|
lines.push(` ${arrow} ${originBadge}${name}${source}${installsBadge}${loadingIndicator}`);
|
|
4337
4656
|
}
|
|
4338
4657
|
}
|
|
4658
|
+
if (jdNeedsLogin) {
|
|
4659
|
+
lines.push("");
|
|
4660
|
+
lines.push(`${YELLOW$1}┄${RESET$3} ${YELLOW$1}JD 内网技能需登录.${RESET$3} ${DIM$3}按 ${TEXT$2}L${RESET$3}${DIM$3} 登录,或退出后运行 ${TEXT$2}jd-skills login${RESET$3}`);
|
|
4661
|
+
}
|
|
4339
4662
|
lines.push("");
|
|
4340
|
-
|
|
4663
|
+
const footerHint = jdNeedsLogin ? `${DIM$3}up/down navigate | enter select | ${TEXT$2}L${DIM$3} login | esc cancel${RESET$3}` : `${DIM$3}up/down navigate | enter select | esc cancel${RESET$3}`;
|
|
4664
|
+
lines.push(footerHint);
|
|
4341
4665
|
for (const line of lines) process.stdout.write(line + "\n");
|
|
4342
4666
|
lastRenderedLines = lines.length;
|
|
4343
4667
|
}
|
|
@@ -4347,9 +4671,10 @@ async function runSearchPrompt(initialQuery = "") {
|
|
|
4347
4671
|
debounceTimer = null;
|
|
4348
4672
|
}
|
|
4349
4673
|
loading = false;
|
|
4350
|
-
if (!q
|
|
4674
|
+
if (!isSearchableQuery(q)) {
|
|
4351
4675
|
results = [];
|
|
4352
4676
|
selectedIndex = 0;
|
|
4677
|
+
jdNeedsLogin = false;
|
|
4353
4678
|
render();
|
|
4354
4679
|
return;
|
|
4355
4680
|
}
|
|
@@ -4360,6 +4685,8 @@ async function runSearchPrompt(initialQuery = "") {
|
|
|
4360
4685
|
try {
|
|
4361
4686
|
results = await searchSkillsAPI(q);
|
|
4362
4687
|
selectedIndex = 0;
|
|
4688
|
+
if (isJdIntranetAvailable()) jdNeedsLogin = await getJdSourcePromptState() === "auth_required" || getLastJdSearchKind() === "auth_required";
|
|
4689
|
+
else jdNeedsLogin = false;
|
|
4363
4690
|
} catch {
|
|
4364
4691
|
results = [];
|
|
4365
4692
|
} finally {
|
|
@@ -4378,7 +4705,7 @@ async function runSearchPrompt(initialQuery = "") {
|
|
|
4378
4705
|
process.stdout.write(SHOW_CURSOR);
|
|
4379
4706
|
process.stdin.pause();
|
|
4380
4707
|
}
|
|
4381
|
-
function handleKeypress(_ch, key) {
|
|
4708
|
+
async function handleKeypress(_ch, key) {
|
|
4382
4709
|
if (!key) return;
|
|
4383
4710
|
if (key.name === "escape" || key.ctrl && key.name === "c") {
|
|
4384
4711
|
cleanup();
|
|
@@ -4402,17 +4729,20 @@ async function runSearchPrompt(initialQuery = "") {
|
|
|
4402
4729
|
}
|
|
4403
4730
|
if (key.name === "backspace") {
|
|
4404
4731
|
if (query.length > 0) {
|
|
4405
|
-
query = query.slice(0, -1);
|
|
4732
|
+
query = [...query].slice(0, -1).join("");
|
|
4406
4733
|
triggerSearch(query);
|
|
4407
4734
|
}
|
|
4408
4735
|
return;
|
|
4409
4736
|
}
|
|
4410
|
-
if (key.sequence && !key.ctrl && !key.meta
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4737
|
+
if ((key.name === "l" || key.sequence === "l") && jdNeedsLogin && !key.ctrl && !key.meta) {
|
|
4738
|
+
cleanup();
|
|
4739
|
+
await offerJdLoginPrompt(query);
|
|
4740
|
+
resolve(null);
|
|
4741
|
+
return;
|
|
4742
|
+
}
|
|
4743
|
+
if (key.sequence && !key.ctrl && !key.meta && isPrintableInput(key.sequence)) {
|
|
4744
|
+
query += key.sequence;
|
|
4745
|
+
triggerSearch(query);
|
|
4416
4746
|
}
|
|
4417
4747
|
}
|
|
4418
4748
|
process.stdin.on("keypress", handleKeypress);
|
|
@@ -4430,6 +4760,30 @@ function getOwnerRepoFromString(pkg) {
|
|
|
4430
4760
|
async function isRepoPublic(owner, repo) {
|
|
4431
4761
|
return await isRepoPrivate(owner, repo) === false;
|
|
4432
4762
|
}
|
|
4763
|
+
async function offerJdLoginPrompt(query) {
|
|
4764
|
+
if (!process.stdin.isTTY) return;
|
|
4765
|
+
if (!await probeJdIntranet()) return;
|
|
4766
|
+
if (await getJdSourcePromptState() !== "auth_required") return;
|
|
4767
|
+
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}`);
|
|
4768
|
+
if (!await promptYesNo(" Log in? [Y/n]: ")) return;
|
|
4769
|
+
const { getJdCookie } = await Promise.resolve().then(() => jd_cookie_exports);
|
|
4770
|
+
if (!!!await getJdCookie({ forceRefresh: true })) {
|
|
4771
|
+
console.log(`${DIM$3}Login cancelled or failed.${RESET$3} You can retry with: jd-skills login`);
|
|
4772
|
+
return;
|
|
4773
|
+
}
|
|
4774
|
+
console.log(`${TEXT$2}✓${RESET$3} Logged in.${query ? " Re-running search with JD results..." : ""}`);
|
|
4775
|
+
if (!query) return;
|
|
4776
|
+
const jdOnly = (await searchSkillsAPI(query)).filter((s) => s.origin === "jd");
|
|
4777
|
+
if (jdOnly.length > 0) {
|
|
4778
|
+
console.log();
|
|
4779
|
+
console.log(`${YELLOW$1}JD results:${RESET$3}`);
|
|
4780
|
+
for (const skill of jdOnly.slice(0, 6)) {
|
|
4781
|
+
const installs = formatInstalls(skill.installs);
|
|
4782
|
+
console.log(`${YELLOW$1}[jd]${RESET$3} ${TEXT$2}${skill.ownerErp}@${skill.name}${RESET$3}${installs ? ` ${CYAN$1}${installs}${RESET$3}` : ""}`);
|
|
4783
|
+
console.log(`${DIM$3}└ ★${skill.starScore?.toFixed(2) ?? "—"} ${skill.category1Name ?? ""}${RESET$3}`);
|
|
4784
|
+
}
|
|
4785
|
+
} else console.log(`${DIM$3}No JD results for "${query}".${RESET$3}`);
|
|
4786
|
+
}
|
|
4433
4787
|
async function runFind(args) {
|
|
4434
4788
|
const query = args.join(" ");
|
|
4435
4789
|
const isNonInteractive = !process.stdin.isTTY;
|
|
@@ -4445,6 +4799,7 @@ ${DIM$3} 2) npx jd-skills add <owner/repo@skill>${RESET$3}`;
|
|
|
4445
4799
|
});
|
|
4446
4800
|
if (results.length === 0) {
|
|
4447
4801
|
console.log(`${DIM$3}No skills found for "${query}"${RESET$3}`);
|
|
4802
|
+
await offerJdLoginPrompt(query);
|
|
4448
4803
|
return;
|
|
4449
4804
|
}
|
|
4450
4805
|
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 +4818,7 @@ ${DIM$3} 2) npx jd-skills add <owner/repo@skill>${RESET$3}`;
|
|
|
4463
4818
|
}
|
|
4464
4819
|
console.log();
|
|
4465
4820
|
}
|
|
4466
|
-
|
|
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
|
-
}
|
|
4821
|
+
await offerJdLoginPrompt(query);
|
|
4487
4822
|
return;
|
|
4488
4823
|
}
|
|
4489
4824
|
if (isNonInteractive || await isRunningInAgent()) {
|
|
@@ -4492,6 +4827,8 @@ ${DIM$3} 2) npx jd-skills add <owner/repo@skill>${RESET$3}`;
|
|
|
4492
4827
|
console.log(`${DIM$3}Usage: npx jd-skills find <query>${RESET$3}`);
|
|
4493
4828
|
return;
|
|
4494
4829
|
}
|
|
4830
|
+
await offerJdLoginPrompt();
|
|
4831
|
+
await probeJdIntranet();
|
|
4495
4832
|
const selected = await runSearchPrompt();
|
|
4496
4833
|
track({
|
|
4497
4834
|
event: "find",
|
|
@@ -4539,7 +4876,7 @@ async function showJdDetailsAndInstall(selected) {
|
|
|
4539
4876
|
}
|
|
4540
4877
|
console.log();
|
|
4541
4878
|
const installCmd = `jd:${d.owner}/${selected.name}`;
|
|
4542
|
-
const apiUrl =
|
|
4879
|
+
const apiUrl = resolveSkillApiUrlSync();
|
|
4543
4880
|
const webUiUrl = apiUrl ? apiUrl.replace(/\/api\/.*$/, `/skill/${d.skillCode}`) : "";
|
|
4544
4881
|
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
4882
|
if (webUiUrl) console.log(`${DIM$3}Or open in browser:${RESET$3}\n ${webUiUrl}`);
|
|
@@ -6117,12 +6454,12 @@ const BOLD = "\x1B[1m";
|
|
|
6117
6454
|
const DIM = "\x1B[38;5;102m";
|
|
6118
6455
|
const TEXT = "\x1B[38;5;145m";
|
|
6119
6456
|
const LOGO_LINES = [
|
|
6120
|
-
"███████╗██╗ ██╗██╗██╗ ██╗ ███████╗",
|
|
6121
|
-
"██╔════╝██║ ██╔╝██║██║ ██║ ██╔════╝",
|
|
6122
|
-
"
|
|
6123
|
-
"
|
|
6124
|
-
"███████║██║ ██╗██║███████╗███████╗███████║",
|
|
6125
|
-
"╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚══════╝"
|
|
6457
|
+
" ██╗██████╗ ███████╗██╗ ██╗██╗██╗ ██╗ ███████╗",
|
|
6458
|
+
" ██║██╔══██╗ ██╔════╝██║ ██╔╝██║██║ ██║ ██╔════╝",
|
|
6459
|
+
" ██║██║ ██║█████╗███████╗█████╔╝ ██║██║ ██║ ███████╗",
|
|
6460
|
+
"██ ██║██║ ██║╚════╝╚════██║██╔═██╗ ██║██║ ██║ ╚════██║",
|
|
6461
|
+
"╚█████╔╝██████╔╝ ███████║██║ ██╗██║███████╗███████╗███████║",
|
|
6462
|
+
" ╚════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚══════╝"
|
|
6126
6463
|
];
|
|
6127
6464
|
const GRAYS = [
|
|
6128
6465
|
"\x1B[38;5;250m",
|
|
@@ -6187,8 +6524,8 @@ ${BOLD}Project:${RESET}
|
|
|
6187
6524
|
experimental_sync Sync skills from node_modules into agent directories
|
|
6188
6525
|
|
|
6189
6526
|
${BOLD}Auth (intranet marketplaces, opt-in):${RESET}
|
|
6190
|
-
login Open browser to authenticate with
|
|
6191
|
-
|
|
6527
|
+
login Open browser to authenticate with JD marketplace
|
|
6528
|
+
(built-in login; no external SDK install)
|
|
6192
6529
|
login --force Re-authenticate even if a valid cookie is cached
|
|
6193
6530
|
logout Clear the cached auth cookie
|
|
6194
6531
|
whoami Show current login status
|
|
@@ -6357,10 +6694,20 @@ async function runLogin(args = []) {
|
|
|
6357
6694
|
console.log(`Run ${TEXT}jd-skills login --force${RESET} to re-authenticate.`);
|
|
6358
6695
|
return;
|
|
6359
6696
|
}
|
|
6360
|
-
if (!await
|
|
6361
|
-
console.log(`${TEXT}Cannot log in:${RESET}
|
|
6362
|
-
console.log(` ${DIM}${
|
|
6363
|
-
|
|
6697
|
+
if (!await probeJdIntranet()) {
|
|
6698
|
+
console.log(`${TEXT}Cannot log in:${RESET} JD intranet not detected.`);
|
|
6699
|
+
console.log(` ${DIM}Connect to JD VPN/network, then run ${TEXT}jd-skills login${RESET} again.${RESET}`);
|
|
6700
|
+
process.exit(1);
|
|
6701
|
+
}
|
|
6702
|
+
const broker = getBrokerUrl();
|
|
6703
|
+
if (!broker) {
|
|
6704
|
+
console.log(`${TEXT}Cannot log in:${RESET} SSO broker URL not configured.`);
|
|
6705
|
+
console.log(` ${DIM}Run ${TEXT}jd-skills config set-broker <url>${RESET}${DIM} or set JD_BROKER_URL.${RESET}`);
|
|
6706
|
+
process.exit(1);
|
|
6707
|
+
}
|
|
6708
|
+
if (!await isBrokerReachable(broker)) {
|
|
6709
|
+
console.log(`${TEXT}Cannot log in:${RESET} SSO broker unreachable at ${broker}.`);
|
|
6710
|
+
console.log(` ${DIM}Check VPN/network, or run ${TEXT}jd-skills doctor${RESET}${DIM} for diagnostics.${RESET}`);
|
|
6364
6711
|
process.exit(1);
|
|
6365
6712
|
}
|
|
6366
6713
|
console.log(`${TEXT}Logging in to JD marketplace...${RESET}`);
|
|
@@ -6384,16 +6731,14 @@ function runLogout() {
|
|
|
6384
6731
|
}
|
|
6385
6732
|
async function runWhoami() {
|
|
6386
6733
|
const status = getCookieStatus();
|
|
6387
|
-
const sdkOk = await isBrokerSdkAvailable();
|
|
6388
6734
|
const broker = getBrokerUrl();
|
|
6735
|
+
const onIntranet = await probeJdIntranet();
|
|
6389
6736
|
console.log(`${BOLD}JD marketplace status${RESET}`);
|
|
6390
|
-
console.log(`
|
|
6391
|
-
console.log(`
|
|
6737
|
+
console.log(` intranet: ${onIntranet ? `${TEXT}detected${RESET}` : `${DIM}not detected${RESET}`}`);
|
|
6738
|
+
console.log(` broker URL: ${broker ? `${TEXT}${broker}${RESET}` : `${DIM}n/a${RESET}`}`);
|
|
6392
6739
|
console.log();
|
|
6393
|
-
if (!
|
|
6394
|
-
console.log(`${
|
|
6395
|
-
console.log(` ${DIM}${installSdkHint()}${RESET}`);
|
|
6396
|
-
console.log(` (or run: ${TEXT}jd-skills doctor${RESET} for a full diagnostic)`);
|
|
6740
|
+
if (!onIntranet) {
|
|
6741
|
+
console.log(`${DIM}JD marketplace is only available on JD intranet.${RESET}`);
|
|
6397
6742
|
return;
|
|
6398
6743
|
}
|
|
6399
6744
|
if (status.loggedIn) {
|
|
@@ -6406,29 +6751,32 @@ async function runDoctor() {
|
|
|
6406
6751
|
console.log(`${BOLD}jd-skills doctor${RESET}`);
|
|
6407
6752
|
console.log(`${DIM}JD marketplace setup diagnostic (read-only, no installs)${RESET}`);
|
|
6408
6753
|
console.log();
|
|
6754
|
+
if (!await probeJdIntranet()) {
|
|
6755
|
+
console.log(`${DIM}JD intranet not detected${RESET} — marketplace probe to ${JD_INTRANET_DEFAULTS.skillApiUrl} failed.`);
|
|
6756
|
+
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}`);
|
|
6757
|
+
console.log();
|
|
6758
|
+
return;
|
|
6759
|
+
}
|
|
6409
6760
|
const checks = [];
|
|
6410
|
-
const
|
|
6411
|
-
const registryOk = npmRegistry.replace(/\/+$/, "") === JD_BROKER_SDK_REGISTRY.replace(/\/+$/, "");
|
|
6761
|
+
const skillApiUrl = await resolveSkillApiUrl();
|
|
6412
6762
|
checks.push({
|
|
6413
|
-
label: "
|
|
6414
|
-
ok:
|
|
6415
|
-
detail:
|
|
6416
|
-
fix: registryOk ? void 0 : `Add this line to ~/.npmrc:\n registry = ${JD_BROKER_SDK_REGISTRY}\n Then re-run npx jd-skills.`
|
|
6763
|
+
label: "JD intranet detected",
|
|
6764
|
+
ok: true,
|
|
6765
|
+
detail: `marketplace reachable (auto: ${JD_INTRANET_DEFAULTS.skillApiUrl})`
|
|
6417
6766
|
});
|
|
6418
|
-
const sdkOk = await isBrokerSdkAvailable();
|
|
6419
6767
|
checks.push({
|
|
6420
|
-
label:
|
|
6421
|
-
ok:
|
|
6422
|
-
detail:
|
|
6423
|
-
fix:
|
|
6768
|
+
label: "JD skill search API",
|
|
6769
|
+
ok: skillApiUrl.length > 0,
|
|
6770
|
+
detail: skillApiUrl || "unavailable after probe",
|
|
6771
|
+
fix: skillApiUrl.length > 0 ? void 0 : `Set JD_SKILL_API_URL only if the default marketplace URL is wrong for your environment.`
|
|
6424
6772
|
});
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
|
|
6428
|
-
|
|
6429
|
-
detail: "skipped (SDK not loadable)"
|
|
6773
|
+
checks.push({
|
|
6774
|
+
label: "built-in login client",
|
|
6775
|
+
ok: true,
|
|
6776
|
+
detail: "cookie broker client bundled with jd-skills (no external SDK install)"
|
|
6430
6777
|
});
|
|
6431
|
-
|
|
6778
|
+
const cookieStatus = getCookieStatus();
|
|
6779
|
+
if (cookieStatus.loggedIn) {
|
|
6432
6780
|
const remaining = cookieStatus.remainingMs ?? 0;
|
|
6433
6781
|
checks.push({
|
|
6434
6782
|
label: "cached cookie",
|
|
@@ -6443,13 +6791,21 @@ async function runDoctor() {
|
|
|
6443
6791
|
fix: `Run jd-skills login to authenticate.`
|
|
6444
6792
|
});
|
|
6445
6793
|
const broker = getBrokerUrl();
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
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.`
|
|
6794
|
+
if (!broker) checks.push({
|
|
6795
|
+
label: "SSO broker URL",
|
|
6796
|
+
ok: false,
|
|
6797
|
+
detail: "not resolved (unexpected on intranet)",
|
|
6798
|
+
fix: `Run jd-skills config set-broker <url> or set JD_BROKER_URL to override the default.`
|
|
6452
6799
|
});
|
|
6800
|
+
else {
|
|
6801
|
+
const brokerOk = await isUrlReachable(broker);
|
|
6802
|
+
checks.push({
|
|
6803
|
+
label: "SSO broker reachable",
|
|
6804
|
+
ok: brokerOk,
|
|
6805
|
+
detail: brokerOk ? `${broker} (auto-detected on intranet)` : `HEAD ${broker} → unreachable (network or DNS)`,
|
|
6806
|
+
fix: brokerOk ? void 0 : `Check VPN/network, or jd-skills config set-broker <url> if your broker host differs.`
|
|
6807
|
+
});
|
|
6808
|
+
}
|
|
6453
6809
|
let allOk = true;
|
|
6454
6810
|
for (const c of checks) {
|
|
6455
6811
|
const mark = c.ok ? `${TEXT}✓${RESET}` : `${TEXT}✗${RESET}`;
|
|
@@ -6472,29 +6828,6 @@ async function runDoctor() {
|
|
|
6472
6828
|
console.log(`Run ${TEXT}jd-skills doctor${RESET} again after fixing to re-verify.`);
|
|
6473
6829
|
process.exit(1);
|
|
6474
6830
|
}
|
|
6475
|
-
async function getNpmRegistry() {
|
|
6476
|
-
const fs = await import("fs");
|
|
6477
|
-
const path = await import("path");
|
|
6478
|
-
let dir = process.cwd();
|
|
6479
|
-
const root = path.parse(dir).root;
|
|
6480
|
-
while (dir !== root) {
|
|
6481
|
-
const rc = path.join(dir, ".npmrc");
|
|
6482
|
-
if (fs.existsSync(rc)) try {
|
|
6483
|
-
const m = fs.readFileSync(rc, "utf-8").match(/^registry\s*=\s*(.+)$/m);
|
|
6484
|
-
if (m) return m[1].trim();
|
|
6485
|
-
} catch {}
|
|
6486
|
-
dir = path.dirname(dir);
|
|
6487
|
-
}
|
|
6488
|
-
const home = process.env.HOME || process.env.USERPROFILE;
|
|
6489
|
-
if (home) {
|
|
6490
|
-
const userRc = path.join(home, ".npmrc");
|
|
6491
|
-
if (fs.existsSync(userRc)) try {
|
|
6492
|
-
const m = fs.readFileSync(userRc, "utf-8").match(/^registry\s*=\s*(.+)$/m);
|
|
6493
|
-
if (m) return m[1].trim();
|
|
6494
|
-
} catch {}
|
|
6495
|
-
}
|
|
6496
|
-
return "https://registry.npmjs.org/";
|
|
6497
|
-
}
|
|
6498
6831
|
async function isUrlReachable(url) {
|
|
6499
6832
|
try {
|
|
6500
6833
|
return (await fetch(url, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jd-skills",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "CLI for the agent skills ecosystem (JD fork of vercel-labs/skills)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -134,6 +134,7 @@
|
|
|
134
134
|
},
|
|
135
135
|
"packageManager": "pnpm@10.17.1",
|
|
136
136
|
"dependencies": {
|
|
137
|
+
"open": "^11.0.0",
|
|
137
138
|
"yaml": "^2.8.3"
|
|
138
139
|
}
|
|
139
140
|
}
|
package/dist/_chunks/config.mjs
DELETED
package/dist/_chunks/config2.mjs
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
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,109 +0,0 @@
|
|
|
1
|
-
import { t as getBrokerUrl } from "./config2.mjs";
|
|
2
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
3
|
-
import { dirname, join } from "path";
|
|
4
|
-
import { homedir } from "os";
|
|
5
|
-
const CACHE_PATH = join(join(homedir(), ".jd-skills"), "cookies.json");
|
|
6
|
-
const COOKIE_TTL_MS = 1440 * 60 * 1e3;
|
|
7
|
-
function getSdkPackageName() {
|
|
8
|
-
return (process.env.JD_BROKER_SDK_PACKAGE ?? "").trim();
|
|
9
|
-
}
|
|
10
|
-
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`;
|
|
13
|
-
}
|
|
14
|
-
function readCache() {
|
|
15
|
-
try {
|
|
16
|
-
if (!existsSync(CACHE_PATH)) return null;
|
|
17
|
-
const raw = readFileSync(CACHE_PATH, "utf-8");
|
|
18
|
-
const parsed = JSON.parse(raw);
|
|
19
|
-
if (typeof parsed.cookie !== "string" || typeof parsed.expiresAt !== "number") return null;
|
|
20
|
-
return parsed;
|
|
21
|
-
} catch {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
function writeCache(entry) {
|
|
26
|
-
try {
|
|
27
|
-
mkdirSync(dirname(CACHE_PATH), { recursive: true });
|
|
28
|
-
writeFileSync(CACHE_PATH, JSON.stringify(entry, null, 2), { mode: 384 });
|
|
29
|
-
} catch {}
|
|
30
|
-
}
|
|
31
|
-
async function getJdCookie(opts) {
|
|
32
|
-
if (!opts?.forceRefresh) {
|
|
33
|
-
const cached = readCache();
|
|
34
|
-
if (cached && cached.expiresAt > Date.now()) return cached.cookie;
|
|
35
|
-
}
|
|
36
|
-
const sdkPackage = getSdkPackageName();
|
|
37
|
-
if (!sdkPackage) return null;
|
|
38
|
-
let loginFn = null;
|
|
39
|
-
try {
|
|
40
|
-
loginFn = (await import(
|
|
41
|
-
/* @vite-ignore */
|
|
42
|
-
`${sdkPackage}/client`
|
|
43
|
-
)).login ?? null;
|
|
44
|
-
} catch {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
if (!loginFn) return null;
|
|
48
|
-
try {
|
|
49
|
-
const cookie = await loginFn({
|
|
50
|
-
brokerUrl: getBrokerUrl(),
|
|
51
|
-
open: true
|
|
52
|
-
});
|
|
53
|
-
if (typeof cookie === "string" && cookie.length > 0) {
|
|
54
|
-
writeCache({
|
|
55
|
-
cookie,
|
|
56
|
-
expiresAt: Date.now() + COOKIE_TTL_MS,
|
|
57
|
-
cachedAt: Date.now()
|
|
58
|
-
});
|
|
59
|
-
return cookie;
|
|
60
|
-
}
|
|
61
|
-
return null;
|
|
62
|
-
} catch {
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
function getCookieStatus() {
|
|
67
|
-
const cached = readCache();
|
|
68
|
-
if (!cached) return { loggedIn: false };
|
|
69
|
-
return {
|
|
70
|
-
loggedIn: true,
|
|
71
|
-
expiresAt: cached.expiresAt,
|
|
72
|
-
remainingMs: cached.expiresAt - Date.now()
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
async function isBrokerSdkAvailable() {
|
|
76
|
-
const sdkPackage = getSdkPackageName();
|
|
77
|
-
if (!sdkPackage) return false;
|
|
78
|
-
try {
|
|
79
|
-
return typeof (await import(
|
|
80
|
-
/* @vite-ignore */
|
|
81
|
-
`${sdkPackage}/client`
|
|
82
|
-
)).login === "function";
|
|
83
|
-
} catch {
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
async function isBrokerReachable(brokerUrl) {
|
|
88
|
-
try {
|
|
89
|
-
return (await fetch(brokerUrl, {
|
|
90
|
-
method: "HEAD",
|
|
91
|
-
signal: AbortSignal.timeout(3e3)
|
|
92
|
-
})).status < 500;
|
|
93
|
-
} catch {
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
async function getJdSourcePromptState() {
|
|
98
|
-
if (!await isBrokerSdkAvailable()) return "sdk_missing";
|
|
99
|
-
const cookieStatus = getCookieStatus();
|
|
100
|
-
if (cookieStatus.loggedIn && cookieStatus.remainingMs && cookieStatus.remainingMs > 0) return "logged_in";
|
|
101
|
-
const { getBrokerUrl } = await import("./config.mjs");
|
|
102
|
-
return await isBrokerReachable(getBrokerUrl()) ? "auth_required" : "unreachable";
|
|
103
|
-
}
|
|
104
|
-
function clearJdCookie() {
|
|
105
|
-
try {
|
|
106
|
-
if (existsSync(CACHE_PATH)) writeFileSync(CACHE_PATH, "", { mode: 384 });
|
|
107
|
-
} catch {}
|
|
108
|
-
}
|
|
109
|
-
export { getSdkPackageName as a, isBrokerSdkAvailable as c, getJdSourcePromptState as i, getCookieStatus as n, installSdkHint as o, getJdCookie as r, isBrokerReachable as s, clearJdCookie as t };
|