@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 +20 -2
- package/dist/{chunk-CU2XPEBG.js → chunk-JFVFODXE.js} +113 -17
- package/dist/index.js +1 -1
- package/dist/main.js +1 -1
- package/package.json +5 -3
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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:
|
|
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
package/dist/main.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@okf-harness/cli",
|
|
3
|
-
"version": "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.
|
|
54
|
-
"@okf-harness/core": "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
|
}
|