@olorehq/olore 0.1.5 → 0.2.1
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 +74 -0
- package/dist/cli.js +464 -169
- package/package.json +3 -3
package/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# olore
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
██████╗ ██╗ ██████╗ ██████╗ ███████╗
|
|
5
|
+
██╔═══██╗██║ ██╔═══██╗██╔══██╗██╔════╝
|
|
6
|
+
██║ ██║██║ ██║ ██║██████╔╝█████╗
|
|
7
|
+
██║ ██║██║ ██║ ██║██╔══██╗██╔══╝
|
|
8
|
+
╚██████╔╝███████╗╚██████╔╝██║ ██║███████╗
|
|
9
|
+
╚═════╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝
|
|
10
|
+
O(pen) Lore for AI Agents
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Documentation package manager for AI coding agents. Local-first. Offline-ready.
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g @olorehq/olore
|
|
19
|
+
olore install prisma
|
|
20
|
+
olore inject
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
That's it. Your agent now has Prisma docs. No hallucinations.
|
|
24
|
+
|
|
25
|
+
## Why olore?
|
|
26
|
+
|
|
27
|
+
Your AI coding agent makes decisions about which tools to invoke. Sometimes it decides wrong — it skips the tool, hallucinates an API, or calls it with bad arguments.
|
|
28
|
+
|
|
29
|
+
**Passive context beats skills.** Vercel's agentic coding eval showed agents with passive documentation context scored **100%** vs **53%** with tool-based retrieval. The difference: passive context is always there. The agent doesn't have to decide to look it up.
|
|
30
|
+
|
|
31
|
+
`olore inject` embeds a compact documentation index directly into your `AGENTS.md` / `CLAUDE.md`. The agent reads it automatically on every session — no invocation decision needed. No network. No retrieval pipeline.
|
|
32
|
+
|
|
33
|
+
- **Version-pinned** — same docs, every run, every machine
|
|
34
|
+
- **Offline** — works on planes, in CI, behind firewalls
|
|
35
|
+
- **Local-first** — docs live in your project, not on someone's server
|
|
36
|
+
- **Any agent** — Claude Code, Codex, OpenCode, anything that reads markdown
|
|
37
|
+
|
|
38
|
+
## Available Packages
|
|
39
|
+
|
|
40
|
+
`prisma` · `nextjs` · `zod` · `drizzle` · `langchain` · `tanstack-query` · `claude-code` · `codex` · `opencode` · `cargo` · `agentskills`
|
|
41
|
+
|
|
42
|
+
More on the [registry](https://github.com/olorehq/olore). Contributions welcome.
|
|
43
|
+
|
|
44
|
+
## Supported Agents
|
|
45
|
+
|
|
46
|
+
- **Claude Code** — injects into `CLAUDE.md`
|
|
47
|
+
- **Codex** — injects into `AGENTS.md`
|
|
48
|
+
- **OpenCode** — injects into `AGENTS.md`
|
|
49
|
+
|
|
50
|
+
## Commands
|
|
51
|
+
|
|
52
|
+
| Command | Description |
|
|
53
|
+
|---|---|
|
|
54
|
+
| `olore install <pkg>` | Install a documentation package |
|
|
55
|
+
| `olore inject` | Inject doc indexes into AGENTS.md / CLAUDE.md |
|
|
56
|
+
| `olore inject --remove` | Remove injected content |
|
|
57
|
+
| `olore list` | List installed packages |
|
|
58
|
+
| `olore remove <pkg>` | Remove a package |
|
|
59
|
+
| `olore search` | Browse available packages |
|
|
60
|
+
| `olore doctor` | Diagnose issues |
|
|
61
|
+
|
|
62
|
+
## Links
|
|
63
|
+
|
|
64
|
+
- [GitHub](https://github.com/olorehq/olore)
|
|
65
|
+
- [Website](https://www.olore.dev)
|
|
66
|
+
- [Contributing](https://github.com/olorehq/olore/blob/main/CONTRIBUTING.md)
|
|
67
|
+
|
|
68
|
+
## License
|
|
69
|
+
|
|
70
|
+
MIT
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
> *"May the Skill be with you."*
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { createRequire } from "module";
|
|
5
5
|
import { Command } from "commander";
|
|
6
|
-
import
|
|
6
|
+
import pc12 from "picocolors";
|
|
7
7
|
|
|
8
8
|
// src/commands/doctor.ts
|
|
9
9
|
import pc from "picocolors";
|
|
@@ -705,11 +705,146 @@ Initialized olore package: `) + pc2.cyan(fullName));
|
|
|
705
705
|
console.log("");
|
|
706
706
|
}
|
|
707
707
|
|
|
708
|
-
// src/commands/
|
|
708
|
+
// src/commands/inject.ts
|
|
709
|
+
import fs6 from "fs";
|
|
709
710
|
import path6 from "path";
|
|
710
|
-
import fs6 from "fs-extra";
|
|
711
|
-
import ora from "ora";
|
|
712
711
|
import pc3 from "picocolors";
|
|
712
|
+
var MARKER_START = "<!-- olore:start -->";
|
|
713
|
+
var MARKER_END = "<!-- olore:end -->";
|
|
714
|
+
var TARGET_FILES = ["AGENTS.md", "CLAUDE.md"];
|
|
715
|
+
var COMPACT_HEADER = "[olore docs]|STOP. Read these docs before answering \u2014 your training data may be outdated.|Format: keywords=path. For dir paths (ending /), list dir then read files.";
|
|
716
|
+
function extractSectionLines(content) {
|
|
717
|
+
return content.split("\n").filter((line) => line.startsWith("@")).filter((line) => line.length > 0);
|
|
718
|
+
}
|
|
719
|
+
function renderCompactBlock(sectionLines, name, version2, rootPath) {
|
|
720
|
+
return `[${name}@${version2} root:${rootPath}]${sectionLines.join("")}`;
|
|
721
|
+
}
|
|
722
|
+
async function buildInjectedContent() {
|
|
723
|
+
const packages = await getInstalledPackages();
|
|
724
|
+
const packageLines = [];
|
|
725
|
+
let count = 0;
|
|
726
|
+
for (const pkg of packages) {
|
|
727
|
+
const indexPath = path6.join(pkg.path, "INDEX.md");
|
|
728
|
+
if (!fs6.existsSync(indexPath)) continue;
|
|
729
|
+
const rawContent = fs6.readFileSync(indexPath, "utf-8");
|
|
730
|
+
const sectionLines = extractSectionLines(rawContent);
|
|
731
|
+
if (sectionLines.length === 0) continue;
|
|
732
|
+
const resolvedBase = fs6.realpathSync(pkg.path);
|
|
733
|
+
const rootPath = path6.join(resolvedBase, "contents");
|
|
734
|
+
packageLines.push(renderCompactBlock(sectionLines, pkg.name, pkg.version, rootPath));
|
|
735
|
+
count++;
|
|
736
|
+
}
|
|
737
|
+
if (count === 0) {
|
|
738
|
+
return { content: "", count: 0 };
|
|
739
|
+
}
|
|
740
|
+
const combined = [MARKER_START, COMPACT_HEADER, ...packageLines, MARKER_END].join("\n");
|
|
741
|
+
return { content: combined, count };
|
|
742
|
+
}
|
|
743
|
+
function smartMerge(filePath, injectedContent) {
|
|
744
|
+
if (!fs6.existsSync(filePath)) {
|
|
745
|
+
fs6.writeFileSync(filePath, injectedContent + "\n", "utf-8");
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
const existing = fs6.readFileSync(filePath, "utf-8");
|
|
749
|
+
const startIdx = existing.indexOf(MARKER_START);
|
|
750
|
+
const endIdx = existing.indexOf(MARKER_END);
|
|
751
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
752
|
+
const before = existing.slice(0, startIdx);
|
|
753
|
+
const after = existing.slice(endIdx + MARKER_END.length);
|
|
754
|
+
fs6.writeFileSync(filePath, before + injectedContent + after, "utf-8");
|
|
755
|
+
} else {
|
|
756
|
+
const separator = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
757
|
+
fs6.writeFileSync(filePath, existing + separator + injectedContent + "\n", "utf-8");
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
function removeSection(filePath) {
|
|
761
|
+
if (!fs6.existsSync(filePath)) return false;
|
|
762
|
+
const content = fs6.readFileSync(filePath, "utf-8");
|
|
763
|
+
const startIdx = content.indexOf(MARKER_START);
|
|
764
|
+
const endIdx = content.indexOf(MARKER_END);
|
|
765
|
+
if (startIdx === -1 || endIdx === -1) return false;
|
|
766
|
+
const before = content.slice(0, startIdx);
|
|
767
|
+
const after = content.slice(endIdx + MARKER_END.length);
|
|
768
|
+
const result = (before + after).replace(/\n{3,}/g, "\n\n").trim();
|
|
769
|
+
if (result.length === 0) {
|
|
770
|
+
fs6.unlinkSync(filePath);
|
|
771
|
+
} else {
|
|
772
|
+
fs6.writeFileSync(filePath, result + "\n", "utf-8");
|
|
773
|
+
}
|
|
774
|
+
return true;
|
|
775
|
+
}
|
|
776
|
+
async function inject(options) {
|
|
777
|
+
const cwd = process.cwd();
|
|
778
|
+
if (options.remove) {
|
|
779
|
+
const filesRemoved = [];
|
|
780
|
+
for (const fileName of TARGET_FILES) {
|
|
781
|
+
const filePath = path6.join(cwd, fileName);
|
|
782
|
+
if (removeSection(filePath)) {
|
|
783
|
+
filesRemoved.push(fileName);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
if (options.json) {
|
|
787
|
+
const result = {
|
|
788
|
+
packagesFound: 0,
|
|
789
|
+
packagesInjected: 0,
|
|
790
|
+
filesWritten: filesRemoved,
|
|
791
|
+
removed: true
|
|
792
|
+
};
|
|
793
|
+
console.log(JSON.stringify(result, null, 2));
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
if (filesRemoved.length === 0) {
|
|
797
|
+
console.log(pc3.yellow("No olore sections found in project files."));
|
|
798
|
+
} else {
|
|
799
|
+
console.log(pc3.green(`Removed olore sections from: ${filesRemoved.join(", ")}`));
|
|
800
|
+
}
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
const { content, count } = await buildInjectedContent();
|
|
804
|
+
if (count === 0) {
|
|
805
|
+
if (options.json) {
|
|
806
|
+
const result = {
|
|
807
|
+
packagesFound: 0,
|
|
808
|
+
packagesInjected: 0,
|
|
809
|
+
filesWritten: [],
|
|
810
|
+
removed: false
|
|
811
|
+
};
|
|
812
|
+
console.log(JSON.stringify(result, null, 2));
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
console.log(pc3.yellow("No installed packages have INDEX.md files."));
|
|
816
|
+
console.log(pc3.gray("Build packages with the latest templates to generate INDEX.md."));
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
const filesWritten = [];
|
|
820
|
+
for (const fileName of TARGET_FILES) {
|
|
821
|
+
const filePath = path6.join(cwd, fileName);
|
|
822
|
+
smartMerge(filePath, content);
|
|
823
|
+
filesWritten.push(fileName);
|
|
824
|
+
}
|
|
825
|
+
if (options.json) {
|
|
826
|
+
const result = {
|
|
827
|
+
packagesFound: count,
|
|
828
|
+
packagesInjected: count,
|
|
829
|
+
filesWritten,
|
|
830
|
+
removed: false
|
|
831
|
+
};
|
|
832
|
+
console.log(JSON.stringify(result, null, 2));
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
console.log(
|
|
836
|
+
pc3.green(
|
|
837
|
+
`Injected ${count} package${count === 1 ? "" : "s"} into: ${filesWritten.join(", ")}`
|
|
838
|
+
)
|
|
839
|
+
);
|
|
840
|
+
console.log(pc3.gray("Run olore inject --remove to clean up."));
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// src/commands/install.ts
|
|
844
|
+
import path7 from "path";
|
|
845
|
+
import fs7 from "fs-extra";
|
|
846
|
+
import ora from "ora";
|
|
847
|
+
import pc5 from "picocolors";
|
|
713
848
|
|
|
714
849
|
// src/core/registry.ts
|
|
715
850
|
var RegistryError = class extends Error {
|
|
@@ -788,25 +923,174 @@ async function resolveVersion(name, version2) {
|
|
|
788
923
|
return versionInfo;
|
|
789
924
|
}
|
|
790
925
|
|
|
926
|
+
// src/core/version-check.ts
|
|
927
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
928
|
+
import { homedir } from "os";
|
|
929
|
+
import { join } from "path";
|
|
930
|
+
import pc4 from "picocolors";
|
|
931
|
+
|
|
932
|
+
// package.json
|
|
933
|
+
var package_default = {
|
|
934
|
+
name: "@olorehq/olore",
|
|
935
|
+
version: "0.2.1",
|
|
936
|
+
description: "Universal documentation for any AI coding agent",
|
|
937
|
+
keywords: [
|
|
938
|
+
"ai",
|
|
939
|
+
"documentation",
|
|
940
|
+
"claude",
|
|
941
|
+
"codex",
|
|
942
|
+
"coding-assistant",
|
|
943
|
+
"context",
|
|
944
|
+
"llm"
|
|
945
|
+
],
|
|
946
|
+
license: "MIT",
|
|
947
|
+
author: "olorehq",
|
|
948
|
+
repository: {
|
|
949
|
+
type: "git",
|
|
950
|
+
url: "git+https://github.com/olorehq/olore.git",
|
|
951
|
+
directory: "cli"
|
|
952
|
+
},
|
|
953
|
+
homepage: "https://www.olore.dev",
|
|
954
|
+
type: "module",
|
|
955
|
+
files: [
|
|
956
|
+
"dist"
|
|
957
|
+
],
|
|
958
|
+
bin: {
|
|
959
|
+
olore: "dist/cli.js"
|
|
960
|
+
},
|
|
961
|
+
scripts: {
|
|
962
|
+
build: "tsup",
|
|
963
|
+
"build:bin": "bun build src/cli.ts --compile --outfile dist/olore",
|
|
964
|
+
"build:bin:all": "npm run build:bin:darwin-arm64 && npm run build:bin:darwin-x64 && npm run build:bin:linux-x64 && npm run build:bin:linux-arm64",
|
|
965
|
+
"build:bin:darwin-arm64": "bun build src/cli.ts --compile --target=bun-darwin-arm64 --outfile dist/olore-darwin-arm64",
|
|
966
|
+
"build:bin:darwin-x64": "bun build src/cli.ts --compile --target=bun-darwin-x64 --outfile dist/olore-darwin-x64",
|
|
967
|
+
"build:bin:linux-arm64": "bun build src/cli.ts --compile --target=bun-linux-arm64 --outfile dist/olore-linux-arm64",
|
|
968
|
+
"build:bin:linux-x64": "bun build src/cli.ts --compile --target=bun-linux-x64 --outfile dist/olore-linux-x64",
|
|
969
|
+
dev: "tsup --watch",
|
|
970
|
+
format: "prettier --write src/",
|
|
971
|
+
"format:check": "prettier --check src/",
|
|
972
|
+
lint: "eslint src/",
|
|
973
|
+
test: "vitest",
|
|
974
|
+
typecheck: "tsc --noEmit",
|
|
975
|
+
"generate-registry": "npx tsx scripts/generate-registry.ts"
|
|
976
|
+
},
|
|
977
|
+
dependencies: {
|
|
978
|
+
commander: "^12.1.0",
|
|
979
|
+
"fs-extra": "^11.3.3",
|
|
980
|
+
ora: "^9.0.0",
|
|
981
|
+
picocolors: "^1.1.1",
|
|
982
|
+
tar: "^7.4.3"
|
|
983
|
+
},
|
|
984
|
+
devDependencies: {
|
|
985
|
+
"@ianvs/prettier-plugin-sort-imports": "^4.7.0",
|
|
986
|
+
"@types/fs-extra": "^11.0.4",
|
|
987
|
+
"@types/node": "^22.10.7",
|
|
988
|
+
prettier: "^3.8.0",
|
|
989
|
+
"prettier-plugin-packagejson": "^2.5.22",
|
|
990
|
+
tsup: "^8.3.5",
|
|
991
|
+
typescript: "^5.7.3",
|
|
992
|
+
vitest: "^2.1.8"
|
|
993
|
+
},
|
|
994
|
+
engines: {
|
|
995
|
+
node: ">=18"
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
|
|
999
|
+
// src/core/version-check.ts
|
|
1000
|
+
var currentVersion = package_default.version;
|
|
1001
|
+
var NPM_REGISTRY = "https://registry.npmjs.org/@olorehq/olore";
|
|
1002
|
+
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
1003
|
+
var CACHE_DIR = join(homedir(), ".olore");
|
|
1004
|
+
var CACHE_FILE = join(CACHE_DIR, "version-check.json");
|
|
1005
|
+
var FETCH_TIMEOUT = 3e3;
|
|
1006
|
+
function readCache() {
|
|
1007
|
+
try {
|
|
1008
|
+
if (existsSync(CACHE_FILE)) {
|
|
1009
|
+
return JSON.parse(readFileSync(CACHE_FILE, "utf-8"));
|
|
1010
|
+
}
|
|
1011
|
+
} catch {
|
|
1012
|
+
}
|
|
1013
|
+
return null;
|
|
1014
|
+
}
|
|
1015
|
+
function writeCache(cache) {
|
|
1016
|
+
try {
|
|
1017
|
+
if (!existsSync(CACHE_DIR)) {
|
|
1018
|
+
mkdirSync(CACHE_DIR, { recursive: true });
|
|
1019
|
+
}
|
|
1020
|
+
writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
1021
|
+
} catch {
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
async function fetchLatestVersion() {
|
|
1025
|
+
try {
|
|
1026
|
+
const controller = new AbortController();
|
|
1027
|
+
const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT);
|
|
1028
|
+
const response = await fetch(NPM_REGISTRY, {
|
|
1029
|
+
signal: controller.signal,
|
|
1030
|
+
headers: { Accept: "application/json" }
|
|
1031
|
+
});
|
|
1032
|
+
clearTimeout(timeoutId);
|
|
1033
|
+
if (!response.ok) return null;
|
|
1034
|
+
const data = await response.json();
|
|
1035
|
+
return data["dist-tags"]?.latest || null;
|
|
1036
|
+
} catch {
|
|
1037
|
+
return null;
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
function compareVersions(current, latest) {
|
|
1041
|
+
const parseVersion = (v) => v.replace(/^v/, "").split(".").map((n) => parseInt(n, 10) || 0);
|
|
1042
|
+
const curr = parseVersion(current);
|
|
1043
|
+
const lat = parseVersion(latest);
|
|
1044
|
+
for (let i = 0; i < 3; i++) {
|
|
1045
|
+
if ((curr[i] || 0) < (lat[i] || 0)) return -1;
|
|
1046
|
+
if ((curr[i] || 0) > (lat[i] || 0)) return 1;
|
|
1047
|
+
}
|
|
1048
|
+
return 0;
|
|
1049
|
+
}
|
|
1050
|
+
async function checkForUpdates() {
|
|
1051
|
+
const cache = readCache();
|
|
1052
|
+
const now = Date.now();
|
|
1053
|
+
if (cache && now - cache.lastCheck < CHECK_INTERVAL_MS) {
|
|
1054
|
+
if (cache.latestVersion && compareVersions(currentVersion, cache.latestVersion) < 0) {
|
|
1055
|
+
printUpdateNotice(cache.latestVersion);
|
|
1056
|
+
}
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
const latestVersion = await fetchLatestVersion();
|
|
1060
|
+
writeCache({
|
|
1061
|
+
lastCheck: now,
|
|
1062
|
+
latestVersion
|
|
1063
|
+
});
|
|
1064
|
+
if (latestVersion && compareVersions(currentVersion, latestVersion) < 0) {
|
|
1065
|
+
printUpdateNotice(latestVersion);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
function printUpdateNotice(latestVersion) {
|
|
1069
|
+
console.log();
|
|
1070
|
+
console.log(
|
|
1071
|
+
pc4.yellow(`\u26A0\uFE0F Update available: ${currentVersion} \u2192 ${latestVersion}`) + pc4.gray(` \u2014 Run `) + pc4.cyan(`npm update -g @olorehq/olore`) + pc4.gray(` to update`)
|
|
1072
|
+
);
|
|
1073
|
+
}
|
|
1074
|
+
|
|
791
1075
|
// src/commands/install.ts
|
|
792
1076
|
async function installFromLocal(localPath) {
|
|
793
1077
|
const fullPath = expandPath(localPath);
|
|
794
|
-
if (!await
|
|
1078
|
+
if (!await fs7.pathExists(fullPath)) {
|
|
795
1079
|
throw new Error(`Path not found: ${fullPath}`);
|
|
796
1080
|
}
|
|
797
|
-
const stat = await
|
|
1081
|
+
const stat = await fs7.stat(fullPath);
|
|
798
1082
|
if (!stat.isDirectory()) {
|
|
799
1083
|
throw new Error(`Not a directory: ${fullPath}`);
|
|
800
1084
|
}
|
|
801
|
-
const lockPath =
|
|
802
|
-
if (!await
|
|
1085
|
+
const lockPath = path7.join(fullPath, "olore-lock.json");
|
|
1086
|
+
if (!await fs7.pathExists(lockPath)) {
|
|
803
1087
|
throw new Error(`Missing olore-lock.json in ${fullPath}`);
|
|
804
1088
|
}
|
|
805
|
-
const skillPath =
|
|
806
|
-
if (!await
|
|
1089
|
+
const skillPath = path7.join(fullPath, "SKILL.md");
|
|
1090
|
+
if (!await fs7.pathExists(skillPath)) {
|
|
807
1091
|
throw new Error(`Missing SKILL.md in ${fullPath}. Run /generate-agent-skills first.`);
|
|
808
1092
|
}
|
|
809
|
-
const lock = await
|
|
1093
|
+
const lock = await fs7.readJson(lockPath);
|
|
810
1094
|
const packageName = lock.name;
|
|
811
1095
|
const packageVersion = lock.version;
|
|
812
1096
|
if (!packageName) {
|
|
@@ -816,57 +1100,58 @@ async function installFromLocal(localPath) {
|
|
|
816
1100
|
throw new Error(`Invalid olore-lock.json: missing "version" field`);
|
|
817
1101
|
}
|
|
818
1102
|
const skillName = `olore-${packageName}-${packageVersion}`;
|
|
819
|
-
const skillContent = await
|
|
1103
|
+
const skillContent = await fs7.readFile(skillPath, "utf-8");
|
|
820
1104
|
const nameMatch = skillContent.match(/^name:\s*(.+)$/m);
|
|
821
1105
|
const skillMdName = nameMatch ? nameMatch[1].trim() : null;
|
|
822
1106
|
if (skillMdName !== skillName) {
|
|
823
|
-
console.log(
|
|
1107
|
+
console.log(pc5.yellow(`
|
|
824
1108
|
Warning: SKILL.md name mismatch`));
|
|
825
|
-
console.log(
|
|
826
|
-
console.log(
|
|
827
|
-
console.log(
|
|
1109
|
+
console.log(pc5.gray(` Expected: ${skillName}`));
|
|
1110
|
+
console.log(pc5.gray(` Found: ${skillMdName || "(none)"}`));
|
|
1111
|
+
console.log(pc5.yellow(` Updating SKILL.md to fix...`));
|
|
828
1112
|
const updatedContent = skillMdName ? skillContent.replace(/^name:\s*.+$/m, `name: ${skillName}`) : skillContent.replace(/^---\n/, `---
|
|
829
1113
|
name: ${skillName}
|
|
830
1114
|
`);
|
|
831
|
-
await
|
|
1115
|
+
await fs7.writeFile(skillPath, updatedContent);
|
|
832
1116
|
}
|
|
833
|
-
console.log(
|
|
1117
|
+
console.log(pc5.bold(`
|
|
834
1118
|
Installing ${packageName}@${packageVersion} from local path...
|
|
835
1119
|
`));
|
|
836
1120
|
const agents = detectAgents();
|
|
837
1121
|
if (agents.length === 0) {
|
|
838
|
-
console.log(
|
|
1122
|
+
console.log(pc5.yellow("No agents detected. Creating directories anyway."));
|
|
839
1123
|
}
|
|
840
1124
|
const agentPaths = getAgentPaths();
|
|
841
1125
|
const olorePath = getOlorePackagePath(packageName, packageVersion);
|
|
842
1126
|
const spinner = ora("Copying to ~/.olore...").start();
|
|
843
|
-
await
|
|
844
|
-
await
|
|
845
|
-
await
|
|
846
|
-
spinner.succeed(`Copied to ${
|
|
1127
|
+
await fs7.ensureDir(path7.dirname(olorePath));
|
|
1128
|
+
await fs7.remove(olorePath);
|
|
1129
|
+
await fs7.copy(fullPath, olorePath);
|
|
1130
|
+
spinner.succeed(`Copied to ${pc5.gray(olorePath)}`);
|
|
847
1131
|
const linkSpinner = ora("Linking to agent directories...").start();
|
|
848
1132
|
const linked = [];
|
|
849
1133
|
for (const [agent, skillsDir] of Object.entries(agentPaths)) {
|
|
850
|
-
const targetDir =
|
|
851
|
-
await
|
|
852
|
-
await
|
|
1134
|
+
const targetDir = path7.join(skillsDir, skillName);
|
|
1135
|
+
await fs7.ensureDir(skillsDir);
|
|
1136
|
+
await fs7.remove(targetDir);
|
|
853
1137
|
await linkOrCopy(olorePath, targetDir);
|
|
854
|
-
linked.push(`${
|
|
1138
|
+
linked.push(`${pc5.green("\u2713")} ${agent} ${pc5.gray("\u2192")} ${pc5.gray(targetDir)}`);
|
|
855
1139
|
}
|
|
856
1140
|
linkSpinner.stop();
|
|
857
1141
|
linked.forEach((line) => console.log(` ${line}`));
|
|
858
|
-
console.log(
|
|
1142
|
+
console.log(pc5.gray(` \u2514\u2500 all linked to ${olorePath}`));
|
|
859
1143
|
console.log("");
|
|
860
|
-
console.log(
|
|
1144
|
+
console.log(pc5.green("Installation complete!"));
|
|
861
1145
|
console.log("");
|
|
862
|
-
console.log(
|
|
863
|
-
console.log(
|
|
864
|
-
console.log(
|
|
865
|
-
console.log(
|
|
1146
|
+
console.log(pc5.gray("Skill is now available as:"));
|
|
1147
|
+
console.log(pc5.cyan(` /${skillName}`) + pc5.gray(" (Claude Code)"));
|
|
1148
|
+
console.log(pc5.cyan(` $${skillName}`) + pc5.gray(" (Codex)"));
|
|
1149
|
+
console.log(pc5.cyan(` ${skillName}`) + pc5.gray(" (OpenCode)"));
|
|
1150
|
+
await checkForUpdates();
|
|
866
1151
|
}
|
|
867
1152
|
async function install(pkg, options) {
|
|
868
1153
|
if (options.force) {
|
|
869
|
-
console.log(
|
|
1154
|
+
console.log(pc5.cyan("\n\u2728 May the Skill be with you.\n"));
|
|
870
1155
|
}
|
|
871
1156
|
if (isLocalPath(pkg)) {
|
|
872
1157
|
await installFromLocal(pkg);
|
|
@@ -912,7 +1197,7 @@ function findSimilarPackages(input, packages, maxResults = 3) {
|
|
|
912
1197
|
async function installFromRemote(pkg, optionsVersion) {
|
|
913
1198
|
const { name, version: specVersion } = parsePackageSpec(pkg);
|
|
914
1199
|
const requestedVersion = optionsVersion || specVersion || "latest";
|
|
915
|
-
console.log(
|
|
1200
|
+
console.log(pc5.bold(`
|
|
916
1201
|
Installing ${name}@${requestedVersion} from registry...
|
|
917
1202
|
`));
|
|
918
1203
|
const spinner = ora("Fetching package info...").start();
|
|
@@ -924,32 +1209,32 @@ Installing ${name}@${requestedVersion} from registry...
|
|
|
924
1209
|
spinner.fail("Failed to resolve package");
|
|
925
1210
|
if (error instanceof RegistryError) {
|
|
926
1211
|
if (error.code === "NOT_FOUND") {
|
|
927
|
-
console.log(
|
|
1212
|
+
console.log(pc5.yellow(`
|
|
928
1213
|
Package "${name}" not found in registry.`));
|
|
929
1214
|
try {
|
|
930
1215
|
const index = await fetchPackageIndex();
|
|
931
1216
|
const similar = findSimilarPackages(name, index.packages);
|
|
932
1217
|
if (similar.length > 0) {
|
|
933
|
-
console.log(
|
|
1218
|
+
console.log(pc5.bold("\nDid you mean?"));
|
|
934
1219
|
for (const pkg2 of similar) {
|
|
935
|
-
console.log(` ${
|
|
1220
|
+
console.log(` ${pc5.cyan(pkg2.name)} ${pc5.gray("-")} ${pc5.gray(pkg2.description)}`);
|
|
936
1221
|
}
|
|
937
1222
|
}
|
|
938
1223
|
} catch {
|
|
939
1224
|
}
|
|
940
1225
|
console.log(
|
|
941
|
-
|
|
1226
|
+
pc5.gray("\nRun ") + pc5.cyan("olore search") + pc5.gray(" to see all available packages.")
|
|
942
1227
|
);
|
|
943
|
-
console.log(
|
|
944
|
-
console.log(
|
|
1228
|
+
console.log(pc5.gray("\nFor local packages, use a path:"));
|
|
1229
|
+
console.log(pc5.cyan(` olore install ./vault/packages/${name}/<version>`));
|
|
945
1230
|
console.log("");
|
|
946
1231
|
} else if (error.code === "NETWORK_ERROR" || error.code === "TIMEOUT") {
|
|
947
|
-
console.log(
|
|
1232
|
+
console.log(pc5.red(`
|
|
948
1233
|
Network error: ${error.message}`));
|
|
949
|
-
console.log(
|
|
1234
|
+
console.log(pc5.gray("Please check your internet connection and try again."));
|
|
950
1235
|
}
|
|
951
1236
|
} else {
|
|
952
|
-
console.log(
|
|
1237
|
+
console.log(pc5.red(`
|
|
953
1238
|
Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
954
1239
|
}
|
|
955
1240
|
process.exit(1);
|
|
@@ -957,26 +1242,26 @@ Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
|
957
1242
|
const skillName = `olore-${name}-${versionInfo.version}`;
|
|
958
1243
|
const agents = detectAgents();
|
|
959
1244
|
if (agents.length === 0) {
|
|
960
|
-
console.log(
|
|
1245
|
+
console.log(pc5.yellow("No agents detected. Creating directories anyway."));
|
|
961
1246
|
}
|
|
962
1247
|
const agentPaths = getAgentPaths();
|
|
963
1248
|
const olorePath = getOlorePackagePath(name, versionInfo.version);
|
|
964
1249
|
const downloadSpinner = ora("Downloading package...").start();
|
|
965
1250
|
try {
|
|
966
1251
|
await downloadAndInstall(versionInfo.downloadUrl, olorePath, versionInfo.integrity);
|
|
967
|
-
downloadSpinner.succeed(`Downloaded to ${
|
|
1252
|
+
downloadSpinner.succeed(`Downloaded to ${pc5.gray(olorePath)}`);
|
|
968
1253
|
} catch (error) {
|
|
969
1254
|
downloadSpinner.fail("Download failed");
|
|
970
1255
|
if (error instanceof DownloadError) {
|
|
971
1256
|
if (error.code === "CHECKSUM_MISMATCH") {
|
|
972
|
-
console.log(
|
|
973
|
-
console.log(
|
|
1257
|
+
console.log(pc5.red("\nChecksum verification failed!"));
|
|
1258
|
+
console.log(pc5.gray("The downloaded package may be corrupted or tampered with."));
|
|
974
1259
|
} else {
|
|
975
|
-
console.log(
|
|
1260
|
+
console.log(pc5.red(`
|
|
976
1261
|
Download error: ${error.message}`));
|
|
977
1262
|
}
|
|
978
1263
|
} else {
|
|
979
|
-
console.log(
|
|
1264
|
+
console.log(pc5.red(`
|
|
980
1265
|
Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
981
1266
|
}
|
|
982
1267
|
process.exit(1);
|
|
@@ -984,47 +1269,48 @@ Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
|
984
1269
|
const linkSpinner = ora("Linking to agent directories...").start();
|
|
985
1270
|
const linked = [];
|
|
986
1271
|
for (const [agent, skillsDir] of Object.entries(agentPaths)) {
|
|
987
|
-
const targetDir =
|
|
988
|
-
await
|
|
989
|
-
await
|
|
1272
|
+
const targetDir = path7.join(skillsDir, skillName);
|
|
1273
|
+
await fs7.ensureDir(skillsDir);
|
|
1274
|
+
await fs7.remove(targetDir);
|
|
990
1275
|
await linkOrCopy(olorePath, targetDir);
|
|
991
|
-
linked.push(`${
|
|
1276
|
+
linked.push(`${pc5.green("\u2713")} ${agent} ${pc5.gray("\u2192")} ${pc5.gray(targetDir)}`);
|
|
992
1277
|
}
|
|
993
1278
|
linkSpinner.stop();
|
|
994
1279
|
linked.forEach((line) => console.log(` ${line}`));
|
|
995
|
-
console.log(
|
|
1280
|
+
console.log(pc5.gray(` \u2514\u2500 all linked to ${olorePath}`));
|
|
996
1281
|
console.log("");
|
|
997
|
-
console.log(
|
|
1282
|
+
console.log(pc5.green("Installation complete!"));
|
|
998
1283
|
console.log("");
|
|
999
|
-
console.log(
|
|
1000
|
-
console.log(
|
|
1001
|
-
console.log(
|
|
1002
|
-
console.log(
|
|
1284
|
+
console.log(pc5.gray("Skill is now available as:"));
|
|
1285
|
+
console.log(pc5.cyan(` /${skillName}`) + pc5.gray(" (Claude Code)"));
|
|
1286
|
+
console.log(pc5.cyan(` $${skillName}`) + pc5.gray(" (Codex)"));
|
|
1287
|
+
console.log(pc5.cyan(` ${skillName}`) + pc5.gray(" (OpenCode)"));
|
|
1288
|
+
await checkForUpdates();
|
|
1003
1289
|
}
|
|
1004
1290
|
|
|
1005
1291
|
// src/commands/link.ts
|
|
1006
|
-
import
|
|
1007
|
-
import
|
|
1292
|
+
import path8 from "path";
|
|
1293
|
+
import fs8 from "fs-extra";
|
|
1008
1294
|
import ora2 from "ora";
|
|
1009
|
-
import
|
|
1295
|
+
import pc6 from "picocolors";
|
|
1010
1296
|
async function link(localPath) {
|
|
1011
1297
|
const fullPath = expandPath(localPath);
|
|
1012
|
-
if (!await
|
|
1298
|
+
if (!await fs8.pathExists(fullPath)) {
|
|
1013
1299
|
throw new Error(`Path not found: ${fullPath}`);
|
|
1014
1300
|
}
|
|
1015
|
-
const stat = await
|
|
1301
|
+
const stat = await fs8.stat(fullPath);
|
|
1016
1302
|
if (!stat.isDirectory()) {
|
|
1017
1303
|
throw new Error(`Not a directory: ${fullPath}`);
|
|
1018
1304
|
}
|
|
1019
|
-
const lockPath =
|
|
1020
|
-
if (!await
|
|
1305
|
+
const lockPath = path8.join(fullPath, "olore-lock.json");
|
|
1306
|
+
if (!await fs8.pathExists(lockPath)) {
|
|
1021
1307
|
throw new Error(`Missing olore-lock.json in ${fullPath}`);
|
|
1022
1308
|
}
|
|
1023
|
-
const skillPath =
|
|
1024
|
-
if (!await
|
|
1309
|
+
const skillPath = path8.join(fullPath, "SKILL.md");
|
|
1310
|
+
if (!await fs8.pathExists(skillPath)) {
|
|
1025
1311
|
throw new Error(`Missing SKILL.md in ${fullPath}. Run /build-docs first.`);
|
|
1026
1312
|
}
|
|
1027
|
-
const lock = await
|
|
1313
|
+
const lock = await fs8.readJson(lockPath);
|
|
1028
1314
|
const packageName = lock.name;
|
|
1029
1315
|
const packageVersion = lock.version;
|
|
1030
1316
|
if (!packageName) {
|
|
@@ -1034,63 +1320,63 @@ async function link(localPath) {
|
|
|
1034
1320
|
throw new Error(`Invalid olore-lock.json: missing "version" field`);
|
|
1035
1321
|
}
|
|
1036
1322
|
const skillName = `olore-${packageName}-${packageVersion}`;
|
|
1037
|
-
const skillContent = await
|
|
1323
|
+
const skillContent = await fs8.readFile(skillPath, "utf-8");
|
|
1038
1324
|
const nameMatch = skillContent.match(/^name:\s*(.+)$/m);
|
|
1039
1325
|
const skillMdName = nameMatch ? nameMatch[1].trim() : null;
|
|
1040
1326
|
if (skillMdName !== skillName) {
|
|
1041
|
-
console.log(
|
|
1327
|
+
console.log(pc6.yellow(`
|
|
1042
1328
|
Warning: SKILL.md name mismatch`));
|
|
1043
|
-
console.log(
|
|
1044
|
-
console.log(
|
|
1045
|
-
console.log(
|
|
1329
|
+
console.log(pc6.gray(` Expected: ${skillName}`));
|
|
1330
|
+
console.log(pc6.gray(` Found: ${skillMdName || "(none)"}`));
|
|
1331
|
+
console.log(pc6.yellow(` Updating SKILL.md to fix...`));
|
|
1046
1332
|
const updatedContent = skillMdName ? skillContent.replace(/^name:\s*.+$/m, `name: ${skillName}`) : skillContent.replace(/^---\n/, `---
|
|
1047
1333
|
name: ${skillName}
|
|
1048
1334
|
`);
|
|
1049
|
-
await
|
|
1335
|
+
await fs8.writeFile(skillPath, updatedContent);
|
|
1050
1336
|
}
|
|
1051
|
-
console.log(
|
|
1337
|
+
console.log(pc6.bold(`
|
|
1052
1338
|
Linking ${packageName}@${packageVersion}...
|
|
1053
1339
|
`));
|
|
1054
1340
|
const agents = detectAgents();
|
|
1055
1341
|
if (agents.length === 0) {
|
|
1056
|
-
console.log(
|
|
1342
|
+
console.log(pc6.yellow("No agents detected. Creating directories anyway."));
|
|
1057
1343
|
}
|
|
1058
1344
|
const agentPaths = getAgentPaths();
|
|
1059
1345
|
const spinner = ora2(`${getLinkActionText()}...`).start();
|
|
1060
1346
|
const linked = [];
|
|
1061
1347
|
for (const [agent, skillsDir] of Object.entries(agentPaths)) {
|
|
1062
|
-
const targetDir =
|
|
1063
|
-
await
|
|
1064
|
-
await
|
|
1348
|
+
const targetDir = path8.join(skillsDir, skillName);
|
|
1349
|
+
await fs8.ensureDir(skillsDir);
|
|
1350
|
+
await fs8.remove(targetDir);
|
|
1065
1351
|
await linkOrCopy(fullPath, targetDir);
|
|
1066
|
-
linked.push(`${
|
|
1352
|
+
linked.push(`${pc6.blue("\u26D3")} ${agent} ${pc6.gray("\u2192")} ${pc6.gray(targetDir)}`);
|
|
1067
1353
|
}
|
|
1068
1354
|
spinner.stop();
|
|
1069
1355
|
linked.forEach((line) => console.log(` ${line}`));
|
|
1070
|
-
console.log(
|
|
1356
|
+
console.log(pc6.gray(` \u2514\u2500 ${getLinkTypeText()} ${fullPath}`));
|
|
1071
1357
|
console.log("");
|
|
1072
|
-
console.log(
|
|
1358
|
+
console.log(pc6.blue("Link complete!"));
|
|
1073
1359
|
console.log("");
|
|
1074
|
-
console.log(
|
|
1075
|
-
console.log(
|
|
1076
|
-
console.log(
|
|
1077
|
-
console.log(
|
|
1360
|
+
console.log(pc6.gray("Skill is now available as:"));
|
|
1361
|
+
console.log(pc6.cyan(` /${skillName}`) + pc6.gray(" (Claude Code)"));
|
|
1362
|
+
console.log(pc6.cyan(` $${skillName}`) + pc6.gray(" (Codex)"));
|
|
1363
|
+
console.log(pc6.cyan(` ${skillName}`) + pc6.gray(" (OpenCode)"));
|
|
1078
1364
|
console.log("");
|
|
1079
|
-
console.log(
|
|
1080
|
-
console.log(
|
|
1365
|
+
console.log(pc6.gray(`Development mode: ${getLinkTypeText()} source (bypasses ~/.olore).`));
|
|
1366
|
+
console.log(pc6.gray("Changes to source are immediately visible."));
|
|
1081
1367
|
console.log(
|
|
1082
|
-
|
|
1368
|
+
pc6.gray("Use ") + pc6.cyan("olore install") + pc6.gray(" for a stable copy in ~/.olore.")
|
|
1083
1369
|
);
|
|
1084
1370
|
}
|
|
1085
1371
|
|
|
1086
1372
|
// src/commands/list.ts
|
|
1087
|
-
import
|
|
1373
|
+
import pc7 from "picocolors";
|
|
1088
1374
|
async function list(options) {
|
|
1089
1375
|
const packages = await getInstalledPackages();
|
|
1090
1376
|
if (packages.length === 0) {
|
|
1091
|
-
console.log(
|
|
1092
|
-
console.log(
|
|
1093
|
-
console.log(`Run ${
|
|
1377
|
+
console.log(pc7.yellow("\nI find your lack of skills disturbing.\n"));
|
|
1378
|
+
console.log(pc7.gray("No packages installed."));
|
|
1379
|
+
console.log(`Run ${pc7.cyan("olore install <package>")} to install documentation.`);
|
|
1094
1380
|
return;
|
|
1095
1381
|
}
|
|
1096
1382
|
if (options.json) {
|
|
@@ -1098,29 +1384,29 @@ async function list(options) {
|
|
|
1098
1384
|
console.log(JSON.stringify({ packages, issueCount: issues2.length }, null, 2));
|
|
1099
1385
|
return;
|
|
1100
1386
|
}
|
|
1101
|
-
console.log(
|
|
1387
|
+
console.log(pc7.bold("\nInstalled packages:\n"));
|
|
1102
1388
|
console.log(
|
|
1103
|
-
|
|
1389
|
+
pc7.gray(
|
|
1104
1390
|
"PACKAGE".padEnd(25) + "VERSION".padEnd(12) + "TYPE".padEnd(10) + "FILES".padStart(8) + "SIZE".padStart(12)
|
|
1105
1391
|
)
|
|
1106
1392
|
);
|
|
1107
|
-
console.log(
|
|
1393
|
+
console.log(pc7.gray("-".repeat(67)));
|
|
1108
1394
|
for (const pkg of packages) {
|
|
1109
|
-
const typeLabel = pkg.installType === "linked" ?
|
|
1395
|
+
const typeLabel = pkg.installType === "linked" ? pc7.blue("linked") : pkg.installType;
|
|
1110
1396
|
console.log(
|
|
1111
1397
|
pkg.name.padEnd(25) + pkg.version.padEnd(12) + typeLabel.padEnd(10) + String(pkg.files).padStart(8) + formatSize(pkg.size).padStart(12)
|
|
1112
1398
|
);
|
|
1113
1399
|
}
|
|
1114
|
-
console.log(
|
|
1115
|
-
console.log(
|
|
1400
|
+
console.log(pc7.gray("-".repeat(67)));
|
|
1401
|
+
console.log(pc7.gray(`Total: ${packages.length} packages`));
|
|
1116
1402
|
console.log("");
|
|
1117
|
-
console.log(
|
|
1403
|
+
console.log(pc7.gray("Types: installed = in ~/.olore, linked = dev symlink, copied = legacy"));
|
|
1118
1404
|
const { issues } = await diagnose();
|
|
1119
1405
|
if (issues.length > 0) {
|
|
1120
1406
|
console.log("");
|
|
1121
1407
|
console.log(
|
|
1122
|
-
|
|
1123
|
-
`\u26A0 ${issues.length} issue${issues.length === 1 ? "" : "s"} detected. Run ${
|
|
1408
|
+
pc7.yellow(
|
|
1409
|
+
`\u26A0 ${issues.length} issue${issues.length === 1 ? "" : "s"} detected. Run ${pc7.cyan("olore doctor")} for details.`
|
|
1124
1410
|
)
|
|
1125
1411
|
);
|
|
1126
1412
|
}
|
|
@@ -1132,59 +1418,59 @@ function formatSize(bytes) {
|
|
|
1132
1418
|
}
|
|
1133
1419
|
|
|
1134
1420
|
// src/commands/order66.ts
|
|
1135
|
-
import
|
|
1136
|
-
import
|
|
1421
|
+
import path9 from "path";
|
|
1422
|
+
import fs9 from "fs-extra";
|
|
1137
1423
|
import ora3 from "ora";
|
|
1138
|
-
import
|
|
1424
|
+
import pc8 from "picocolors";
|
|
1139
1425
|
async function order66() {
|
|
1140
|
-
console.log(
|
|
1141
|
-
console.log(
|
|
1426
|
+
console.log(pc8.red("\n\u26A0\uFE0F Execute Order 66?\n"));
|
|
1427
|
+
console.log(pc8.yellow("This will remove ALL installed documentation packages."));
|
|
1142
1428
|
const packages = await getInstalledPackages();
|
|
1143
1429
|
if (packages.length === 0) {
|
|
1144
|
-
console.log(
|
|
1430
|
+
console.log(pc8.gray("\nNo packages to remove. The Jedi are already gone."));
|
|
1145
1431
|
return;
|
|
1146
1432
|
}
|
|
1147
|
-
console.log(
|
|
1433
|
+
console.log(pc8.gray(`
|
|
1148
1434
|
Packages to be removed: ${packages.length}`));
|
|
1149
1435
|
for (const pkg of packages) {
|
|
1150
|
-
console.log(
|
|
1436
|
+
console.log(pc8.gray(` - ${pkg.name}@${pkg.version}`));
|
|
1151
1437
|
}
|
|
1152
|
-
console.log(
|
|
1438
|
+
console.log(pc8.red('\n"It will be done, my lord."\n'));
|
|
1153
1439
|
const spinner = ora3("Executing Order 66...").start();
|
|
1154
1440
|
let removedCount = 0;
|
|
1155
1441
|
const agentPaths = getAgentPaths();
|
|
1156
1442
|
for (const pkg of packages) {
|
|
1157
1443
|
const skillName = `olore-${pkg.name}-${pkg.version}`;
|
|
1158
1444
|
for (const [, basePath] of Object.entries(agentPaths)) {
|
|
1159
|
-
const skillPath =
|
|
1160
|
-
if (await
|
|
1161
|
-
await
|
|
1445
|
+
const skillPath = path9.join(basePath, skillName);
|
|
1446
|
+
if (await fs9.pathExists(skillPath)) {
|
|
1447
|
+
await fs9.remove(skillPath);
|
|
1162
1448
|
}
|
|
1163
1449
|
}
|
|
1164
1450
|
if (pkg.installType === "installed") {
|
|
1165
1451
|
const olorePath = getOlorePackagePath(pkg.name, pkg.version);
|
|
1166
|
-
if (await
|
|
1167
|
-
await
|
|
1452
|
+
if (await fs9.pathExists(olorePath)) {
|
|
1453
|
+
await fs9.remove(olorePath);
|
|
1168
1454
|
}
|
|
1169
1455
|
}
|
|
1170
1456
|
removedCount++;
|
|
1171
1457
|
}
|
|
1172
1458
|
spinner.succeed(`Removed ${removedCount} packages`);
|
|
1173
|
-
console.log(
|
|
1459
|
+
console.log(pc8.gray("\nThe Jedi have been eliminated."));
|
|
1174
1460
|
}
|
|
1175
1461
|
|
|
1176
1462
|
// src/commands/prune.ts
|
|
1177
|
-
import
|
|
1463
|
+
import pc9 from "picocolors";
|
|
1178
1464
|
async function prune(options) {
|
|
1179
1465
|
if (!options.json) {
|
|
1180
|
-
console.log(
|
|
1466
|
+
console.log(pc9.bold("\nScanning for issues...\n"));
|
|
1181
1467
|
}
|
|
1182
1468
|
const { issues } = await diagnose();
|
|
1183
1469
|
if (issues.length === 0) {
|
|
1184
1470
|
if (options.json) {
|
|
1185
1471
|
console.log(JSON.stringify({ removed: [], failed: [] }, null, 2));
|
|
1186
1472
|
} else {
|
|
1187
|
-
console.log(
|
|
1473
|
+
console.log(pc9.green("Nothing to prune. Everything is clean."));
|
|
1188
1474
|
}
|
|
1189
1475
|
return;
|
|
1190
1476
|
}
|
|
@@ -1194,14 +1480,14 @@ async function prune(options) {
|
|
|
1194
1480
|
return;
|
|
1195
1481
|
}
|
|
1196
1482
|
console.log(
|
|
1197
|
-
|
|
1483
|
+
pc9.yellow(`Would remove ${issues.length} item${issues.length === 1 ? "" : "s"}:
|
|
1198
1484
|
`)
|
|
1199
1485
|
);
|
|
1200
1486
|
for (const issue of issues) {
|
|
1201
1487
|
console.log(` ${issueLabel(issue.type)} ${displayPath(issue.path)}`);
|
|
1202
1488
|
}
|
|
1203
1489
|
console.log(`
|
|
1204
|
-
Run ${
|
|
1490
|
+
Run ${pc9.cyan("olore prune")} (without --dry-run) to remove them.`);
|
|
1205
1491
|
return;
|
|
1206
1492
|
}
|
|
1207
1493
|
const result = await pruneIssues(issues);
|
|
@@ -1215,7 +1501,7 @@ Run ${pc7.cyan("olore prune")} (without --dry-run) to remove them.`);
|
|
|
1215
1501
|
for (const entry of result.removed) {
|
|
1216
1502
|
totalFreed += entry.freedBytes;
|
|
1217
1503
|
console.log(
|
|
1218
|
-
` ${
|
|
1504
|
+
` ${pc9.green("\u2713")} ${displayPath(entry.issue.path)} (${issueLabel(entry.issue.type)})`
|
|
1219
1505
|
);
|
|
1220
1506
|
}
|
|
1221
1507
|
if (totalFreed > 0) {
|
|
@@ -1226,12 +1512,12 @@ ${formatBytes(totalFreed)} freed.`);
|
|
|
1226
1512
|
if (result.failed.length > 0) {
|
|
1227
1513
|
console.log("");
|
|
1228
1514
|
console.log(
|
|
1229
|
-
|
|
1515
|
+
pc9.red(
|
|
1230
1516
|
`Failed to remove ${result.failed.length} item${result.failed.length === 1 ? "" : "s"}:`
|
|
1231
1517
|
)
|
|
1232
1518
|
);
|
|
1233
1519
|
for (const entry of result.failed) {
|
|
1234
|
-
console.log(` ${
|
|
1520
|
+
console.log(` ${pc9.red("\u2717")} ${displayPath(entry.issue.path)}: ${entry.error}`);
|
|
1235
1521
|
}
|
|
1236
1522
|
}
|
|
1237
1523
|
}
|
|
@@ -1249,12 +1535,12 @@ function issueLabel(type) {
|
|
|
1249
1535
|
}
|
|
1250
1536
|
|
|
1251
1537
|
// src/commands/remove.ts
|
|
1252
|
-
import
|
|
1253
|
-
import
|
|
1538
|
+
import path10 from "path";
|
|
1539
|
+
import fs10 from "fs-extra";
|
|
1254
1540
|
import ora4 from "ora";
|
|
1255
|
-
import
|
|
1541
|
+
import pc10 from "picocolors";
|
|
1256
1542
|
async function remove(pkg) {
|
|
1257
|
-
console.log(
|
|
1543
|
+
console.log(pc10.bold(`
|
|
1258
1544
|
Removing ${pkg}...
|
|
1259
1545
|
`));
|
|
1260
1546
|
const packages = await getInstalledPackages();
|
|
@@ -1270,20 +1556,20 @@ Removing ${pkg}...
|
|
|
1270
1556
|
return p.name === name;
|
|
1271
1557
|
});
|
|
1272
1558
|
if (matches.length === 0) {
|
|
1273
|
-
console.error(
|
|
1559
|
+
console.error(pc10.red(`Package not found: ${pkg}`));
|
|
1274
1560
|
console.log("\nInstalled packages:");
|
|
1275
1561
|
for (const p of packages) {
|
|
1276
|
-
console.log(` ${
|
|
1562
|
+
console.log(` ${pc10.cyan(p.name)}@${p.version}`);
|
|
1277
1563
|
}
|
|
1278
1564
|
process.exit(1);
|
|
1279
1565
|
}
|
|
1280
1566
|
if (matches.length > 1 && !version2) {
|
|
1281
|
-
console.error(
|
|
1567
|
+
console.error(pc10.red(`Multiple versions found for ${name}:`));
|
|
1282
1568
|
for (const p of matches) {
|
|
1283
|
-
console.log(` ${
|
|
1569
|
+
console.log(` ${pc10.cyan(p.name)}@${p.version} (${p.installType})`);
|
|
1284
1570
|
}
|
|
1285
1571
|
console.log(`
|
|
1286
|
-
Specify version: ${
|
|
1572
|
+
Specify version: ${pc10.cyan(`olore remove ${name}@<version>`)}`);
|
|
1287
1573
|
process.exit(1);
|
|
1288
1574
|
}
|
|
1289
1575
|
const found = matches[0];
|
|
@@ -1292,32 +1578,32 @@ Specify version: ${pc8.cyan(`olore remove ${name}@<version>`)}`);
|
|
|
1292
1578
|
const removed = [];
|
|
1293
1579
|
const agentPaths = getAgentPaths();
|
|
1294
1580
|
for (const [agent, basePath] of Object.entries(agentPaths)) {
|
|
1295
|
-
const skillPath =
|
|
1296
|
-
if (await
|
|
1297
|
-
await
|
|
1298
|
-
removed.push(`${
|
|
1581
|
+
const skillPath = path10.join(basePath, skillName);
|
|
1582
|
+
if (await fs10.pathExists(skillPath)) {
|
|
1583
|
+
await fs10.remove(skillPath);
|
|
1584
|
+
removed.push(`${pc10.green("\u2713")} ${agent}`);
|
|
1299
1585
|
}
|
|
1300
1586
|
}
|
|
1301
1587
|
if (found.installType === "installed") {
|
|
1302
1588
|
const olorePath = getOlorePackagePath(found.name, found.version);
|
|
1303
|
-
if (await
|
|
1304
|
-
await
|
|
1305
|
-
removed.push(`${
|
|
1589
|
+
if (await fs10.pathExists(olorePath)) {
|
|
1590
|
+
await fs10.remove(olorePath);
|
|
1591
|
+
removed.push(`${pc10.green("\u2713")} ~/.olore`);
|
|
1306
1592
|
}
|
|
1307
1593
|
}
|
|
1308
1594
|
spinner.stop();
|
|
1309
1595
|
if (removed.length === 0) {
|
|
1310
|
-
console.log(
|
|
1596
|
+
console.log(pc10.yellow("No files found to remove."));
|
|
1311
1597
|
} else {
|
|
1312
1598
|
removed.forEach((line) => console.log(` ${line}`));
|
|
1313
1599
|
console.log("");
|
|
1314
|
-
console.log(
|
|
1600
|
+
console.log(pc10.green(`Removed ${found.name}@${found.version}`));
|
|
1315
1601
|
}
|
|
1316
1602
|
}
|
|
1317
1603
|
|
|
1318
1604
|
// src/commands/search.ts
|
|
1319
1605
|
import ora5 from "ora";
|
|
1320
|
-
import
|
|
1606
|
+
import pc11 from "picocolors";
|
|
1321
1607
|
async function search(query, options) {
|
|
1322
1608
|
const spinner = ora5("Fetching package registry...").start();
|
|
1323
1609
|
let packages;
|
|
@@ -1329,15 +1615,15 @@ async function search(query, options) {
|
|
|
1329
1615
|
spinner.fail("Failed to fetch registry");
|
|
1330
1616
|
if (error instanceof RegistryError) {
|
|
1331
1617
|
if (error.code === "NETWORK_ERROR" || error.code === "TIMEOUT") {
|
|
1332
|
-
console.log(
|
|
1618
|
+
console.log(pc11.red(`
|
|
1333
1619
|
Network error: ${error.message}`));
|
|
1334
|
-
console.log(
|
|
1620
|
+
console.log(pc11.gray("Please check your internet connection and try again."));
|
|
1335
1621
|
} else {
|
|
1336
|
-
console.log(
|
|
1622
|
+
console.log(pc11.red(`
|
|
1337
1623
|
Error: ${error.message}`));
|
|
1338
1624
|
}
|
|
1339
1625
|
} else {
|
|
1340
|
-
console.log(
|
|
1626
|
+
console.log(pc11.red(`
|
|
1341
1627
|
Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
1342
1628
|
}
|
|
1343
1629
|
process.exit(1);
|
|
@@ -1351,10 +1637,10 @@ Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
|
1351
1637
|
}
|
|
1352
1638
|
if (entries.length === 0) {
|
|
1353
1639
|
if (query) {
|
|
1354
|
-
console.log(
|
|
1640
|
+
console.log(pc11.yellow(`
|
|
1355
1641
|
No packages matching '${query}'`));
|
|
1356
1642
|
} else {
|
|
1357
|
-
console.log(
|
|
1643
|
+
console.log(pc11.yellow("\nNo packages available in the registry"));
|
|
1358
1644
|
}
|
|
1359
1645
|
return;
|
|
1360
1646
|
}
|
|
@@ -1381,26 +1667,27 @@ No packages matching '${query}'`));
|
|
|
1381
1667
|
const colName = 20;
|
|
1382
1668
|
const colDesc = 44;
|
|
1383
1669
|
const colVersions = 12;
|
|
1384
|
-
console.log(
|
|
1670
|
+
console.log(pc11.bold("\nAvailable packages:\n"));
|
|
1385
1671
|
console.log(
|
|
1386
|
-
|
|
1672
|
+
pc11.gray(
|
|
1387
1673
|
"PACKAGE".padEnd(colName) + "DESCRIPTION".padEnd(colDesc) + "VERSIONS".padEnd(colVersions) + "INSTALLED"
|
|
1388
1674
|
)
|
|
1389
1675
|
);
|
|
1390
|
-
console.log(
|
|
1676
|
+
console.log(pc11.gray("\u2500".repeat(colName + colDesc + colVersions + 12)));
|
|
1391
1677
|
for (const [name, info] of entries.sort(([a], [b]) => a.localeCompare(b))) {
|
|
1392
1678
|
const desc = truncate(info.description, colDesc - 2);
|
|
1393
1679
|
const versions = info.versions.join(", ");
|
|
1394
1680
|
const installedVersion = installedVersions.get(name);
|
|
1395
|
-
const status = installedVersion ?
|
|
1681
|
+
const status = installedVersion ? pc11.green(`\u2713 ${installedVersion}`) : "";
|
|
1396
1682
|
console.log(
|
|
1397
1683
|
name.padEnd(colName) + desc.padEnd(colDesc) + versions.padEnd(colVersions) + status
|
|
1398
1684
|
);
|
|
1399
1685
|
}
|
|
1400
|
-
console.log(
|
|
1401
|
-
console.log(
|
|
1686
|
+
console.log(pc11.gray("\u2500".repeat(colName + colDesc + colVersions + 12)));
|
|
1687
|
+
console.log(pc11.gray(`${entries.length} package${entries.length === 1 ? "" : "s"} available`));
|
|
1402
1688
|
console.log(`
|
|
1403
|
-
Install with: ${
|
|
1689
|
+
Install with: ${pc11.cyan("olore install <package>")}`);
|
|
1690
|
+
await checkForUpdates();
|
|
1404
1691
|
}
|
|
1405
1692
|
function truncate(str, maxLen) {
|
|
1406
1693
|
if (str.length <= maxLen) return str;
|
|
@@ -1412,12 +1699,12 @@ var require2 = createRequire(import.meta.url);
|
|
|
1412
1699
|
var { version } = require2("../package.json");
|
|
1413
1700
|
var program = new Command();
|
|
1414
1701
|
program.name("olore").description("Universal documentation for any AI coding agent").version(version).addHelpText("after", `
|
|
1415
|
-
${
|
|
1702
|
+
${pc12.gray("May the Skill be with you.")}`);
|
|
1416
1703
|
program.command("init").description("Initialize a documentation package in the current directory").option("-n, --name <name>", "Package name (default: folder name)").option("-v, --version <version>", "Package version (default: latest)").option("-y, --yes", "Skip prompts, use defaults").action(async (options) => {
|
|
1417
1704
|
try {
|
|
1418
1705
|
await init(options);
|
|
1419
1706
|
} catch (error) {
|
|
1420
|
-
console.error(
|
|
1707
|
+
console.error(pc12.red(`Error: ${error.message}`));
|
|
1421
1708
|
process.exit(1);
|
|
1422
1709
|
}
|
|
1423
1710
|
});
|
|
@@ -1425,7 +1712,7 @@ program.command("install <package>").alias("i").description("Install a documenta
|
|
|
1425
1712
|
try {
|
|
1426
1713
|
await install(pkg, options);
|
|
1427
1714
|
} catch (error) {
|
|
1428
|
-
console.error(
|
|
1715
|
+
console.error(pc12.red(`Error: ${error.message}`));
|
|
1429
1716
|
process.exit(1);
|
|
1430
1717
|
}
|
|
1431
1718
|
});
|
|
@@ -1433,7 +1720,7 @@ program.command("link <path>").description("Link a local package for development
|
|
|
1433
1720
|
try {
|
|
1434
1721
|
await link(localPath);
|
|
1435
1722
|
} catch (error) {
|
|
1436
|
-
console.error(
|
|
1723
|
+
console.error(pc12.red(`Error: ${error.message}`));
|
|
1437
1724
|
process.exit(1);
|
|
1438
1725
|
}
|
|
1439
1726
|
});
|
|
@@ -1441,7 +1728,7 @@ program.command("list").alias("ls").description("List installed documentation pa
|
|
|
1441
1728
|
try {
|
|
1442
1729
|
await list(options);
|
|
1443
1730
|
} catch (error) {
|
|
1444
|
-
console.error(
|
|
1731
|
+
console.error(pc12.red(`Error: ${error.message}`));
|
|
1445
1732
|
process.exit(1);
|
|
1446
1733
|
}
|
|
1447
1734
|
});
|
|
@@ -1449,7 +1736,7 @@ program.command("search [query]").description("Search available packages in the
|
|
|
1449
1736
|
try {
|
|
1450
1737
|
await search(query, options);
|
|
1451
1738
|
} catch (error) {
|
|
1452
|
-
console.error(
|
|
1739
|
+
console.error(pc12.red(`Error: ${error.message}`));
|
|
1453
1740
|
process.exit(1);
|
|
1454
1741
|
}
|
|
1455
1742
|
});
|
|
@@ -1457,7 +1744,7 @@ program.command("remove <package>").alias("rm").description("Remove an installed
|
|
|
1457
1744
|
try {
|
|
1458
1745
|
await remove(pkg);
|
|
1459
1746
|
} catch (error) {
|
|
1460
|
-
console.error(
|
|
1747
|
+
console.error(pc12.red(`Error: ${error.message}`));
|
|
1461
1748
|
process.exit(1);
|
|
1462
1749
|
}
|
|
1463
1750
|
});
|
|
@@ -1465,7 +1752,7 @@ program.command("doctor").description("Check for issues with installed packages"
|
|
|
1465
1752
|
try {
|
|
1466
1753
|
await doctor(options);
|
|
1467
1754
|
} catch (error) {
|
|
1468
|
-
console.error(
|
|
1755
|
+
console.error(pc12.red(`Error: ${error.message}`));
|
|
1469
1756
|
process.exit(1);
|
|
1470
1757
|
}
|
|
1471
1758
|
});
|
|
@@ -1473,7 +1760,15 @@ program.command("prune").description("Remove dangling symlinks, orphaned package
|
|
|
1473
1760
|
try {
|
|
1474
1761
|
await prune(options);
|
|
1475
1762
|
} catch (error) {
|
|
1476
|
-
console.error(
|
|
1763
|
+
console.error(pc12.red(`Error: ${error.message}`));
|
|
1764
|
+
process.exit(1);
|
|
1765
|
+
}
|
|
1766
|
+
});
|
|
1767
|
+
program.command("inject").description("Inject compressed doc indexes into AGENTS.md and CLAUDE.md").option("--remove", "Remove injected content from project files").option("--json", "Output as JSON").action(async (options) => {
|
|
1768
|
+
try {
|
|
1769
|
+
await inject(options);
|
|
1770
|
+
} catch (error) {
|
|
1771
|
+
console.error(pc12.red(`Error: ${error.message}`));
|
|
1477
1772
|
process.exit(1);
|
|
1478
1773
|
}
|
|
1479
1774
|
});
|
|
@@ -1481,7 +1776,7 @@ program.command("order66").description(false).action(async () => {
|
|
|
1481
1776
|
try {
|
|
1482
1777
|
await order66();
|
|
1483
1778
|
} catch (error) {
|
|
1484
|
-
console.error(
|
|
1779
|
+
console.error(pc12.red(`Error: ${error.message}`));
|
|
1485
1780
|
process.exit(1);
|
|
1486
1781
|
}
|
|
1487
1782
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olorehq/olore",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Universal documentation for any AI coding agent",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
"context",
|
|
12
12
|
"llm"
|
|
13
13
|
],
|
|
14
|
-
"license": "
|
|
14
|
+
"license": "MIT",
|
|
15
15
|
"author": "olorehq",
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
18
|
"url": "git+https://github.com/olorehq/olore.git",
|
|
19
19
|
"directory": "cli"
|
|
20
20
|
},
|
|
21
|
-
"homepage": "https://
|
|
21
|
+
"homepage": "https://www.olore.dev",
|
|
22
22
|
"type": "module",
|
|
23
23
|
"files": [
|
|
24
24
|
"dist"
|