@wiimdy/openfunderse 0.1.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 ADDED
@@ -0,0 +1,22 @@
1
+ # openfunderse
2
+
3
+ Install OpenFunderse skill packs into Codex.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ # list bundled packs
9
+ npx @wiimdy/openfunderse@latest list
10
+
11
+ # install pack into ~/.codex/skills
12
+ npx @wiimdy/openfunderse@latest install openfunderse
13
+
14
+ # install into custom codex home
15
+ npx @wiimdy/openfunderse@latest install openfunderse --codex-home /custom/.codex
16
+ ```
17
+
18
+ ## Notes
19
+
20
+ - Skills are copied into `$CODEX_HOME/skills` (default `~/.codex/skills`).
21
+ - Pack metadata/prompts are copied into `$CODEX_HOME/packs/<pack-name>`.
22
+ - Use `--force` to overwrite existing installed skills.
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { existsSync } from "node:fs";
4
+ import { cp, mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
5
+ import os from "node:os";
6
+ import path from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+
9
+ const THIS_FILE = fileURLToPath(import.meta.url);
10
+ const PACKAGE_ROOT = path.resolve(path.dirname(THIS_FILE), "..");
11
+ const PACKS_ROOT = path.join(PACKAGE_ROOT, "packs");
12
+
13
+ function printUsage() {
14
+ console.log(`openfunderse
15
+
16
+ Usage:
17
+ openfunderse list
18
+ openfunderse install <pack-name> [--dest <skills-dir>] [--codex-home <dir>] [--force]
19
+
20
+ Examples:
21
+ openfunderse list
22
+ openfunderse install openfunderse
23
+ openfunderse install openfunderse --codex-home /tmp/codex-home
24
+ `);
25
+ }
26
+
27
+ function parseArgs(argv) {
28
+ const args = [...argv];
29
+ const command = args.shift();
30
+ const options = {
31
+ force: false,
32
+ dest: "",
33
+ codexHome: ""
34
+ };
35
+ const positionals = [];
36
+
37
+ for (let i = 0; i < args.length; i += 1) {
38
+ const token = args[i];
39
+ if (token === "--help" || token === "-h") {
40
+ options.help = true;
41
+ continue;
42
+ }
43
+ if (token === "--force") {
44
+ options.force = true;
45
+ continue;
46
+ }
47
+ if (token === "--dest") {
48
+ options.dest = args[i + 1] ?? "";
49
+ i += 1;
50
+ continue;
51
+ }
52
+ if (token === "--codex-home") {
53
+ options.codexHome = args[i + 1] ?? "";
54
+ i += 1;
55
+ continue;
56
+ }
57
+ if (token.startsWith("--")) {
58
+ throw new Error(`unknown option: ${token}`);
59
+ }
60
+ positionals.push(token);
61
+ }
62
+
63
+ return { command, options, positionals };
64
+ }
65
+
66
+ function defaultCodexHome() {
67
+ return process.env.CODEX_HOME || path.join(os.homedir(), ".codex");
68
+ }
69
+
70
+ function ensureUnderRoot(root, target) {
71
+ const resolvedRoot = path.resolve(root);
72
+ const resolvedTarget = path.resolve(target);
73
+ if (resolvedTarget === resolvedRoot || resolvedTarget.startsWith(`${resolvedRoot}${path.sep}`)) {
74
+ return;
75
+ }
76
+ throw new Error(`path escapes pack root: ${target}`);
77
+ }
78
+
79
+ async function listPacks() {
80
+ const entries = await readdir(PACKS_ROOT, { withFileTypes: true });
81
+ const packs = entries
82
+ .filter((entry) => entry.isDirectory())
83
+ .map((entry) => entry.name)
84
+ .sort((a, b) => a.localeCompare(b));
85
+
86
+ if (packs.length === 0) {
87
+ console.log("No packs bundled.");
88
+ return;
89
+ }
90
+
91
+ for (const pack of packs) {
92
+ console.log(pack);
93
+ }
94
+ }
95
+
96
+ async function loadManifest(packDir) {
97
+ const candidates = [
98
+ path.join(packDir, "manifest.json"),
99
+ path.join(packDir, "config", "setup-manifest.json")
100
+ ];
101
+
102
+ for (const candidate of candidates) {
103
+ if (!existsSync(candidate)) continue;
104
+ const json = JSON.parse(await readFile(candidate, "utf8"));
105
+ return { json, path: candidate };
106
+ }
107
+
108
+ throw new Error("manifest file not found (manifest.json or config/setup-manifest.json)");
109
+ }
110
+
111
+ async function copySkillDir(sourceDir, destinationDir, force) {
112
+ const destinationExists = existsSync(destinationDir);
113
+ if (destinationExists && !force) {
114
+ throw new Error(`skill already exists: ${destinationDir} (use --force to overwrite)`);
115
+ }
116
+
117
+ if (destinationExists && force) {
118
+ await rm(destinationDir, { recursive: true, force: true });
119
+ }
120
+
121
+ await mkdir(path.dirname(destinationDir), { recursive: true });
122
+ await cp(sourceDir, destinationDir, { recursive: true });
123
+ }
124
+
125
+ async function installPack(packName, options) {
126
+ const packDir = path.join(PACKS_ROOT, packName);
127
+ if (!existsSync(packDir)) {
128
+ throw new Error(`pack not found: ${packName}`);
129
+ }
130
+
131
+ const { json: manifest, path: manifestPath } = await loadManifest(packDir);
132
+ if (!Array.isArray(manifest.bundles) || manifest.bundles.length === 0) {
133
+ throw new Error("manifest has no bundles");
134
+ }
135
+
136
+ const codexHome = options.codexHome ? path.resolve(options.codexHome) : defaultCodexHome();
137
+ const skillsRoot = options.dest
138
+ ? path.resolve(options.dest)
139
+ : path.join(codexHome, "skills");
140
+
141
+ await mkdir(skillsRoot, { recursive: true });
142
+
143
+ const installed = [];
144
+
145
+ for (const bundle of manifest.bundles) {
146
+ if (!bundle || typeof bundle.skill !== "string") {
147
+ throw new Error("invalid bundle entry: missing skill path");
148
+ }
149
+
150
+ const skillMd = path.resolve(packDir, bundle.skill);
151
+ ensureUnderRoot(packDir, skillMd);
152
+
153
+ if (path.basename(skillMd) !== "SKILL.md") {
154
+ throw new Error(`bundle skill must point to SKILL.md: ${bundle.skill}`);
155
+ }
156
+
157
+ if (!existsSync(skillMd)) {
158
+ throw new Error(`missing skill file: ${skillMd}`);
159
+ }
160
+
161
+ const sourceSkillDir = path.dirname(skillMd);
162
+ const skillName = path.basename(sourceSkillDir);
163
+ const destinationSkillDir = path.join(skillsRoot, skillName);
164
+
165
+ await copySkillDir(sourceSkillDir, destinationSkillDir, options.force);
166
+ installed.push(skillName);
167
+ }
168
+
169
+ const packMetaRoot = path.join(codexHome, "packs", packName);
170
+ await mkdir(path.dirname(path.join(packMetaRoot, "_")), { recursive: true });
171
+
172
+ await cp(packDir, packMetaRoot, { recursive: true, force: true });
173
+
174
+ const installedMeta = {
175
+ installedAt: new Date().toISOString(),
176
+ source: "openfunderse",
177
+ packageRoot: PACKAGE_ROOT,
178
+ manifestPath: path.relative(packDir, manifestPath),
179
+ installedSkills: installed
180
+ };
181
+ await writeFile(path.join(packMetaRoot, "install.json"), `${JSON.stringify(installedMeta, null, 2)}\n`);
182
+
183
+ console.log(`Installed pack: ${packName}`);
184
+ console.log(`Skills root: ${skillsRoot}`);
185
+ console.log(`Installed skills: ${installed.join(", ")}`);
186
+ console.log(`Pack metadata: ${packMetaRoot}`);
187
+ console.log("Restart Codex to pick up new skills.");
188
+ }
189
+
190
+ async function main() {
191
+ const { command, options, positionals } = parseArgs(process.argv.slice(2));
192
+
193
+ if (!command || options.help || command === "help") {
194
+ printUsage();
195
+ return;
196
+ }
197
+
198
+ if (command === "list") {
199
+ await listPacks();
200
+ return;
201
+ }
202
+
203
+ if (command === "install") {
204
+ const packName = positionals[0];
205
+ if (!packName) {
206
+ throw new Error("missing required argument: <pack-name>");
207
+ }
208
+ await installPack(packName, options);
209
+ return;
210
+ }
211
+
212
+ throw new Error(`unknown command: ${command}`);
213
+ }
214
+
215
+ main().catch((error) => {
216
+ const message = error instanceof Error ? error.message : String(error);
217
+ console.error(`openfunderse error: ${message}`);
218
+ process.exitCode = 1;
219
+ });
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "@wiimdy/openfunderse",
3
+ "version": "0.1.0",
4
+ "description": "Install OpenFunderse skill packs into Codex",
5
+ "type": "module",
6
+ "bin": {
7
+ "openfunderse": "./bin/openfunderse.mjs"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "packs",
12
+ "README.md"
13
+ ],
14
+ "engines": {
15
+ "node": ">=20"
16
+ },
17
+ "scripts": {
18
+ "start": "node ./bin/openfunderse.mjs",
19
+ "check": "node ./bin/openfunderse.mjs list"
20
+ }
21
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "openfunderse-agent-pack",
3
+ "version": "0.1.0",
4
+ "installCommand": "npx @wiimdy/openfunderse@latest install openfunderse",
5
+ "description": "Scaffold manifest for future MoltBot skills/prompts packaging.",
6
+ "bundles": [
7
+ {
8
+ "id": "strategy",
9
+ "skill": "skills/strategy/SKILL.md",
10
+ "prompt": "prompts/strategy/system.md"
11
+ },
12
+ {
13
+ "id": "participant",
14
+ "skill": "skills/participant/SKILL.md",
15
+ "prompt": "prompts/participant/system.md"
16
+ },
17
+ {
18
+ "id": "relayer",
19
+ "skill": "skills/relayer/SKILL.md",
20
+ "prompt": "prompts/relayer/system.md"
21
+ }
22
+ ],
23
+ "todo": [
24
+ "Implement openfunderse installer package publishing flow",
25
+ "Add signed package checksum and version pinning",
26
+ "Add integration test that installs this pack in a clean environment"
27
+ ]
28
+ }
@@ -0,0 +1,3 @@
1
+ # Participant System Prompt (TODO)
2
+
3
+ Define deterministic prompt contract for claim mining/verification behaviors.
@@ -0,0 +1,3 @@
1
+ # Relayer System Prompt (TODO)
2
+
3
+ Define deterministic prompt contract for relayer-side orchestration helpers.
@@ -0,0 +1,3 @@
1
+ # Strategy System Prompt (TODO)
2
+
3
+ Define deterministic prompt contract for strategy intent generation.
@@ -0,0 +1,9 @@
1
+ # Participant Skill (TODO)
2
+
3
+ Purpose:
4
+ - Define participant MoltBot behavior for claim collection and validation loops.
5
+
6
+ TODO:
7
+ - Claim extraction and evidence policy
8
+ - Attestation checks and signing guardrails
9
+ - Chat command interoperability
@@ -0,0 +1,9 @@
1
+ # Relayer Skill (TODO)
2
+
3
+ Purpose:
4
+ - Define relayer-support MoltBot behavior for submission orchestration.
5
+
6
+ TODO:
7
+ - Batch submission policy (claims/intents)
8
+ - Retry, nonce, and expiry policy
9
+ - Operator notification hooks
@@ -0,0 +1,9 @@
1
+ # Strategy Skill (TODO)
2
+
3
+ Purpose:
4
+ - Define strategy MoltBot behavior for proposing intents from finalized snapshots.
5
+
6
+ TODO:
7
+ - Input contract (snapshot, risk policy, fund config)
8
+ - Output contract (intent payload + reason hash)
9
+ - Failure handling and safe fallback policy