risupack 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,155 @@
1
+ # risupack
2
+
3
+ A CLI and TypeScript library for building and unpacking RisuAI CharX and RisuM artifacts.
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ npm install --save-dev risupack
9
+ ```
10
+
11
+ ## Commands
12
+
13
+ ```sh
14
+ risupack build-charx <manifest.json> [output.charx]
15
+ risupack bundle-lua <entry.lua> <output.lua>
16
+ risupack inspect-risusave <database.bin> [namespace-or-name]
17
+ risupack unpack-charx <input.charx> [output-directory]
18
+ risupack unpack-risum <input.risum> [output-directory]
19
+ ```
20
+
21
+ Set `SOURCE_DATE_EPOCH` when reproducible CharX output is required.
22
+
23
+ ```sh
24
+ SOURCE_DATE_EPOCH=1700000000 risupack build-charx module/charx.json
25
+ ```
26
+
27
+ ## CharX output
28
+
29
+ The builder creates a ZIP archive containing the RisuAI card, encoded module, assets, and CharX metadata.
30
+
31
+ ```text
32
+ module.charx
33
+ ├── card.json
34
+ ├── module.risum
35
+ ├── assets/
36
+ └── x_meta/
37
+ ```
38
+
39
+ ## Module layout
40
+
41
+ The builder does not require a particular source directory layout. The `unpack-charx` and `unpack-risum` commands materialize recovered sources with the following layout when the corresponding source types exist.
42
+
43
+ ```text
44
+ <output>/
45
+ ├── assets/
46
+ ├── lorebooks/
47
+ ├── regex/
48
+ ├── styles/
49
+ ├── triggers/
50
+ ├── charx.json
51
+ └── toggles.txt
52
+ ```
53
+
54
+ Input manifests may use other layouts. Update every affected path in `charx.json` after moving a source file.
55
+
56
+ ## Manifest paths
57
+
58
+ Resolve paths inside `charx.json` from the directory containing `charx.json`. This rule applies to `CSS`, `assets`, `icon`, `lorebook`, `output`, `regex`, `toggles`, trigger `lua`, and trigger `bundleOutput`.
59
+
60
+ Use the following manifest structure.
61
+
62
+ ```json
63
+ {
64
+ "CSS": "style.html",
65
+ "assets": [
66
+ {
67
+ "file": "assets/background.webp",
68
+ "name": "background"
69
+ }
70
+ ],
71
+ "description": "Module description",
72
+ "hideIcon": false,
73
+ "icon": "assets/icon.png",
74
+ "lorebook": [
75
+ {
76
+ "alwaysActive": false,
77
+ "comment": "sample",
78
+ "file": "lorebooks/sample.md",
79
+ "folder": "Sample",
80
+ "insertOrder": 100,
81
+ "key": "",
82
+ "mode": "normal",
83
+ "secondaryKey": "",
84
+ "selective": false,
85
+ "useRegex": false
86
+ }
87
+ ],
88
+ "lowLevelAccess": true,
89
+ "name": "Sample Module",
90
+ "namespace": "sample",
91
+ "regex": ["regex/display.md"],
92
+ "toggles": "toggles.txt",
93
+ "triggers": [
94
+ {
95
+ "bundle": true,
96
+ "lowLevelAccess": true,
97
+ "lua": "triggers/main.lua",
98
+ "type": "start"
99
+ }
100
+ ],
101
+ "version": "1.0.0"
102
+ }
103
+ ```
104
+
105
+ Use `{ "content": "..." }` instead of a file path only when a `CSS`, `toggles`, or lorebook source must remain inline.
106
+
107
+ ## Lua triggers
108
+
109
+ Set trigger `lua` to the unbundled entry file. Omit `bundle` or set `bundle` to `true` to let the CharX builder invoke the Lua bundler and embed the bundled code.
110
+
111
+ Omit `bundleOutput` for normal CharX builds. The builder uses a temporary output and removes it after packaging. Set `bundleOutput` only when a standalone bundled Lua artifact is required.
112
+
113
+ Keep modules loaded through Lua `require()` beside the trigger entry point or at paths resolvable by the Lua bundler.
114
+
115
+ ## Regex entries
116
+
117
+ Store one regex entry in each Markdown file. Put RisuAI regex metadata in frontmatter and the pattern pair in the body.
118
+
119
+ ```md
120
+ ---
121
+ ableFlag: true
122
+ comment: Display
123
+ flag: gs
124
+ type: editdisplay
125
+ ---
126
+
127
+ IN:
128
+ input pattern
129
+ OUT:
130
+ replacement
131
+ ```
132
+
133
+ Use the frontmatter keys `ableFlag`, `comment`, `flag`, and `type`. Omit `flag` when the regex requires no flags. Leave the body after `OUT:` empty when the replacement is empty.
134
+
135
+ List regex file paths in execution order in the manifest `regex` array.
136
+
137
+ ## Lorebooks
138
+
139
+ Include Markdown prompts in the manifest `lorebook` array.
140
+
141
+ Set `comment` to the exact lorebook name consumed by the module. Use `folder` to group entries in RisuAI.
142
+
143
+ Set lorebook `bundle` to `true` when RisuAI must receive bundled Lua as lorebook instead of the source file. Set lorebook `file` to the unbundled Lua entry point. Omit `bundleOutput` to remove the temporary bundle after packaging.
144
+
145
+ ## Assets
146
+
147
+ List additional packaged files in the manifest `assets` array. Set `file` and the RisuAI lookup `name`. Set `extension` only when the file extension cannot be inferred from `file`.
148
+
149
+ ## Programmatic API
150
+
151
+ The package exports `buildCharX()`, `bundleLua()`, `createExpandedModuleSources()`, `decodeModule()`, `parseModuleBlock()`, `parseZIP()`, `unpackCharX()`, and `unpackRisuM()`.
152
+
153
+ ## License
154
+
155
+ risupack is licensed under the GNU Affero General Public License version 3.
@@ -0,0 +1,2 @@
1
+ declare function buildCharX(manifestPath: string, outputArgument?: string): string;
2
+ export { buildCharX };
@@ -0,0 +1,2 @@
1
+ declare function bundleLua(entryPath: string, outputArgument: string): string;
2
+ export { bundleLua };
package/dist/cli.js ADDED
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env node
2
+ import { a as unpackCharX, c as bundleLua, o as parseModuleBlock, s as buildCharX, t as unpackRisuM } from "./unpack-risum-8Iw-UEO2.js";
3
+ import { readFileSync } from "node:fs";
4
+ import { join, parse } from "node:path";
5
+ //#region src/cli.ts
6
+ var COMMANDS = [
7
+ "build-charx",
8
+ "bundle-lua",
9
+ "inspect-risusave",
10
+ "unpack-charx",
11
+ "unpack-risum"
12
+ ];
13
+ function printUsage() {
14
+ console.error(`Usage: risupack <command> [arguments]
15
+
16
+ Commands:
17
+ build-charx <manifest.json> [output.charx]
18
+ bundle-lua <entry.lua> <output.lua>
19
+ inspect-risusave <database.bin> [namespace-or-name]
20
+ unpack-charx <input.charx> [output-directory]
21
+ unpack-risum <input.risum> [output-directory]`);
22
+ }
23
+ async function main() {
24
+ const [command, ...args] = process.argv.slice(2);
25
+ try {
26
+ switch (command) {
27
+ case "build-charx": {
28
+ const [manifestPath, outputPath] = args;
29
+ if (!manifestPath) throw new Error("build-charx requires a manifest path");
30
+ buildCharX(manifestPath, outputPath);
31
+ return;
32
+ }
33
+ case "bundle-lua": {
34
+ const [entryPath, outputPath] = args;
35
+ if (!entryPath || !outputPath) throw new Error("bundle-lua requires entry and output paths");
36
+ bundleLua(entryPath, outputPath);
37
+ return;
38
+ }
39
+ case "inspect-risusave": {
40
+ const [databasePath, query] = args;
41
+ if (!databasePath) throw new Error("inspect-risusave requires a database path");
42
+ const modules = parseModuleBlock(readFileSync(databasePath));
43
+ const selected = query ? modules.filter((module) => module.namespace === query || module.name === query || module.id === query) : modules;
44
+ process.stdout.write(`${JSON.stringify(selected, null, 2)}\n`);
45
+ return;
46
+ }
47
+ case "unpack-charx": {
48
+ const [inputPath, outputPath] = args;
49
+ if (!inputPath) throw new Error("unpack-charx requires an input path");
50
+ const parsedInput = parse(inputPath);
51
+ unpackCharX(inputPath, outputPath ?? join(parsedInput.dir, parsedInput.name));
52
+ return;
53
+ }
54
+ case "unpack-risum": {
55
+ const [inputPath, outputPath] = args;
56
+ if (!inputPath) throw new Error("unpack-risum requires an input path");
57
+ const parsedInput = parse(inputPath);
58
+ unpackRisuM(inputPath, outputPath ?? join(parsedInput.dir, parsedInput.name));
59
+ return;
60
+ }
61
+ default:
62
+ printUsage();
63
+ process.exitCode = command && !COMMANDS.includes(command) ? 1 : 0;
64
+ }
65
+ } catch (error) {
66
+ console.error(error instanceof Error ? error.message : error);
67
+ process.exitCode = 1;
68
+ }
69
+ }
70
+ await main();
71
+ //#endregion
72
+
73
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { join, parse as parsePath } from \"node:path\";\n\nimport { buildCharX } from \"./build-charx.js\";\nimport { bundleLua } from \"./bundle.js\";\nimport { parseModuleBlock } from \"./inspect-risusave.js\";\nimport { unpackCharX } from \"./unpack-charx.js\";\nimport { unpackRisuM } from \"./unpack-risum.js\";\n\nconst COMMANDS = [\n \"build-charx\",\n \"bundle-lua\",\n \"inspect-risusave\",\n \"unpack-charx\",\n \"unpack-risum\",\n] as const;\n\nfunction printUsage(): void {\n console.error(`Usage: risupack <command> [arguments]\n\nCommands:\n build-charx <manifest.json> [output.charx]\n bundle-lua <entry.lua> <output.lua>\n inspect-risusave <database.bin> [namespace-or-name]\n unpack-charx <input.charx> [output-directory]\n unpack-risum <input.risum> [output-directory]`);\n}\n\nasync function main(): Promise<void> {\n const [command, ...args] = process.argv.slice(2);\n\n try {\n switch (command) {\n case \"build-charx\": {\n const [manifestPath, outputPath] = args;\n if (!manifestPath) {\n throw new Error(\"build-charx requires a manifest path\");\n }\n buildCharX(manifestPath, outputPath);\n return;\n }\n case \"bundle-lua\": {\n const [entryPath, outputPath] = args;\n if (!entryPath || !outputPath) {\n throw new Error(\"bundle-lua requires entry and output paths\");\n }\n bundleLua(entryPath, outputPath);\n return;\n }\n case \"inspect-risusave\": {\n const [databasePath, query] = args;\n if (!databasePath) {\n throw new Error(\"inspect-risusave requires a database path\");\n }\n const modules = parseModuleBlock(readFileSync(databasePath));\n const selected = query\n ? modules.filter(\n (module) =>\n module.namespace === query || module.name === query || module.id === query,\n )\n : modules;\n process.stdout.write(`${JSON.stringify(selected, null, 2)}\\n`);\n return;\n }\n case \"unpack-charx\": {\n const [inputPath, outputPath] = args;\n if (!inputPath) {\n throw new Error(\"unpack-charx requires an input path\");\n }\n const parsedInput = parsePath(inputPath);\n unpackCharX(inputPath, outputPath ?? join(parsedInput.dir, parsedInput.name));\n return;\n }\n case \"unpack-risum\": {\n const [inputPath, outputPath] = args;\n if (!inputPath) {\n throw new Error(\"unpack-risum requires an input path\");\n }\n const parsedInput = parsePath(inputPath);\n unpackRisuM(inputPath, outputPath ?? join(parsedInput.dir, parsedInput.name));\n return;\n }\n default: {\n printUsage();\n process.exitCode =\n command && !COMMANDS.includes(command as (typeof COMMANDS)[number]) ? 1 : 0;\n }\n }\n } catch (error) {\n console.error(error instanceof Error ? error.message : error);\n process.exitCode = 1;\n }\n}\n\nawait main();\n"],"mappings":";;;;;AASA,IAAM,WAAW;CACf;CACA;CACA;CACA;CACA;AACF;AAEA,SAAS,aAAmB;CAC1B,QAAQ,MAAM;;;;;;;gDAOgC;AAChD;AAEA,eAAe,OAAsB;CACnC,MAAM,CAAC,SAAS,GAAG,QAAQ,QAAQ,KAAK,MAAM,CAAC;CAE/C,IAAI;EACF,QAAQ,SAAR;GACE,KAAK,eAAe;IAClB,MAAM,CAAC,cAAc,cAAc;IACnC,IAAI,CAAC,cACH,MAAM,IAAI,MAAM,sCAAsC;IAExD,WAAW,cAAc,UAAU;IACnC;GACF;GACA,KAAK,cAAc;IACjB,MAAM,CAAC,WAAW,cAAc;IAChC,IAAI,CAAC,aAAa,CAAC,YACjB,MAAM,IAAI,MAAM,4CAA4C;IAE9D,UAAU,WAAW,UAAU;IAC/B;GACF;GACA,KAAK,oBAAoB;IACvB,MAAM,CAAC,cAAc,SAAS;IAC9B,IAAI,CAAC,cACH,MAAM,IAAI,MAAM,2CAA2C;IAE7D,MAAM,UAAU,iBAAiB,aAAa,YAAY,CAAC;IAC3D,MAAM,WAAW,QACb,QAAQ,QACL,WACC,OAAO,cAAc,SAAS,OAAO,SAAS,SAAS,OAAO,OAAO,KACzE,IACA;IACJ,QAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,EAAE,GAAG;IAC7D;GACF;GACA,KAAK,gBAAgB;IACnB,MAAM,CAAC,WAAW,cAAc;IAChC,IAAI,CAAC,WACH,MAAM,IAAI,MAAM,qCAAqC;IAEvD,MAAM,cAAc,MAAU,SAAS;IACvC,YAAY,WAAW,cAAc,KAAK,YAAY,KAAK,YAAY,IAAI,CAAC;IAC5E;GACF;GACA,KAAK,gBAAgB;IACnB,MAAM,CAAC,WAAW,cAAc;IAChC,IAAI,CAAC,WACH,MAAM,IAAI,MAAM,qCAAqC;IAEvD,MAAM,cAAc,MAAU,SAAS;IACvC,YAAY,WAAW,cAAc,KAAK,YAAY,KAAK,YAAY,IAAI,CAAC;IAC5E;GACF;GACA;IACE,WAAW;IACX,QAAQ,WACN,WAAW,CAAC,SAAS,SAAS,OAAoC,IAAI,IAAI;EAEhF;CACF,SAAS,OAAO;EACd,QAAQ,MAAM,iBAAiB,QAAQ,MAAM,UAAU,KAAK;EAC5D,QAAQ,WAAW;CACrB;AACF;AAEA,MAAM,KAAK"}
@@ -0,0 +1,5 @@
1
+ export { buildCharX } from "./build-charx.js";
2
+ export { bundleLua } from "./bundle.js";
3
+ export { parseModuleBlock } from "./inspect-risusave.js";
4
+ export { createExpandedModuleSources, decodeModule, parseZIP, unpackCharX, } from "./unpack-charx.js";
5
+ export { unpackRisuM } from "./unpack-risum.js";
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import { a as unpackCharX, c as bundleLua, i as parseZIP, n as createExpandedModuleSources, o as parseModuleBlock, r as decodeModule, s as buildCharX, t as unpackRisuM } from "./unpack-risum-8Iw-UEO2.js";
2
+ export { buildCharX, bundleLua, createExpandedModuleSources, decodeModule, parseModuleBlock, parseZIP, unpackCharX, unpackRisuM };
@@ -0,0 +1,8 @@
1
+ interface ModuleRecord {
2
+ id?: unknown;
3
+ name?: unknown;
4
+ namespace?: unknown;
5
+ [key: string]: unknown;
6
+ }
7
+ declare function parseModuleBlock(database: Buffer): ModuleRecord[];
8
+ export { parseModuleBlock };
@@ -0,0 +1,5 @@
1
+ declare function decodeModule(data: Buffer, map: Buffer): Record<string, any>;
2
+ declare function createExpandedModuleSources(card: Record<string, any>, decodedModule: Record<string, any>): Map<string, Buffer>;
3
+ declare function parseZIP(archive: Buffer): any[];
4
+ declare function unpackCharX(inputPath: string, outputPath: string): string;
5
+ export { createExpandedModuleSources, decodeModule, parseZIP, unpackCharX };