@lumi-ai-lab/harness-data 0.0.14 → 0.0.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumi-ai-lab/harness-data",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "description": "Installer and updater for Harness Data",
5
5
  "type": "module",
6
6
  "bin": {
@@ -40,10 +40,15 @@ function configPathsValid(workspace) {
40
40
  return matches.length >= 3 && matches.every((entry) => fs.existsSync(entry));
41
41
  }
42
42
 
43
- function jsonFileValid(file) {
43
+ function casCredentialsValid(dir) {
44
+ const encrypted = path.join(dir, "credentials.enc");
44
45
  try {
45
- JSON.parse(fs.readFileSync(file, "utf8"));
46
- return true;
46
+ if (fs.statSync(encrypted).size > 0) return true;
47
+ } catch {}
48
+
49
+ try {
50
+ const config = JSON.parse(fs.readFileSync(path.join(dir, "config.json"), "utf8"));
51
+ return Boolean(config?.cas?.username && config?.cas?.password);
47
52
  } catch {
48
53
  return false;
49
54
  }
@@ -65,7 +70,7 @@ export async function collectDoctor(workspace, options = {}) {
65
70
  add("config/harness-config.yaml", fs.existsSync(path.join(workspace, "config", "harness-config.yaml")));
66
71
  add("config/qdm-cli-paths.env", fs.existsSync(path.join(workspace, "config", "qdm-cli-paths.env")));
67
72
  add("config CLI paths", configPathsValid(workspace));
68
- add("CAS credentials file", jsonFileValid(path.join(casConfigDir, "config.json")), casConfigDir);
73
+ add("CAS credentials file", casCredentialsValid(casConfigDir), casConfigDir);
69
74
  add("CMR token", await tokenCheck(workspace, "qdm-cmr-cli", env));
70
75
  add("Indicators token", await tokenCheck(workspace, "qdm-indicators-cli", env));
71
76
  add("Agent hook", concreteAgentNames.some((name) => agentOk(workspace, name)));
@@ -170,8 +170,9 @@ async function writeCasCredentials(runtimeDir, options = {}) {
170
170
  if (!username || !password) throw new Error("CAS username and password are required");
171
171
  const dir = casConfigDir(runtimeDir);
172
172
  fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
173
- fs.writeFileSync(path.join(dir, "config.json"), `${JSON.stringify({ cas: { username, password } }, null, 2)}\n`, { mode: 0o600 });
174
- ok("CAS 凭证已保存到 .qdm-auth/cas/config.json");
173
+ const env = { QDM_CAS_CONFIG_DIR: dir };
174
+ await run(path.join(runtimeDir, "bin", binaryName("cas-cli")), ["config", "set-credentials", "--username", username, "--password", password], { cwd: runtimeDir, env });
175
+ ok("CAS 凭证已加密保存到 .qdm-auth/cas/credentials.enc");
175
176
  return dir;
176
177
  }
177
178
 
@@ -204,8 +205,10 @@ export async function buildAndCheck(runtimeDir, options = {}) {
204
205
  return { ok: true, docs, recall, runtimeDocs };
205
206
  }
206
207
 
207
- export function printDoctorSummary(doctor) {
208
- const failed = doctor.checks.filter((check) => !check.ok);
208
+ export function printDoctorSummary(doctor, options = {}) {
209
+ const nonBlocking = options.nonBlocking || (() => false);
210
+ const failed = doctor.checks.filter((check) => !check.ok && !nonBlocking(check));
211
+ const warnings = doctor.checks.filter((check) => !check.ok && nonBlocking(check));
209
212
  if (!failed.length) {
210
213
  ok("runtime");
211
214
  ok("wikis/spec");
@@ -216,9 +219,11 @@ export function printDoctorSummary(doctor) {
216
219
  ok("CAS 凭证");
217
220
  ok("CMR Token");
218
221
  ok("Indicators Token");
219
- ok("Agent Hook");
222
+ if (!warnings.some((check) => check.name.startsWith("Agent hook"))) ok("Agent Hook");
223
+ for (const check of warnings) warn(`${check.name}${check.detail ? ` (${check.detail})` : ""}`);
220
224
  return;
221
225
  }
226
+ for (const check of warnings) warn(`${check.name}${check.detail ? ` (${check.detail})` : ""}`);
222
227
  for (const check of failed) fail(`${check.name}${check.detail ? ` (${check.detail})` : ""}`);
223
228
  }
224
229
 
@@ -13,6 +13,10 @@ import { buildAndCheck, installRuntimeBundle, printDoctorSummary } from "./insta
13
13
  import { collectDoctor } from "./doctor.js";
14
14
  import { action, blank, header, ok, shortSha, skip, step, warn } from "../lib/log.js";
15
15
 
16
+ export function isNonBlockingUpdateDoctorCheck(check) {
17
+ return check.name === "Agent hook" || check.name.startsWith("Agent hook .");
18
+ }
19
+
16
20
  async function npmLatest() {
17
21
  try {
18
22
  const response = await fetch("https://registry.npmjs.org/@lumi-ai-lab%2Fharness-data/latest", { signal: AbortSignal.timeout(5000) });
@@ -184,8 +188,8 @@ export async function updateCommand(options = {}) {
184
188
  step(6, 6, "安装校验");
185
189
  if (changed) {
186
190
  const doctor = await collectDoctor(runtimeDir, trackingOptions);
187
- printDoctorSummary(doctor);
188
- if (doctor.checks.some((check) => !check.ok)) throw new Error("doctor failed; update is incomplete");
191
+ printDoctorSummary(doctor, { nonBlocking: isNonBlockingUpdateDoctorCheck });
192
+ if (doctor.checks.some((check) => !check.ok && !isNonBlockingUpdateDoctorCheck(check))) throw new Error("doctor failed; update is incomplete");
189
193
  writeState(runtimeDir, {
190
194
  ...state,
191
195
  runtimeTag,
package/src/lib/config.js CHANGED
@@ -36,16 +36,17 @@ export function writeLocalConfig(workspace, options = {}) {
36
36
  }
37
37
 
38
38
  export function validateCasConfigDir(dir) {
39
- const file = path.join(dir, "config.json");
40
- let config;
39
+ const encrypted = path.join(dir, "credentials.enc");
41
40
  try {
42
- config = JSON.parse(fs.readFileSync(file, "utf8"));
43
- } catch {
44
- throw new Error(`CAS config is missing or invalid: ${file}`);
45
- }
46
- if (!config?.cas?.username || !config?.cas?.password) {
47
- throw new Error(`CAS config must contain non-empty cas.username and cas.password: ${file}`);
48
- }
41
+ if (fs.statSync(encrypted).size > 0) return;
42
+ } catch {}
43
+
44
+ const legacy = path.join(dir, "config.json");
45
+ try {
46
+ const config = JSON.parse(fs.readFileSync(legacy, "utf8"));
47
+ if (config?.cas?.username && config?.cas?.password) return;
48
+ } catch {}
49
+ throw new Error(`CAS credentials are missing or invalid in: ${dir}`);
49
50
  }
50
51
 
51
52
  export function linkAgents(workspace, agent) {