@okf-harness/cli 0.1.0 → 0.2.0

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
@@ -2,7 +2,9 @@
2
2
 
3
3
  Command-line package for OKF Harness local workspaces. It provides the `okfh` command for initializing workspaces, registering sources, linting wiki content, searching and reading pages, generating graph reports, and installing Claude Code or Codex guidance.
4
4
 
5
- OKF Harness is an independent open-source project built on [Andrej Karpathy's LLM Wiki](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) pattern and Google's [Open Knowledge Format](https://cloud.google.com/blog/products/data-analytics/how-the-open-knowledge-format-can-improve-data-sharing) / [OKF specification](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md).
5
+ OKF Harness is an independent open-source project built on Andrej Karpathy's [LLM Wiki](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) pattern and Google's [Open Knowledge Format](https://cloud.google.com/blog/products/data-analytics/how-the-open-knowledge-format-can-improve-data-sharing) / [OKF specification](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md).
6
+
7
+ Most users install this package once, create one local workspace per knowledge domain, then ask Claude Code or Codex to maintain the workspace through `okfh --json`.
6
8
 
7
9
  Install:
8
10
 
@@ -17,4 +19,20 @@ Try without a global install:
17
19
  npx --package @okf-harness/cli okfh doctor --json
18
20
  ```
19
21
 
20
- For project overview, workflows, and security notes, see the [main repository README](https://github.com/pumblus/okf-harness#readme).
22
+ Common commands:
23
+
24
+ ```bash
25
+ okfh init "$HOME/Documents/OKF Harness/ai-research" --name "AI Research" --agents all --git --json
26
+ okfh source add ~/Downloads/paper.pdf --workspace "$HOME/Documents/OKF Harness/ai-research" --json
27
+ okfh ingest plan <source-id> --workspace "$HOME/Documents/OKF Harness/ai-research" --json
28
+ okfh search "LLM Wiki" --workspace "$HOME/Documents/OKF Harness/ai-research" --json
29
+ okfh read topics/llm-wiki --workspace "$HOME/Documents/OKF Harness/ai-research" --json
30
+ okfh lint --workspace "$HOME/Documents/OKF Harness/ai-research" --json
31
+ okfh graph --workspace "$HOME/Documents/OKF Harness/ai-research" --json
32
+ ```
33
+
34
+ On Windows PowerShell, use `$env:USERPROFILE\Documents\OKF Harness` for the workspace parent folder. On Command Prompt, use `%USERPROFILE%\Documents\OKF Harness`.
35
+
36
+ OKF Harness keeps raw sources under `raw/sources/`, synthesized knowledge under `wiki/`, source records in `.okfh/manifest.jsonl`, and generated reports under `.okfh/reports/`.
37
+
38
+ For project overview, workflows, security notes, and LLM-readable context, see the [main repository README](https://github.com/pumblus/okf-harness#readme) and [llms.txt](https://github.com/pumblus/okf-harness/blob/main/llms.txt).
@@ -1,5 +1,4 @@
1
1
  // src/index.ts
2
- import { execFile as execFile2 } from "child_process";
3
2
  import path2 from "path";
4
3
  import { installAgentAdapters } from "@okf-harness/agent-pack";
5
4
  import {
@@ -36,19 +35,26 @@ var requiredSkills = [
36
35
  "okf-harness-maintain"
37
36
  ];
38
37
  async function runDoctor(options = {}) {
38
+ const runtimePlatform = options.runtimePlatform ?? process.platform;
39
+ const runExecutable = options.runExecutable ?? runExecutableDefault;
39
40
  const checks = [
40
41
  checkOkfh(),
42
+ checkPlatform(runtimePlatform),
41
43
  checkNode(),
42
44
  await checkExecutable("git", ["--version"], {
43
45
  id: "git",
44
46
  label: "git",
45
- missingMessage: "git executable was not found."
47
+ missingMessage: "git executable was not found.",
48
+ runtimePlatform,
49
+ runExecutable
46
50
  }),
47
51
  await checkExecutable("pnpm", ["--version"], {
48
52
  id: "pnpm",
49
53
  label: "pnpm",
50
54
  missingMessage: "pnpm executable was not found.",
51
- outputPrefix: "pnpm "
55
+ outputPrefix: "pnpm ",
56
+ runtimePlatform,
57
+ runExecutable
52
58
  })
53
59
  ];
54
60
  const workspaceRoot = await resolveDoctorWorkspace(options, checks);
@@ -81,6 +87,33 @@ function checkOkfh() {
81
87
  }
82
88
  };
83
89
  }
90
+ function checkPlatform(runtimePlatform) {
91
+ const platformLabel = platformLabelFor(runtimePlatform);
92
+ const supported = platformLabel !== null;
93
+ return {
94
+ id: "platform",
95
+ label: "Runtime platform",
96
+ status: supported ? "pass" : "fail",
97
+ message: supported ? `${platformLabel} is supported by OKF Harness.` : `Node platform ${runtimePlatform} is not supported by OKF Harness.`,
98
+ details: {
99
+ nodePlatform: runtimePlatform,
100
+ okfHarnessPlatform: platformLabel,
101
+ supported
102
+ }
103
+ };
104
+ }
105
+ function platformLabelFor(runtimePlatform) {
106
+ switch (runtimePlatform) {
107
+ case "darwin":
108
+ return "macOS";
109
+ case "win32":
110
+ return "Windows";
111
+ case "linux":
112
+ return "Linux";
113
+ default:
114
+ return null;
115
+ }
116
+ }
84
117
  function checkNode() {
85
118
  const version = process.versions.node;
86
119
  const major = Number.parseInt(version.split(".")[0] ?? "", 10);
@@ -103,7 +136,9 @@ function checkNode() {
103
136
  }
104
137
  async function checkExecutable(executable, args, options) {
105
138
  try {
106
- const { stdout, stderr } = await execFileAsync(executable, args);
139
+ const { stdout, stderr } = await options.runExecutable(executable, args, {
140
+ shell: shouldUseWindowsShell(options.runtimePlatform, executable)
141
+ });
107
142
  const output = `${stdout}${stderr}`.trim();
108
143
  return {
109
144
  id: options.id,
@@ -126,6 +161,16 @@ async function checkExecutable(executable, args, options) {
126
161
  };
127
162
  }
128
163
  }
164
+ async function runExecutableDefault(executable, args, options) {
165
+ const { stdout, stderr } = await execFileAsync(executable, args, {
166
+ shell: options.shell === true,
167
+ windowsHide: true
168
+ });
169
+ return { stdout: String(stdout), stderr: String(stderr) };
170
+ }
171
+ function shouldUseWindowsShell(runtimePlatform, executable) {
172
+ return runtimePlatform === "win32" && ["npm", "pnpm"].includes(executable);
173
+ }
129
174
  async function resolveDoctorWorkspace(options, checks) {
130
175
  try {
131
176
  return await resolveWorkspaceRoot({
@@ -422,6 +467,66 @@ function isRecord(value) {
422
467
  return typeof value === "object" && value !== null && !Array.isArray(value);
423
468
  }
424
469
 
470
+ // src/graph-open.ts
471
+ import { execFile as execFile2 } from "child_process";
472
+ var GRAPH_OPEN_FAILED = "GRAPH_OPEN_FAILED";
473
+ var GraphOpenError = class extends Error {
474
+ constructor(message, details = {}) {
475
+ super(message);
476
+ this.details = details;
477
+ this.name = "GraphOpenError";
478
+ }
479
+ details;
480
+ code = GRAPH_OPEN_FAILED;
481
+ };
482
+ async function openGraphReport(htmlPath, options = {}) {
483
+ const runtimePlatform = options.runtimePlatform ?? process.platform;
484
+ const runExecutable = options.runExecutable ?? runExecutableDefault2;
485
+ const command = graphOpenCommand(runtimePlatform, htmlPath);
486
+ if (command === null) {
487
+ throw new GraphOpenError(
488
+ `Node platform ${runtimePlatform} cannot automatically open graph reports.`,
489
+ { nodePlatform: runtimePlatform, htmlPath }
490
+ );
491
+ }
492
+ try {
493
+ await runExecutable(command.executable, command.args);
494
+ } catch (error) {
495
+ throw new GraphOpenError(
496
+ `Graph report was generated, but OKF Harness could not open it automatically: ${htmlPath}`,
497
+ {
498
+ nodePlatform: runtimePlatform,
499
+ htmlPath,
500
+ executable: command.executable,
501
+ error: error instanceof Error ? error.message : String(error)
502
+ }
503
+ );
504
+ }
505
+ }
506
+ function graphOpenCommand(runtimePlatform, htmlPath) {
507
+ switch (runtimePlatform) {
508
+ case "darwin":
509
+ return { executable: "open", args: [htmlPath] };
510
+ case "win32":
511
+ return { executable: "cmd.exe", args: ["/d", "/s", "/c", "start", "", htmlPath] };
512
+ case "linux":
513
+ return { executable: "xdg-open", args: [htmlPath] };
514
+ default:
515
+ return null;
516
+ }
517
+ }
518
+ async function runExecutableDefault2(executable, args) {
519
+ await new Promise((resolve, reject) => {
520
+ execFile2(executable, args, { windowsHide: true }, (error) => {
521
+ if (error !== null) {
522
+ reject(error);
523
+ return;
524
+ }
525
+ resolve();
526
+ });
527
+ });
528
+ }
529
+
425
530
  // src/options/index.ts
426
531
  function parseIntegerOption(value) {
427
532
  const parsed = Number.parseInt(value, 10);
@@ -722,7 +827,7 @@ async function runCli(argv = process.argv, io = {
722
827
  throw error;
723
828
  }
724
829
  });
725
- program.command("graph").description("Generate OKF backlinks data and a self-contained graph report.").storeOptionsAsProperties(false).option("--workspace <path>", "workspace path").option("--open", "open the generated graph report in the default macOS browser").option("--json", "write machine-readable JSON").action(async (command) => {
830
+ program.command("graph").description("Generate OKF backlinks data and a self-contained graph report.").storeOptionsAsProperties(false).option("--workspace <path>", "workspace path").option("--open", "open the generated graph report in the system default browser").option("--json", "write machine-readable JSON").action(async (command) => {
726
831
  const options = command.opts();
727
832
  let workspaceRoot = null;
728
833
  try {
@@ -747,7 +852,9 @@ async function runCli(argv = process.argv, io = {
747
852
  command: "graph",
748
853
  error,
749
854
  workspace: workspaceRoot,
750
- next: ["Check write permissions under .okfh and rerun okfh graph --json."],
855
+ next: error instanceof GraphOpenError ? [
856
+ "Open the generated graph HTML report manually, or rerun okfh graph --json without --open."
857
+ ] : ["Check write permissions under .okfh and rerun okfh graph --json."],
751
858
  json: options.json === true
752
859
  });
753
860
  if (handled) {
@@ -988,17 +1095,6 @@ async function runCli(argv = process.argv, io = {
988
1095
  restoreConsoleError();
989
1096
  }
990
1097
  }
991
- async function openGraphReport(htmlPath) {
992
- await new Promise((resolve, reject) => {
993
- execFile2("open", [htmlPath], (error) => {
994
- if (error !== null) {
995
- reject(error);
996
- return;
997
- }
998
- resolve();
999
- });
1000
- });
1001
- }
1002
1098
  function captureCommanderConsoleError(capturedErrors) {
1003
1099
  const originalConsoleError = console.error;
1004
1100
  console.error = (...args) => {
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  packageInfo,
3
3
  runCli
4
- } from "./chunk-CU2XPEBG.js";
4
+ } from "./chunk-JFVFODXE.js";
5
5
  export {
6
6
  packageInfo,
7
7
  runCli
package/dist/main.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runCli
4
- } from "./chunk-CU2XPEBG.js";
4
+ } from "./chunk-JFVFODXE.js";
5
5
 
6
6
  // src/main.ts
7
7
  process.exitCode = await runCli(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@okf-harness/cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "The okfh command-line package for local OKF Harness workspaces.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -25,6 +25,8 @@
25
25
  "claude-code",
26
26
  "codex",
27
27
  "macos",
28
+ "windows",
29
+ "linux",
28
30
  "knowledge-management"
29
31
  ],
30
32
  "publishConfig": {
@@ -50,8 +52,8 @@
50
52
  "prepublishOnly": "pnpm run build"
51
53
  },
52
54
  "dependencies": {
53
- "@okf-harness/agent-pack": "0.1.0",
54
- "@okf-harness/core": "0.1.0",
55
+ "@okf-harness/agent-pack": "0.2.0",
56
+ "@okf-harness/core": "0.2.0",
55
57
  "commander": "4.1.1"
56
58
  }
57
59
  }