@lumi-ai-lab/harness-data 0.0.6 → 0.0.10

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/README.md CHANGED
@@ -40,4 +40,4 @@ npx @lumi-ai-lab/harness-data doctor
40
40
 
41
41
  The runtime is assembled from the `harness-data` runtime bundle, platform-specific CLI Release assets, `harness-data-wikis`, generated local config, CAS credentials, and selected Agent symlinks.
42
42
 
43
- `--agent` supports `claude`, `codex`, `pi`, and `all`; the default is `all`.
43
+ `--agent` supports `claude`, `codex`, `pi`, `openclaw`, `hermes`, `both`, and `all`; the default is `all`. `both` installs Claude + Codex, while `all` installs Claude + Codex + Pi + OpenClaw + Hermes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumi-ai-lab/harness-data",
3
- "version": "0.0.6",
3
+ "version": "0.0.10",
4
4
  "description": "Installer and updater for Harness Data",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -43,6 +43,7 @@ Commands:
43
43
 
44
44
  Install options:
45
45
  --dir PATH Runtime directory (default: current directory)
46
+ --agent NAME claude, codex, pi, openclaw, hermes, both, or all
46
47
  --github-token TOKEN GitHub token for private Release assets`);
47
48
  if (unknown) process.exitCode = 1;
48
49
  }
@@ -3,6 +3,7 @@ import path from "node:path";
3
3
  import { run } from "../lib/exec.js";
4
4
  import { findWorkspaceDir } from "../lib/paths.js";
5
5
  import { binaryName } from "../lib/platform.js";
6
+ import { concreteAgentNames } from "../lib/config.js";
6
7
 
7
8
  function existsExecutable(file) {
8
9
  try {
@@ -67,7 +68,12 @@ export async function collectDoctor(workspace, options = {}) {
67
68
  add("CAS credentials file", jsonFileValid(path.join(casConfigDir, "config.json")), casConfigDir);
68
69
  add("CMR token", await tokenCheck(workspace, "qdm-cmr-cli", env));
69
70
  add("Indicators token", await tokenCheck(workspace, "qdm-indicators-cli", env));
70
- add("Agent hook", agentOk(workspace, "claude") || agentOk(workspace, "codex") || agentOk(workspace, "pi"));
71
+ add("Agent hook", concreteAgentNames.some((name) => agentOk(workspace, name)));
72
+ for (const name of ["openclaw", "hermes"]) {
73
+ if (fs.existsSync(path.join(workspace, `.${name}`))) {
74
+ add(`Agent hook .${name}`, agentOk(workspace, name), `agents/${name}`);
75
+ }
76
+ }
71
77
  if (!fs.existsSync(path.join(workspace, ".harness", "index", "wikis-index.json")) &&
72
78
  !fs.existsSync(path.join(workspace, ".harness", "index", "wikis-runtime-index.json"))) {
73
79
  checks.push({ name: "wikis index", ok: true, detail: "missing; run data-harness-cli wikis build-index --skip-checks" });
@@ -265,8 +265,8 @@ export async function installCommand(options = {}) {
265
265
  blank();
266
266
 
267
267
  step(8, 8, "配置 Agent Hook");
268
- linkAgents(runtimeDir, await chooseAgent(options));
269
- for (const [target, source] of [[".claude", "agents/claude"], [".codex", "agents/codex"], [".pi", "agents/pi"]]) {
268
+ const linkedAgents = linkAgents(runtimeDir, await chooseAgent(options));
269
+ for (const [source, target] of linkedAgents) {
270
270
  if (fs.existsSync(path.join(runtimeDir, target))) ok(`${target} -> ${source}`);
271
271
  }
272
272
  blank();
package/src/lib/config.js CHANGED
@@ -2,6 +2,25 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { binaryName } from "./platform.js";
4
4
 
5
+ export const agentChoices = ["claude", "codex", "pi", "openclaw", "hermes", "both", "all"];
6
+ export const concreteAgentNames = ["claude", "codex", "pi", "openclaw", "hermes"];
7
+ export const agentLinks = {
8
+ claude: [["agents/claude", ".claude"]],
9
+ codex: [["agents/codex", ".codex"]],
10
+ pi: [["agents/pi", ".pi"]],
11
+ openclaw: [["agents/openclaw", ".openclaw"]],
12
+ hermes: [["agents/hermes", ".hermes"]],
13
+ both: [["agents/claude", ".claude"], ["agents/codex", ".codex"]],
14
+ all: [
15
+ ["agents/claude", ".claude"],
16
+ ["agents/codex", ".codex"],
17
+ ["agents/pi", ".pi"],
18
+ ["agents/openclaw", ".openclaw"],
19
+ ["agents/hermes", ".hermes"],
20
+ ],
21
+ };
22
+ export const agentChoiceText = agentChoices.join(", ");
23
+
5
24
  export function writeLocalConfig(workspace, options = {}) {
6
25
  const configDir = path.join(workspace, "config");
7
26
  fs.mkdirSync(configDir, { recursive: true });
@@ -11,8 +30,9 @@ export function writeLocalConfig(workspace, options = {}) {
11
30
  throw new Error("local config already exists; rerun interactively and confirm overwrite or remove the files");
12
31
  }
13
32
  const bin = (name) => path.join(workspace, "bin", binaryName(name)).replaceAll("\\", "/");
33
+ const casConfigDir = path.join(workspace, ".qdm-auth", "cas").replaceAll("\\", "/");
14
34
  fs.writeFileSync(harness, `paths:\n spec: wikis/spec\n playbooks: wikis/playbooks\n templates: wikis/templates\n\ncli:\n qdm_cmr_cli: ${bin("qdm-cmr-cli")}\n qdm_indicators_cli: ${bin("qdm-indicators-cli")}\n qdm_cas_cli: ${bin("cas-cli")}\n`);
15
- fs.writeFileSync(env, `export QDM_CMR_CLI="${bin("qdm-cmr-cli")}"\nexport QDM_INDICATORS_CLI="${bin("qdm-indicators-cli")}"\nexport QDM_CAS_CLI="${bin("cas-cli")}"\n`);
35
+ fs.writeFileSync(env, `export QDM_CMR_CLI="${bin("qdm-cmr-cli")}"\nexport QDM_INDICATORS_CLI="${bin("qdm-indicators-cli")}"\nexport QDM_CAS_CLI="${bin("cas-cli")}"\nexport QDM_CAS_CONFIG_DIR="${casConfigDir}"\n`);
16
36
  }
17
37
 
18
38
  export function validateCasConfigDir(dir) {
@@ -29,10 +49,8 @@ export function validateCasConfigDir(dir) {
29
49
  }
30
50
 
31
51
  export function linkAgents(workspace, agent) {
32
- const pairs = [];
33
- if (agent === "claude" || agent === "all") pairs.push(["agents/claude", ".claude"]);
34
- if (agent === "codex" || agent === "all") pairs.push(["agents/codex", ".codex"]);
35
- if (agent === "pi" || agent === "all") pairs.push(["agents/pi", ".pi"]);
52
+ const pairs = agentLinks[agent];
53
+ if (!pairs) throw new Error(`agent must be ${agentChoiceText}`);
36
54
  for (const [sourceRel, targetRel] of pairs) {
37
55
  const source = path.join(workspace, sourceRel);
38
56
  const target = path.join(workspace, targetRel);
@@ -40,4 +58,5 @@ export function linkAgents(workspace, agent) {
40
58
  if (fs.existsSync(target)) fs.rmSync(target, { recursive: true, force: true });
41
59
  fs.symlinkSync(source, target, "junction");
42
60
  }
61
+ return pairs;
43
62
  }
package/src/lib/prompt.js CHANGED
@@ -1,8 +1,7 @@
1
1
  import readline from "node:readline/promises";
2
2
  import { stdin as input, stdout as output } from "node:process";
3
3
  import { Writable } from "node:stream";
4
-
5
- const agentChoices = ["claude", "codex", "pi", "all"];
4
+ import { agentChoices, agentChoiceText } from "./config.js";
6
5
 
7
6
  export async function confirm(message, options = {}) {
8
7
  if (options.yes) return true;
@@ -20,15 +19,15 @@ export async function confirm(message, options = {}) {
20
19
  export async function chooseAgent(options = {}) {
21
20
  if (options.agent) {
22
21
  const value = String(options.agent).trim().toLowerCase();
23
- if (!agentChoices.includes(value)) throw new Error("agent must be claude, codex, pi, or all");
22
+ if (!agentChoices.includes(value)) throw new Error(`agent must be ${agentChoiceText}`);
24
23
  return value;
25
24
  }
26
25
  if (options.yes) return "all";
27
26
  const rl = readline.createInterface({ input, output });
28
27
  try {
29
- const answer = (await rl.question("选择 Agent:claude, codex, pi, all [all] ")).trim().toLowerCase();
28
+ const answer = (await rl.question(`选择 Agent:${agentChoiceText} [all] `)).trim().toLowerCase();
30
29
  const value = answer || "all";
31
- if (!agentChoices.includes(value)) throw new Error("agent must be claude, codex, pi, or all");
30
+ if (!agentChoices.includes(value)) throw new Error(`agent must be ${agentChoiceText}`);
32
31
  return value;
33
32
  } finally {
34
33
  rl.close();