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