@olorehq/olore 0.1.4 → 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 +74 -0
- package/dist/cli.js +348 -166
- 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 pc11 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 pc4 from "picocolors";
|
|
713
848
|
|
|
714
849
|
// src/core/registry.ts
|
|
715
850
|
var RegistryError = class extends Error {
|
|
@@ -791,22 +926,22 @@ async function resolveVersion(name, version2) {
|
|
|
791
926
|
// src/commands/install.ts
|
|
792
927
|
async function installFromLocal(localPath) {
|
|
793
928
|
const fullPath = expandPath(localPath);
|
|
794
|
-
if (!await
|
|
929
|
+
if (!await fs7.pathExists(fullPath)) {
|
|
795
930
|
throw new Error(`Path not found: ${fullPath}`);
|
|
796
931
|
}
|
|
797
|
-
const stat = await
|
|
932
|
+
const stat = await fs7.stat(fullPath);
|
|
798
933
|
if (!stat.isDirectory()) {
|
|
799
934
|
throw new Error(`Not a directory: ${fullPath}`);
|
|
800
935
|
}
|
|
801
|
-
const lockPath =
|
|
802
|
-
if (!await
|
|
936
|
+
const lockPath = path7.join(fullPath, "olore-lock.json");
|
|
937
|
+
if (!await fs7.pathExists(lockPath)) {
|
|
803
938
|
throw new Error(`Missing olore-lock.json in ${fullPath}`);
|
|
804
939
|
}
|
|
805
|
-
const skillPath =
|
|
806
|
-
if (!await
|
|
940
|
+
const skillPath = path7.join(fullPath, "SKILL.md");
|
|
941
|
+
if (!await fs7.pathExists(skillPath)) {
|
|
807
942
|
throw new Error(`Missing SKILL.md in ${fullPath}. Run /generate-agent-skills first.`);
|
|
808
943
|
}
|
|
809
|
-
const lock = await
|
|
944
|
+
const lock = await fs7.readJson(lockPath);
|
|
810
945
|
const packageName = lock.name;
|
|
811
946
|
const packageVersion = lock.version;
|
|
812
947
|
if (!packageName) {
|
|
@@ -816,57 +951,57 @@ async function installFromLocal(localPath) {
|
|
|
816
951
|
throw new Error(`Invalid olore-lock.json: missing "version" field`);
|
|
817
952
|
}
|
|
818
953
|
const skillName = `olore-${packageName}-${packageVersion}`;
|
|
819
|
-
const skillContent = await
|
|
954
|
+
const skillContent = await fs7.readFile(skillPath, "utf-8");
|
|
820
955
|
const nameMatch = skillContent.match(/^name:\s*(.+)$/m);
|
|
821
956
|
const skillMdName = nameMatch ? nameMatch[1].trim() : null;
|
|
822
957
|
if (skillMdName !== skillName) {
|
|
823
|
-
console.log(
|
|
958
|
+
console.log(pc4.yellow(`
|
|
824
959
|
Warning: SKILL.md name mismatch`));
|
|
825
|
-
console.log(
|
|
826
|
-
console.log(
|
|
827
|
-
console.log(
|
|
960
|
+
console.log(pc4.gray(` Expected: ${skillName}`));
|
|
961
|
+
console.log(pc4.gray(` Found: ${skillMdName || "(none)"}`));
|
|
962
|
+
console.log(pc4.yellow(` Updating SKILL.md to fix...`));
|
|
828
963
|
const updatedContent = skillMdName ? skillContent.replace(/^name:\s*.+$/m, `name: ${skillName}`) : skillContent.replace(/^---\n/, `---
|
|
829
964
|
name: ${skillName}
|
|
830
965
|
`);
|
|
831
|
-
await
|
|
966
|
+
await fs7.writeFile(skillPath, updatedContent);
|
|
832
967
|
}
|
|
833
|
-
console.log(
|
|
968
|
+
console.log(pc4.bold(`
|
|
834
969
|
Installing ${packageName}@${packageVersion} from local path...
|
|
835
970
|
`));
|
|
836
971
|
const agents = detectAgents();
|
|
837
972
|
if (agents.length === 0) {
|
|
838
|
-
console.log(
|
|
973
|
+
console.log(pc4.yellow("No agents detected. Creating directories anyway."));
|
|
839
974
|
}
|
|
840
975
|
const agentPaths = getAgentPaths();
|
|
841
976
|
const olorePath = getOlorePackagePath(packageName, packageVersion);
|
|
842
977
|
const spinner = ora("Copying to ~/.olore...").start();
|
|
843
|
-
await
|
|
844
|
-
await
|
|
845
|
-
await
|
|
846
|
-
spinner.succeed(`Copied to ${
|
|
978
|
+
await fs7.ensureDir(path7.dirname(olorePath));
|
|
979
|
+
await fs7.remove(olorePath);
|
|
980
|
+
await fs7.copy(fullPath, olorePath);
|
|
981
|
+
spinner.succeed(`Copied to ${pc4.gray(olorePath)}`);
|
|
847
982
|
const linkSpinner = ora("Linking to agent directories...").start();
|
|
848
983
|
const linked = [];
|
|
849
984
|
for (const [agent, skillsDir] of Object.entries(agentPaths)) {
|
|
850
|
-
const targetDir =
|
|
851
|
-
await
|
|
852
|
-
await
|
|
985
|
+
const targetDir = path7.join(skillsDir, skillName);
|
|
986
|
+
await fs7.ensureDir(skillsDir);
|
|
987
|
+
await fs7.remove(targetDir);
|
|
853
988
|
await linkOrCopy(olorePath, targetDir);
|
|
854
|
-
linked.push(`${
|
|
989
|
+
linked.push(`${pc4.green("\u2713")} ${agent} ${pc4.gray("\u2192")} ${pc4.gray(targetDir)}`);
|
|
855
990
|
}
|
|
856
991
|
linkSpinner.stop();
|
|
857
992
|
linked.forEach((line) => console.log(` ${line}`));
|
|
858
|
-
console.log(
|
|
993
|
+
console.log(pc4.gray(` \u2514\u2500 all linked to ${olorePath}`));
|
|
859
994
|
console.log("");
|
|
860
|
-
console.log(
|
|
995
|
+
console.log(pc4.green("Installation complete!"));
|
|
861
996
|
console.log("");
|
|
862
|
-
console.log(
|
|
863
|
-
console.log(
|
|
864
|
-
console.log(
|
|
865
|
-
console.log(
|
|
997
|
+
console.log(pc4.gray("Skill is now available as:"));
|
|
998
|
+
console.log(pc4.cyan(` /${skillName}`) + pc4.gray(" (Claude Code)"));
|
|
999
|
+
console.log(pc4.cyan(` $${skillName}`) + pc4.gray(" (Codex)"));
|
|
1000
|
+
console.log(pc4.cyan(` ${skillName}`) + pc4.gray(" (OpenCode)"));
|
|
866
1001
|
}
|
|
867
1002
|
async function install(pkg, options) {
|
|
868
1003
|
if (options.force) {
|
|
869
|
-
console.log(
|
|
1004
|
+
console.log(pc4.cyan("\n\u2728 May the Skill be with you.\n"));
|
|
870
1005
|
}
|
|
871
1006
|
if (isLocalPath(pkg)) {
|
|
872
1007
|
await installFromLocal(pkg);
|
|
@@ -884,10 +1019,35 @@ function parsePackageSpec(spec) {
|
|
|
884
1019
|
}
|
|
885
1020
|
return { name: spec };
|
|
886
1021
|
}
|
|
1022
|
+
function levenshtein(a, b) {
|
|
1023
|
+
const m = a.length;
|
|
1024
|
+
const n = b.length;
|
|
1025
|
+
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
|
|
1026
|
+
for (let i = 0; i <= m; i++) dp[i][0] = i;
|
|
1027
|
+
for (let j = 0; j <= n; j++) dp[0][j] = j;
|
|
1028
|
+
for (let i = 1; i <= m; i++) {
|
|
1029
|
+
for (let j = 1; j <= n; j++) {
|
|
1030
|
+
dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
return dp[m][n];
|
|
1034
|
+
}
|
|
1035
|
+
function findSimilarPackages(input, packages, maxResults = 3) {
|
|
1036
|
+
const results = [];
|
|
1037
|
+
for (const [name, entry] of Object.entries(packages)) {
|
|
1038
|
+
const distance = levenshtein(input.toLowerCase(), name.toLowerCase());
|
|
1039
|
+
const isSubstring = name.toLowerCase().includes(input.toLowerCase()) || input.toLowerCase().includes(name.toLowerCase());
|
|
1040
|
+
if (distance <= 3 || isSubstring) {
|
|
1041
|
+
results.push({ name, description: entry.description, distance });
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
results.sort((a, b) => a.distance - b.distance);
|
|
1045
|
+
return results.slice(0, maxResults).map(({ name, description }) => ({ name, description }));
|
|
1046
|
+
}
|
|
887
1047
|
async function installFromRemote(pkg, optionsVersion) {
|
|
888
1048
|
const { name, version: specVersion } = parsePackageSpec(pkg);
|
|
889
1049
|
const requestedVersion = optionsVersion || specVersion || "latest";
|
|
890
|
-
console.log(
|
|
1050
|
+
console.log(pc4.bold(`
|
|
891
1051
|
Installing ${name}@${requestedVersion} from registry...
|
|
892
1052
|
`));
|
|
893
1053
|
const spinner = ora("Fetching package info...").start();
|
|
@@ -899,18 +1059,32 @@ Installing ${name}@${requestedVersion} from registry...
|
|
|
899
1059
|
spinner.fail("Failed to resolve package");
|
|
900
1060
|
if (error instanceof RegistryError) {
|
|
901
1061
|
if (error.code === "NOT_FOUND") {
|
|
902
|
-
console.log(
|
|
1062
|
+
console.log(pc4.yellow(`
|
|
903
1063
|
Package "${name}" not found in registry.`));
|
|
904
|
-
|
|
905
|
-
|
|
1064
|
+
try {
|
|
1065
|
+
const index = await fetchPackageIndex();
|
|
1066
|
+
const similar = findSimilarPackages(name, index.packages);
|
|
1067
|
+
if (similar.length > 0) {
|
|
1068
|
+
console.log(pc4.bold("\nDid you mean?"));
|
|
1069
|
+
for (const pkg2 of similar) {
|
|
1070
|
+
console.log(` ${pc4.cyan(pkg2.name)} ${pc4.gray("-")} ${pc4.gray(pkg2.description)}`);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
} catch {
|
|
1074
|
+
}
|
|
1075
|
+
console.log(
|
|
1076
|
+
pc4.gray("\nRun ") + pc4.cyan("olore search") + pc4.gray(" to see all available packages.")
|
|
1077
|
+
);
|
|
1078
|
+
console.log(pc4.gray("\nFor local packages, use a path:"));
|
|
1079
|
+
console.log(pc4.cyan(` olore install ./vault/packages/${name}/<version>`));
|
|
906
1080
|
console.log("");
|
|
907
1081
|
} else if (error.code === "NETWORK_ERROR" || error.code === "TIMEOUT") {
|
|
908
|
-
console.log(
|
|
1082
|
+
console.log(pc4.red(`
|
|
909
1083
|
Network error: ${error.message}`));
|
|
910
|
-
console.log(
|
|
1084
|
+
console.log(pc4.gray("Please check your internet connection and try again."));
|
|
911
1085
|
}
|
|
912
1086
|
} else {
|
|
913
|
-
console.log(
|
|
1087
|
+
console.log(pc4.red(`
|
|
914
1088
|
Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
915
1089
|
}
|
|
916
1090
|
process.exit(1);
|
|
@@ -918,26 +1092,26 @@ Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
|
918
1092
|
const skillName = `olore-${name}-${versionInfo.version}`;
|
|
919
1093
|
const agents = detectAgents();
|
|
920
1094
|
if (agents.length === 0) {
|
|
921
|
-
console.log(
|
|
1095
|
+
console.log(pc4.yellow("No agents detected. Creating directories anyway."));
|
|
922
1096
|
}
|
|
923
1097
|
const agentPaths = getAgentPaths();
|
|
924
1098
|
const olorePath = getOlorePackagePath(name, versionInfo.version);
|
|
925
1099
|
const downloadSpinner = ora("Downloading package...").start();
|
|
926
1100
|
try {
|
|
927
1101
|
await downloadAndInstall(versionInfo.downloadUrl, olorePath, versionInfo.integrity);
|
|
928
|
-
downloadSpinner.succeed(`Downloaded to ${
|
|
1102
|
+
downloadSpinner.succeed(`Downloaded to ${pc4.gray(olorePath)}`);
|
|
929
1103
|
} catch (error) {
|
|
930
1104
|
downloadSpinner.fail("Download failed");
|
|
931
1105
|
if (error instanceof DownloadError) {
|
|
932
1106
|
if (error.code === "CHECKSUM_MISMATCH") {
|
|
933
|
-
console.log(
|
|
934
|
-
console.log(
|
|
1107
|
+
console.log(pc4.red("\nChecksum verification failed!"));
|
|
1108
|
+
console.log(pc4.gray("The downloaded package may be corrupted or tampered with."));
|
|
935
1109
|
} else {
|
|
936
|
-
console.log(
|
|
1110
|
+
console.log(pc4.red(`
|
|
937
1111
|
Download error: ${error.message}`));
|
|
938
1112
|
}
|
|
939
1113
|
} else {
|
|
940
|
-
console.log(
|
|
1114
|
+
console.log(pc4.red(`
|
|
941
1115
|
Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
942
1116
|
}
|
|
943
1117
|
process.exit(1);
|
|
@@ -945,47 +1119,47 @@ Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
|
945
1119
|
const linkSpinner = ora("Linking to agent directories...").start();
|
|
946
1120
|
const linked = [];
|
|
947
1121
|
for (const [agent, skillsDir] of Object.entries(agentPaths)) {
|
|
948
|
-
const targetDir =
|
|
949
|
-
await
|
|
950
|
-
await
|
|
1122
|
+
const targetDir = path7.join(skillsDir, skillName);
|
|
1123
|
+
await fs7.ensureDir(skillsDir);
|
|
1124
|
+
await fs7.remove(targetDir);
|
|
951
1125
|
await linkOrCopy(olorePath, targetDir);
|
|
952
|
-
linked.push(`${
|
|
1126
|
+
linked.push(`${pc4.green("\u2713")} ${agent} ${pc4.gray("\u2192")} ${pc4.gray(targetDir)}`);
|
|
953
1127
|
}
|
|
954
1128
|
linkSpinner.stop();
|
|
955
1129
|
linked.forEach((line) => console.log(` ${line}`));
|
|
956
|
-
console.log(
|
|
1130
|
+
console.log(pc4.gray(` \u2514\u2500 all linked to ${olorePath}`));
|
|
957
1131
|
console.log("");
|
|
958
|
-
console.log(
|
|
1132
|
+
console.log(pc4.green("Installation complete!"));
|
|
959
1133
|
console.log("");
|
|
960
|
-
console.log(
|
|
961
|
-
console.log(
|
|
962
|
-
console.log(
|
|
963
|
-
console.log(
|
|
1134
|
+
console.log(pc4.gray("Skill is now available as:"));
|
|
1135
|
+
console.log(pc4.cyan(` /${skillName}`) + pc4.gray(" (Claude Code)"));
|
|
1136
|
+
console.log(pc4.cyan(` $${skillName}`) + pc4.gray(" (Codex)"));
|
|
1137
|
+
console.log(pc4.cyan(` ${skillName}`) + pc4.gray(" (OpenCode)"));
|
|
964
1138
|
}
|
|
965
1139
|
|
|
966
1140
|
// src/commands/link.ts
|
|
967
|
-
import
|
|
968
|
-
import
|
|
1141
|
+
import path8 from "path";
|
|
1142
|
+
import fs8 from "fs-extra";
|
|
969
1143
|
import ora2 from "ora";
|
|
970
|
-
import
|
|
1144
|
+
import pc5 from "picocolors";
|
|
971
1145
|
async function link(localPath) {
|
|
972
1146
|
const fullPath = expandPath(localPath);
|
|
973
|
-
if (!await
|
|
1147
|
+
if (!await fs8.pathExists(fullPath)) {
|
|
974
1148
|
throw new Error(`Path not found: ${fullPath}`);
|
|
975
1149
|
}
|
|
976
|
-
const stat = await
|
|
1150
|
+
const stat = await fs8.stat(fullPath);
|
|
977
1151
|
if (!stat.isDirectory()) {
|
|
978
1152
|
throw new Error(`Not a directory: ${fullPath}`);
|
|
979
1153
|
}
|
|
980
|
-
const lockPath =
|
|
981
|
-
if (!await
|
|
1154
|
+
const lockPath = path8.join(fullPath, "olore-lock.json");
|
|
1155
|
+
if (!await fs8.pathExists(lockPath)) {
|
|
982
1156
|
throw new Error(`Missing olore-lock.json in ${fullPath}`);
|
|
983
1157
|
}
|
|
984
|
-
const skillPath =
|
|
985
|
-
if (!await
|
|
1158
|
+
const skillPath = path8.join(fullPath, "SKILL.md");
|
|
1159
|
+
if (!await fs8.pathExists(skillPath)) {
|
|
986
1160
|
throw new Error(`Missing SKILL.md in ${fullPath}. Run /build-docs first.`);
|
|
987
1161
|
}
|
|
988
|
-
const lock = await
|
|
1162
|
+
const lock = await fs8.readJson(lockPath);
|
|
989
1163
|
const packageName = lock.name;
|
|
990
1164
|
const packageVersion = lock.version;
|
|
991
1165
|
if (!packageName) {
|
|
@@ -995,63 +1169,63 @@ async function link(localPath) {
|
|
|
995
1169
|
throw new Error(`Invalid olore-lock.json: missing "version" field`);
|
|
996
1170
|
}
|
|
997
1171
|
const skillName = `olore-${packageName}-${packageVersion}`;
|
|
998
|
-
const skillContent = await
|
|
1172
|
+
const skillContent = await fs8.readFile(skillPath, "utf-8");
|
|
999
1173
|
const nameMatch = skillContent.match(/^name:\s*(.+)$/m);
|
|
1000
1174
|
const skillMdName = nameMatch ? nameMatch[1].trim() : null;
|
|
1001
1175
|
if (skillMdName !== skillName) {
|
|
1002
|
-
console.log(
|
|
1176
|
+
console.log(pc5.yellow(`
|
|
1003
1177
|
Warning: SKILL.md name mismatch`));
|
|
1004
|
-
console.log(
|
|
1005
|
-
console.log(
|
|
1006
|
-
console.log(
|
|
1178
|
+
console.log(pc5.gray(` Expected: ${skillName}`));
|
|
1179
|
+
console.log(pc5.gray(` Found: ${skillMdName || "(none)"}`));
|
|
1180
|
+
console.log(pc5.yellow(` Updating SKILL.md to fix...`));
|
|
1007
1181
|
const updatedContent = skillMdName ? skillContent.replace(/^name:\s*.+$/m, `name: ${skillName}`) : skillContent.replace(/^---\n/, `---
|
|
1008
1182
|
name: ${skillName}
|
|
1009
1183
|
`);
|
|
1010
|
-
await
|
|
1184
|
+
await fs8.writeFile(skillPath, updatedContent);
|
|
1011
1185
|
}
|
|
1012
|
-
console.log(
|
|
1186
|
+
console.log(pc5.bold(`
|
|
1013
1187
|
Linking ${packageName}@${packageVersion}...
|
|
1014
1188
|
`));
|
|
1015
1189
|
const agents = detectAgents();
|
|
1016
1190
|
if (agents.length === 0) {
|
|
1017
|
-
console.log(
|
|
1191
|
+
console.log(pc5.yellow("No agents detected. Creating directories anyway."));
|
|
1018
1192
|
}
|
|
1019
1193
|
const agentPaths = getAgentPaths();
|
|
1020
1194
|
const spinner = ora2(`${getLinkActionText()}...`).start();
|
|
1021
1195
|
const linked = [];
|
|
1022
1196
|
for (const [agent, skillsDir] of Object.entries(agentPaths)) {
|
|
1023
|
-
const targetDir =
|
|
1024
|
-
await
|
|
1025
|
-
await
|
|
1197
|
+
const targetDir = path8.join(skillsDir, skillName);
|
|
1198
|
+
await fs8.ensureDir(skillsDir);
|
|
1199
|
+
await fs8.remove(targetDir);
|
|
1026
1200
|
await linkOrCopy(fullPath, targetDir);
|
|
1027
|
-
linked.push(`${
|
|
1201
|
+
linked.push(`${pc5.blue("\u26D3")} ${agent} ${pc5.gray("\u2192")} ${pc5.gray(targetDir)}`);
|
|
1028
1202
|
}
|
|
1029
1203
|
spinner.stop();
|
|
1030
1204
|
linked.forEach((line) => console.log(` ${line}`));
|
|
1031
|
-
console.log(
|
|
1205
|
+
console.log(pc5.gray(` \u2514\u2500 ${getLinkTypeText()} ${fullPath}`));
|
|
1032
1206
|
console.log("");
|
|
1033
|
-
console.log(
|
|
1207
|
+
console.log(pc5.blue("Link complete!"));
|
|
1034
1208
|
console.log("");
|
|
1035
|
-
console.log(
|
|
1036
|
-
console.log(
|
|
1037
|
-
console.log(
|
|
1038
|
-
console.log(
|
|
1209
|
+
console.log(pc5.gray("Skill is now available as:"));
|
|
1210
|
+
console.log(pc5.cyan(` /${skillName}`) + pc5.gray(" (Claude Code)"));
|
|
1211
|
+
console.log(pc5.cyan(` $${skillName}`) + pc5.gray(" (Codex)"));
|
|
1212
|
+
console.log(pc5.cyan(` ${skillName}`) + pc5.gray(" (OpenCode)"));
|
|
1039
1213
|
console.log("");
|
|
1040
|
-
console.log(
|
|
1041
|
-
console.log(
|
|
1214
|
+
console.log(pc5.gray(`Development mode: ${getLinkTypeText()} source (bypasses ~/.olore).`));
|
|
1215
|
+
console.log(pc5.gray("Changes to source are immediately visible."));
|
|
1042
1216
|
console.log(
|
|
1043
|
-
|
|
1217
|
+
pc5.gray("Use ") + pc5.cyan("olore install") + pc5.gray(" for a stable copy in ~/.olore.")
|
|
1044
1218
|
);
|
|
1045
1219
|
}
|
|
1046
1220
|
|
|
1047
1221
|
// src/commands/list.ts
|
|
1048
|
-
import
|
|
1222
|
+
import pc6 from "picocolors";
|
|
1049
1223
|
async function list(options) {
|
|
1050
1224
|
const packages = await getInstalledPackages();
|
|
1051
1225
|
if (packages.length === 0) {
|
|
1052
|
-
console.log(
|
|
1053
|
-
console.log(
|
|
1054
|
-
console.log(`Run ${
|
|
1226
|
+
console.log(pc6.yellow("\nI find your lack of skills disturbing.\n"));
|
|
1227
|
+
console.log(pc6.gray("No packages installed."));
|
|
1228
|
+
console.log(`Run ${pc6.cyan("olore install <package>")} to install documentation.`);
|
|
1055
1229
|
return;
|
|
1056
1230
|
}
|
|
1057
1231
|
if (options.json) {
|
|
@@ -1059,29 +1233,29 @@ async function list(options) {
|
|
|
1059
1233
|
console.log(JSON.stringify({ packages, issueCount: issues2.length }, null, 2));
|
|
1060
1234
|
return;
|
|
1061
1235
|
}
|
|
1062
|
-
console.log(
|
|
1236
|
+
console.log(pc6.bold("\nInstalled packages:\n"));
|
|
1063
1237
|
console.log(
|
|
1064
|
-
|
|
1238
|
+
pc6.gray(
|
|
1065
1239
|
"PACKAGE".padEnd(25) + "VERSION".padEnd(12) + "TYPE".padEnd(10) + "FILES".padStart(8) + "SIZE".padStart(12)
|
|
1066
1240
|
)
|
|
1067
1241
|
);
|
|
1068
|
-
console.log(
|
|
1242
|
+
console.log(pc6.gray("-".repeat(67)));
|
|
1069
1243
|
for (const pkg of packages) {
|
|
1070
|
-
const typeLabel = pkg.installType === "linked" ?
|
|
1244
|
+
const typeLabel = pkg.installType === "linked" ? pc6.blue("linked") : pkg.installType;
|
|
1071
1245
|
console.log(
|
|
1072
1246
|
pkg.name.padEnd(25) + pkg.version.padEnd(12) + typeLabel.padEnd(10) + String(pkg.files).padStart(8) + formatSize(pkg.size).padStart(12)
|
|
1073
1247
|
);
|
|
1074
1248
|
}
|
|
1075
|
-
console.log(
|
|
1076
|
-
console.log(
|
|
1249
|
+
console.log(pc6.gray("-".repeat(67)));
|
|
1250
|
+
console.log(pc6.gray(`Total: ${packages.length} packages`));
|
|
1077
1251
|
console.log("");
|
|
1078
|
-
console.log(
|
|
1252
|
+
console.log(pc6.gray("Types: installed = in ~/.olore, linked = dev symlink, copied = legacy"));
|
|
1079
1253
|
const { issues } = await diagnose();
|
|
1080
1254
|
if (issues.length > 0) {
|
|
1081
1255
|
console.log("");
|
|
1082
1256
|
console.log(
|
|
1083
|
-
|
|
1084
|
-
`\u26A0 ${issues.length} issue${issues.length === 1 ? "" : "s"} detected. Run ${
|
|
1257
|
+
pc6.yellow(
|
|
1258
|
+
`\u26A0 ${issues.length} issue${issues.length === 1 ? "" : "s"} detected. Run ${pc6.cyan("olore doctor")} for details.`
|
|
1085
1259
|
)
|
|
1086
1260
|
);
|
|
1087
1261
|
}
|
|
@@ -1093,59 +1267,59 @@ function formatSize(bytes) {
|
|
|
1093
1267
|
}
|
|
1094
1268
|
|
|
1095
1269
|
// src/commands/order66.ts
|
|
1096
|
-
import
|
|
1097
|
-
import
|
|
1270
|
+
import path9 from "path";
|
|
1271
|
+
import fs9 from "fs-extra";
|
|
1098
1272
|
import ora3 from "ora";
|
|
1099
|
-
import
|
|
1273
|
+
import pc7 from "picocolors";
|
|
1100
1274
|
async function order66() {
|
|
1101
|
-
console.log(
|
|
1102
|
-
console.log(
|
|
1275
|
+
console.log(pc7.red("\n\u26A0\uFE0F Execute Order 66?\n"));
|
|
1276
|
+
console.log(pc7.yellow("This will remove ALL installed documentation packages."));
|
|
1103
1277
|
const packages = await getInstalledPackages();
|
|
1104
1278
|
if (packages.length === 0) {
|
|
1105
|
-
console.log(
|
|
1279
|
+
console.log(pc7.gray("\nNo packages to remove. The Jedi are already gone."));
|
|
1106
1280
|
return;
|
|
1107
1281
|
}
|
|
1108
|
-
console.log(
|
|
1282
|
+
console.log(pc7.gray(`
|
|
1109
1283
|
Packages to be removed: ${packages.length}`));
|
|
1110
1284
|
for (const pkg of packages) {
|
|
1111
|
-
console.log(
|
|
1285
|
+
console.log(pc7.gray(` - ${pkg.name}@${pkg.version}`));
|
|
1112
1286
|
}
|
|
1113
|
-
console.log(
|
|
1287
|
+
console.log(pc7.red('\n"It will be done, my lord."\n'));
|
|
1114
1288
|
const spinner = ora3("Executing Order 66...").start();
|
|
1115
1289
|
let removedCount = 0;
|
|
1116
1290
|
const agentPaths = getAgentPaths();
|
|
1117
1291
|
for (const pkg of packages) {
|
|
1118
1292
|
const skillName = `olore-${pkg.name}-${pkg.version}`;
|
|
1119
1293
|
for (const [, basePath] of Object.entries(agentPaths)) {
|
|
1120
|
-
const skillPath =
|
|
1121
|
-
if (await
|
|
1122
|
-
await
|
|
1294
|
+
const skillPath = path9.join(basePath, skillName);
|
|
1295
|
+
if (await fs9.pathExists(skillPath)) {
|
|
1296
|
+
await fs9.remove(skillPath);
|
|
1123
1297
|
}
|
|
1124
1298
|
}
|
|
1125
1299
|
if (pkg.installType === "installed") {
|
|
1126
1300
|
const olorePath = getOlorePackagePath(pkg.name, pkg.version);
|
|
1127
|
-
if (await
|
|
1128
|
-
await
|
|
1301
|
+
if (await fs9.pathExists(olorePath)) {
|
|
1302
|
+
await fs9.remove(olorePath);
|
|
1129
1303
|
}
|
|
1130
1304
|
}
|
|
1131
1305
|
removedCount++;
|
|
1132
1306
|
}
|
|
1133
1307
|
spinner.succeed(`Removed ${removedCount} packages`);
|
|
1134
|
-
console.log(
|
|
1308
|
+
console.log(pc7.gray("\nThe Jedi have been eliminated."));
|
|
1135
1309
|
}
|
|
1136
1310
|
|
|
1137
1311
|
// src/commands/prune.ts
|
|
1138
|
-
import
|
|
1312
|
+
import pc8 from "picocolors";
|
|
1139
1313
|
async function prune(options) {
|
|
1140
1314
|
if (!options.json) {
|
|
1141
|
-
console.log(
|
|
1315
|
+
console.log(pc8.bold("\nScanning for issues...\n"));
|
|
1142
1316
|
}
|
|
1143
1317
|
const { issues } = await diagnose();
|
|
1144
1318
|
if (issues.length === 0) {
|
|
1145
1319
|
if (options.json) {
|
|
1146
1320
|
console.log(JSON.stringify({ removed: [], failed: [] }, null, 2));
|
|
1147
1321
|
} else {
|
|
1148
|
-
console.log(
|
|
1322
|
+
console.log(pc8.green("Nothing to prune. Everything is clean."));
|
|
1149
1323
|
}
|
|
1150
1324
|
return;
|
|
1151
1325
|
}
|
|
@@ -1155,14 +1329,14 @@ async function prune(options) {
|
|
|
1155
1329
|
return;
|
|
1156
1330
|
}
|
|
1157
1331
|
console.log(
|
|
1158
|
-
|
|
1332
|
+
pc8.yellow(`Would remove ${issues.length} item${issues.length === 1 ? "" : "s"}:
|
|
1159
1333
|
`)
|
|
1160
1334
|
);
|
|
1161
1335
|
for (const issue of issues) {
|
|
1162
1336
|
console.log(` ${issueLabel(issue.type)} ${displayPath(issue.path)}`);
|
|
1163
1337
|
}
|
|
1164
1338
|
console.log(`
|
|
1165
|
-
Run ${
|
|
1339
|
+
Run ${pc8.cyan("olore prune")} (without --dry-run) to remove them.`);
|
|
1166
1340
|
return;
|
|
1167
1341
|
}
|
|
1168
1342
|
const result = await pruneIssues(issues);
|
|
@@ -1176,7 +1350,7 @@ Run ${pc7.cyan("olore prune")} (without --dry-run) to remove them.`);
|
|
|
1176
1350
|
for (const entry of result.removed) {
|
|
1177
1351
|
totalFreed += entry.freedBytes;
|
|
1178
1352
|
console.log(
|
|
1179
|
-
` ${
|
|
1353
|
+
` ${pc8.green("\u2713")} ${displayPath(entry.issue.path)} (${issueLabel(entry.issue.type)})`
|
|
1180
1354
|
);
|
|
1181
1355
|
}
|
|
1182
1356
|
if (totalFreed > 0) {
|
|
@@ -1187,12 +1361,12 @@ ${formatBytes(totalFreed)} freed.`);
|
|
|
1187
1361
|
if (result.failed.length > 0) {
|
|
1188
1362
|
console.log("");
|
|
1189
1363
|
console.log(
|
|
1190
|
-
|
|
1364
|
+
pc8.red(
|
|
1191
1365
|
`Failed to remove ${result.failed.length} item${result.failed.length === 1 ? "" : "s"}:`
|
|
1192
1366
|
)
|
|
1193
1367
|
);
|
|
1194
1368
|
for (const entry of result.failed) {
|
|
1195
|
-
console.log(` ${
|
|
1369
|
+
console.log(` ${pc8.red("\u2717")} ${displayPath(entry.issue.path)}: ${entry.error}`);
|
|
1196
1370
|
}
|
|
1197
1371
|
}
|
|
1198
1372
|
}
|
|
@@ -1210,12 +1384,12 @@ function issueLabel(type) {
|
|
|
1210
1384
|
}
|
|
1211
1385
|
|
|
1212
1386
|
// src/commands/remove.ts
|
|
1213
|
-
import
|
|
1214
|
-
import
|
|
1387
|
+
import path10 from "path";
|
|
1388
|
+
import fs10 from "fs-extra";
|
|
1215
1389
|
import ora4 from "ora";
|
|
1216
|
-
import
|
|
1390
|
+
import pc9 from "picocolors";
|
|
1217
1391
|
async function remove(pkg) {
|
|
1218
|
-
console.log(
|
|
1392
|
+
console.log(pc9.bold(`
|
|
1219
1393
|
Removing ${pkg}...
|
|
1220
1394
|
`));
|
|
1221
1395
|
const packages = await getInstalledPackages();
|
|
@@ -1231,20 +1405,20 @@ Removing ${pkg}...
|
|
|
1231
1405
|
return p.name === name;
|
|
1232
1406
|
});
|
|
1233
1407
|
if (matches.length === 0) {
|
|
1234
|
-
console.error(
|
|
1408
|
+
console.error(pc9.red(`Package not found: ${pkg}`));
|
|
1235
1409
|
console.log("\nInstalled packages:");
|
|
1236
1410
|
for (const p of packages) {
|
|
1237
|
-
console.log(` ${
|
|
1411
|
+
console.log(` ${pc9.cyan(p.name)}@${p.version}`);
|
|
1238
1412
|
}
|
|
1239
1413
|
process.exit(1);
|
|
1240
1414
|
}
|
|
1241
1415
|
if (matches.length > 1 && !version2) {
|
|
1242
|
-
console.error(
|
|
1416
|
+
console.error(pc9.red(`Multiple versions found for ${name}:`));
|
|
1243
1417
|
for (const p of matches) {
|
|
1244
|
-
console.log(` ${
|
|
1418
|
+
console.log(` ${pc9.cyan(p.name)}@${p.version} (${p.installType})`);
|
|
1245
1419
|
}
|
|
1246
1420
|
console.log(`
|
|
1247
|
-
Specify version: ${
|
|
1421
|
+
Specify version: ${pc9.cyan(`olore remove ${name}@<version>`)}`);
|
|
1248
1422
|
process.exit(1);
|
|
1249
1423
|
}
|
|
1250
1424
|
const found = matches[0];
|
|
@@ -1253,32 +1427,32 @@ Specify version: ${pc8.cyan(`olore remove ${name}@<version>`)}`);
|
|
|
1253
1427
|
const removed = [];
|
|
1254
1428
|
const agentPaths = getAgentPaths();
|
|
1255
1429
|
for (const [agent, basePath] of Object.entries(agentPaths)) {
|
|
1256
|
-
const skillPath =
|
|
1257
|
-
if (await
|
|
1258
|
-
await
|
|
1259
|
-
removed.push(`${
|
|
1430
|
+
const skillPath = path10.join(basePath, skillName);
|
|
1431
|
+
if (await fs10.pathExists(skillPath)) {
|
|
1432
|
+
await fs10.remove(skillPath);
|
|
1433
|
+
removed.push(`${pc9.green("\u2713")} ${agent}`);
|
|
1260
1434
|
}
|
|
1261
1435
|
}
|
|
1262
1436
|
if (found.installType === "installed") {
|
|
1263
1437
|
const olorePath = getOlorePackagePath(found.name, found.version);
|
|
1264
|
-
if (await
|
|
1265
|
-
await
|
|
1266
|
-
removed.push(`${
|
|
1438
|
+
if (await fs10.pathExists(olorePath)) {
|
|
1439
|
+
await fs10.remove(olorePath);
|
|
1440
|
+
removed.push(`${pc9.green("\u2713")} ~/.olore`);
|
|
1267
1441
|
}
|
|
1268
1442
|
}
|
|
1269
1443
|
spinner.stop();
|
|
1270
1444
|
if (removed.length === 0) {
|
|
1271
|
-
console.log(
|
|
1445
|
+
console.log(pc9.yellow("No files found to remove."));
|
|
1272
1446
|
} else {
|
|
1273
1447
|
removed.forEach((line) => console.log(` ${line}`));
|
|
1274
1448
|
console.log("");
|
|
1275
|
-
console.log(
|
|
1449
|
+
console.log(pc9.green(`Removed ${found.name}@${found.version}`));
|
|
1276
1450
|
}
|
|
1277
1451
|
}
|
|
1278
1452
|
|
|
1279
1453
|
// src/commands/search.ts
|
|
1280
1454
|
import ora5 from "ora";
|
|
1281
|
-
import
|
|
1455
|
+
import pc10 from "picocolors";
|
|
1282
1456
|
async function search(query, options) {
|
|
1283
1457
|
const spinner = ora5("Fetching package registry...").start();
|
|
1284
1458
|
let packages;
|
|
@@ -1290,15 +1464,15 @@ async function search(query, options) {
|
|
|
1290
1464
|
spinner.fail("Failed to fetch registry");
|
|
1291
1465
|
if (error instanceof RegistryError) {
|
|
1292
1466
|
if (error.code === "NETWORK_ERROR" || error.code === "TIMEOUT") {
|
|
1293
|
-
console.log(
|
|
1467
|
+
console.log(pc10.red(`
|
|
1294
1468
|
Network error: ${error.message}`));
|
|
1295
|
-
console.log(
|
|
1469
|
+
console.log(pc10.gray("Please check your internet connection and try again."));
|
|
1296
1470
|
} else {
|
|
1297
|
-
console.log(
|
|
1471
|
+
console.log(pc10.red(`
|
|
1298
1472
|
Error: ${error.message}`));
|
|
1299
1473
|
}
|
|
1300
1474
|
} else {
|
|
1301
|
-
console.log(
|
|
1475
|
+
console.log(pc10.red(`
|
|
1302
1476
|
Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
1303
1477
|
}
|
|
1304
1478
|
process.exit(1);
|
|
@@ -1312,10 +1486,10 @@ Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
|
1312
1486
|
}
|
|
1313
1487
|
if (entries.length === 0) {
|
|
1314
1488
|
if (query) {
|
|
1315
|
-
console.log(
|
|
1489
|
+
console.log(pc10.yellow(`
|
|
1316
1490
|
No packages matching '${query}'`));
|
|
1317
1491
|
} else {
|
|
1318
|
-
console.log(
|
|
1492
|
+
console.log(pc10.yellow("\nNo packages available in the registry"));
|
|
1319
1493
|
}
|
|
1320
1494
|
return;
|
|
1321
1495
|
}
|
|
@@ -1342,26 +1516,26 @@ No packages matching '${query}'`));
|
|
|
1342
1516
|
const colName = 20;
|
|
1343
1517
|
const colDesc = 44;
|
|
1344
1518
|
const colVersions = 12;
|
|
1345
|
-
console.log(
|
|
1519
|
+
console.log(pc10.bold("\nAvailable packages:\n"));
|
|
1346
1520
|
console.log(
|
|
1347
|
-
|
|
1521
|
+
pc10.gray(
|
|
1348
1522
|
"PACKAGE".padEnd(colName) + "DESCRIPTION".padEnd(colDesc) + "VERSIONS".padEnd(colVersions) + "INSTALLED"
|
|
1349
1523
|
)
|
|
1350
1524
|
);
|
|
1351
|
-
console.log(
|
|
1525
|
+
console.log(pc10.gray("\u2500".repeat(colName + colDesc + colVersions + 12)));
|
|
1352
1526
|
for (const [name, info] of entries.sort(([a], [b]) => a.localeCompare(b))) {
|
|
1353
1527
|
const desc = truncate(info.description, colDesc - 2);
|
|
1354
1528
|
const versions = info.versions.join(", ");
|
|
1355
1529
|
const installedVersion = installedVersions.get(name);
|
|
1356
|
-
const status = installedVersion ?
|
|
1530
|
+
const status = installedVersion ? pc10.green(`\u2713 ${installedVersion}`) : "";
|
|
1357
1531
|
console.log(
|
|
1358
1532
|
name.padEnd(colName) + desc.padEnd(colDesc) + versions.padEnd(colVersions) + status
|
|
1359
1533
|
);
|
|
1360
1534
|
}
|
|
1361
|
-
console.log(
|
|
1362
|
-
console.log(
|
|
1535
|
+
console.log(pc10.gray("\u2500".repeat(colName + colDesc + colVersions + 12)));
|
|
1536
|
+
console.log(pc10.gray(`${entries.length} package${entries.length === 1 ? "" : "s"} available`));
|
|
1363
1537
|
console.log(`
|
|
1364
|
-
Install with: ${
|
|
1538
|
+
Install with: ${pc10.cyan("olore install <package>")}`);
|
|
1365
1539
|
}
|
|
1366
1540
|
function truncate(str, maxLen) {
|
|
1367
1541
|
if (str.length <= maxLen) return str;
|
|
@@ -1373,12 +1547,12 @@ var require2 = createRequire(import.meta.url);
|
|
|
1373
1547
|
var { version } = require2("../package.json");
|
|
1374
1548
|
var program = new Command();
|
|
1375
1549
|
program.name("olore").description("Universal documentation for any AI coding agent").version(version).addHelpText("after", `
|
|
1376
|
-
${
|
|
1550
|
+
${pc11.gray("May the Skill be with you.")}`);
|
|
1377
1551
|
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) => {
|
|
1378
1552
|
try {
|
|
1379
1553
|
await init(options);
|
|
1380
1554
|
} catch (error) {
|
|
1381
|
-
console.error(
|
|
1555
|
+
console.error(pc11.red(`Error: ${error.message}`));
|
|
1382
1556
|
process.exit(1);
|
|
1383
1557
|
}
|
|
1384
1558
|
});
|
|
@@ -1386,7 +1560,7 @@ program.command("install <package>").alias("i").description("Install a documenta
|
|
|
1386
1560
|
try {
|
|
1387
1561
|
await install(pkg, options);
|
|
1388
1562
|
} catch (error) {
|
|
1389
|
-
console.error(
|
|
1563
|
+
console.error(pc11.red(`Error: ${error.message}`));
|
|
1390
1564
|
process.exit(1);
|
|
1391
1565
|
}
|
|
1392
1566
|
});
|
|
@@ -1394,7 +1568,7 @@ program.command("link <path>").description("Link a local package for development
|
|
|
1394
1568
|
try {
|
|
1395
1569
|
await link(localPath);
|
|
1396
1570
|
} catch (error) {
|
|
1397
|
-
console.error(
|
|
1571
|
+
console.error(pc11.red(`Error: ${error.message}`));
|
|
1398
1572
|
process.exit(1);
|
|
1399
1573
|
}
|
|
1400
1574
|
});
|
|
@@ -1402,7 +1576,7 @@ program.command("list").alias("ls").description("List installed documentation pa
|
|
|
1402
1576
|
try {
|
|
1403
1577
|
await list(options);
|
|
1404
1578
|
} catch (error) {
|
|
1405
|
-
console.error(
|
|
1579
|
+
console.error(pc11.red(`Error: ${error.message}`));
|
|
1406
1580
|
process.exit(1);
|
|
1407
1581
|
}
|
|
1408
1582
|
});
|
|
@@ -1410,7 +1584,7 @@ program.command("search [query]").description("Search available packages in the
|
|
|
1410
1584
|
try {
|
|
1411
1585
|
await search(query, options);
|
|
1412
1586
|
} catch (error) {
|
|
1413
|
-
console.error(
|
|
1587
|
+
console.error(pc11.red(`Error: ${error.message}`));
|
|
1414
1588
|
process.exit(1);
|
|
1415
1589
|
}
|
|
1416
1590
|
});
|
|
@@ -1418,7 +1592,7 @@ program.command("remove <package>").alias("rm").description("Remove an installed
|
|
|
1418
1592
|
try {
|
|
1419
1593
|
await remove(pkg);
|
|
1420
1594
|
} catch (error) {
|
|
1421
|
-
console.error(
|
|
1595
|
+
console.error(pc11.red(`Error: ${error.message}`));
|
|
1422
1596
|
process.exit(1);
|
|
1423
1597
|
}
|
|
1424
1598
|
});
|
|
@@ -1426,7 +1600,7 @@ program.command("doctor").description("Check for issues with installed packages"
|
|
|
1426
1600
|
try {
|
|
1427
1601
|
await doctor(options);
|
|
1428
1602
|
} catch (error) {
|
|
1429
|
-
console.error(
|
|
1603
|
+
console.error(pc11.red(`Error: ${error.message}`));
|
|
1430
1604
|
process.exit(1);
|
|
1431
1605
|
}
|
|
1432
1606
|
});
|
|
@@ -1434,7 +1608,15 @@ program.command("prune").description("Remove dangling symlinks, orphaned package
|
|
|
1434
1608
|
try {
|
|
1435
1609
|
await prune(options);
|
|
1436
1610
|
} catch (error) {
|
|
1437
|
-
console.error(
|
|
1611
|
+
console.error(pc11.red(`Error: ${error.message}`));
|
|
1612
|
+
process.exit(1);
|
|
1613
|
+
}
|
|
1614
|
+
});
|
|
1615
|
+
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) => {
|
|
1616
|
+
try {
|
|
1617
|
+
await inject(options);
|
|
1618
|
+
} catch (error) {
|
|
1619
|
+
console.error(pc11.red(`Error: ${error.message}`));
|
|
1438
1620
|
process.exit(1);
|
|
1439
1621
|
}
|
|
1440
1622
|
});
|
|
@@ -1442,7 +1624,7 @@ program.command("order66").description(false).action(async () => {
|
|
|
1442
1624
|
try {
|
|
1443
1625
|
await order66();
|
|
1444
1626
|
} catch (error) {
|
|
1445
|
-
console.error(
|
|
1627
|
+
console.error(pc11.red(`Error: ${error.message}`));
|
|
1446
1628
|
process.exit(1);
|
|
1447
1629
|
}
|
|
1448
1630
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olorehq/olore",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
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"
|