@hmcs/sdk 1.0.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 +30 -0
- package/dist/app.cjs +63 -0
- package/dist/app.js +63 -0
- package/dist/assets.cjs +52 -0
- package/dist/assets.js +52 -0
- package/dist/audio.cjs +159 -0
- package/dist/audio.js +159 -0
- package/dist/commands.cjs +298 -0
- package/dist/commands.d.ts +852 -0
- package/dist/commands.js +296 -0
- package/dist/coordinates.cjs +69 -0
- package/dist/coordinates.js +69 -0
- package/dist/displays.cjs +38 -0
- package/dist/displays.js +38 -0
- package/dist/effects.cjs +50 -0
- package/dist/effects.js +50 -0
- package/dist/entities.cjs +249 -0
- package/dist/entities.js +249 -0
- package/dist/host.cjs +297 -0
- package/dist/host.js +294 -0
- package/dist/index.cjs +98 -0
- package/dist/index.d.ts +2612 -0
- package/dist/index.js +17 -0
- package/dist/mods.cjs +207 -0
- package/dist/mods.js +207 -0
- package/dist/preferences.cjs +90 -0
- package/dist/preferences.js +90 -0
- package/dist/settings.cjs +46 -0
- package/dist/settings.js +46 -0
- package/dist/shadowPanel.cjs +46 -0
- package/dist/shadowPanel.js +46 -0
- package/dist/signals.cjs +158 -0
- package/dist/signals.js +158 -0
- package/dist/speech.cjs +48 -0
- package/dist/speech.js +48 -0
- package/dist/utils.cjs +13 -0
- package/dist/utils.js +11 -0
- package/dist/vrm.cjs +469 -0
- package/dist/vrm.js +466 -0
- package/dist/webviews.cjs +310 -0
- package/dist/webviews.js +302 -0
- package/package.json +61 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var node_fs = require('node:fs');
|
|
4
|
+
var zod = require('zod');
|
|
5
|
+
var vrm = require('./vrm.cjs');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Command script utilities for Desktop Homunculus mods.
|
|
9
|
+
*
|
|
10
|
+
* This module provides helpers for parsing stdin input and writing structured
|
|
11
|
+
* output in mod command scripts (`bin/` scripts invoked via the HTTP command
|
|
12
|
+
* execution API).
|
|
13
|
+
*
|
|
14
|
+
* **Input:** {@link input.parse} / {@link input.parseMenu} / {@link input.read}
|
|
15
|
+
* **Output:** {@link output.succeed} / {@link output.fail} / {@link output.write} / {@link output.writeError}
|
|
16
|
+
*
|
|
17
|
+
* @remarks
|
|
18
|
+
* This module uses Node.js APIs (`process.stdin`, `fs.writeFileSync`) and is
|
|
19
|
+
* not browser-compatible. Import from `@hmcs/sdk/commands` — it is intentionally
|
|
20
|
+
* not re-exported from the main `@hmcs/sdk` entry point.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import { z } from "zod";
|
|
25
|
+
* import { input, output, StdinParseError } from "@hmcs/sdk/commands";
|
|
26
|
+
*
|
|
27
|
+
* const schema = z.object({ name: z.string() });
|
|
28
|
+
*
|
|
29
|
+
* try {
|
|
30
|
+
* const data = await input.parse(schema);
|
|
31
|
+
* output.succeed({ greeting: `Hello, ${data.name}!` });
|
|
32
|
+
* } catch (err) {
|
|
33
|
+
* output.fail("GREET_FAILED", (err as Error).message);
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @packageDocumentation
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Safely serialize a value to JSON. Returns a fallback error JSON string
|
|
41
|
+
* if serialization fails (e.g., circular references or BigInt values).
|
|
42
|
+
*/
|
|
43
|
+
function safeStringify(data) {
|
|
44
|
+
try {
|
|
45
|
+
return JSON.stringify(data);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return '{"code":"SERIALIZE_ERROR","message":"Failed to serialize output"}';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Error thrown by {@link input.parse} when stdin is empty, contains invalid JSON,
|
|
53
|
+
* or fails Zod schema validation.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* import { input, StdinParseError } from "@hmcs/sdk/commands";
|
|
58
|
+
*
|
|
59
|
+
* try {
|
|
60
|
+
* const data = await input.parse(schema);
|
|
61
|
+
* } catch (err) {
|
|
62
|
+
* if (err instanceof StdinParseError) {
|
|
63
|
+
* console.error(JSON.stringify({ code: err.code, message: err.message }));
|
|
64
|
+
* process.exit(1);
|
|
65
|
+
* }
|
|
66
|
+
* throw err;
|
|
67
|
+
* }
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
class StdinParseError extends Error {
|
|
71
|
+
code;
|
|
72
|
+
details;
|
|
73
|
+
name = "StdinParseError";
|
|
74
|
+
constructor(
|
|
75
|
+
/** Structured error code identifying the failure stage. */
|
|
76
|
+
code, message,
|
|
77
|
+
/** For `VALIDATION_ERROR`, contains the `ZodError` instance. */
|
|
78
|
+
details) {
|
|
79
|
+
super(message);
|
|
80
|
+
this.code = code;
|
|
81
|
+
this.details = details;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Input helpers for reading and parsing stdin in bin command scripts.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* import { z } from "zod";
|
|
90
|
+
* import { input } from "@hmcs/sdk/commands";
|
|
91
|
+
*
|
|
92
|
+
* const data = await input.parse(
|
|
93
|
+
* z.object({ name: z.string(), count: z.number() })
|
|
94
|
+
* );
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
exports.input = void 0;
|
|
98
|
+
(function (input) {
|
|
99
|
+
/**
|
|
100
|
+
* Read all of stdin as a UTF-8 string.
|
|
101
|
+
*
|
|
102
|
+
* Consumes the entire `process.stdin` stream via async iteration and returns
|
|
103
|
+
* the concatenated result. Useful when you need the raw string without JSON
|
|
104
|
+
* parsing or validation.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* import { input } from "@hmcs/sdk/commands";
|
|
109
|
+
*
|
|
110
|
+
* const raw = await input.read();
|
|
111
|
+
* console.log("Received:", raw);
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
async function read() {
|
|
115
|
+
const chunks = [];
|
|
116
|
+
for await (const chunk of process.stdin) {
|
|
117
|
+
chunks.push(chunk);
|
|
118
|
+
}
|
|
119
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
120
|
+
}
|
|
121
|
+
input.read = read;
|
|
122
|
+
/**
|
|
123
|
+
* Read JSON from stdin and validate it against a Zod schema.
|
|
124
|
+
*
|
|
125
|
+
* Performs three steps:
|
|
126
|
+
* 1. Reads all of stdin via {@link input.read}
|
|
127
|
+
* 2. Parses the raw string as JSON
|
|
128
|
+
* 3. Validates the parsed object against the provided Zod schema
|
|
129
|
+
*
|
|
130
|
+
* @typeParam T - The output type inferred from the Zod schema
|
|
131
|
+
* @param schema - A Zod schema to validate the parsed JSON against
|
|
132
|
+
* @returns The validated and typed input object
|
|
133
|
+
* @throws {StdinParseError} With `code: "EMPTY_STDIN"` if stdin is empty or whitespace-only
|
|
134
|
+
* @throws {StdinParseError} With `code: "INVALID_JSON"` if stdin is not valid JSON
|
|
135
|
+
* @throws {StdinParseError} With `code: "VALIDATION_ERROR"` if the JSON does not match the schema
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```typescript
|
|
139
|
+
* import { z } from "zod";
|
|
140
|
+
* import { input } from "@hmcs/sdk/commands";
|
|
141
|
+
*
|
|
142
|
+
* const data = await input.parse(
|
|
143
|
+
* z.object({
|
|
144
|
+
* entity: z.number(),
|
|
145
|
+
* text: z.union([z.string(), z.array(z.string())]),
|
|
146
|
+
* speaker: z.number().default(0),
|
|
147
|
+
* })
|
|
148
|
+
* );
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
async function parse(schema) {
|
|
152
|
+
const raw = await read();
|
|
153
|
+
if (raw.trim().length === 0) {
|
|
154
|
+
throw new StdinParseError("EMPTY_STDIN", "No input received on stdin");
|
|
155
|
+
}
|
|
156
|
+
let json;
|
|
157
|
+
try {
|
|
158
|
+
json = JSON.parse(raw);
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
throw new StdinParseError("INVALID_JSON", `Invalid JSON: ${raw.slice(0, 200)}`);
|
|
162
|
+
}
|
|
163
|
+
const result = schema.safeParse(json);
|
|
164
|
+
if (!result.success) {
|
|
165
|
+
throw new StdinParseError("VALIDATION_ERROR", `Validation failed: ${result.error.message}`, result.error);
|
|
166
|
+
}
|
|
167
|
+
return result.data;
|
|
168
|
+
}
|
|
169
|
+
input.parse = parse;
|
|
170
|
+
/**
|
|
171
|
+
* Parse menu command stdin and return the linked VRM instance.
|
|
172
|
+
*
|
|
173
|
+
* Menu commands receive `{ "linkedVrm": <entityId> }` on stdin from the
|
|
174
|
+
* menu UI. This helper validates the input and returns a ready-to-use
|
|
175
|
+
* {@link Vrm} instance.
|
|
176
|
+
*
|
|
177
|
+
* @returns A {@link Vrm} instance for the linked entity
|
|
178
|
+
* @throws {StdinParseError} With `code: "EMPTY_STDIN"` if stdin is empty
|
|
179
|
+
* @throws {StdinParseError} With `code: "INVALID_JSON"` if stdin is not valid JSON
|
|
180
|
+
* @throws {StdinParseError} With `code: "VALIDATION_ERROR"` if `linkedVrm` is missing or not a number
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* import { input } from "@hmcs/sdk/commands";
|
|
185
|
+
*
|
|
186
|
+
* const vrm = await input.parseMenu();
|
|
187
|
+
* await vrm.setExpressions({ happy: 1.0 });
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
async function parseMenu() {
|
|
191
|
+
const parsed = await parse(zod.z.object({ linkedVrm: zod.z.number() }));
|
|
192
|
+
return new vrm.Vrm(parsed.linkedVrm);
|
|
193
|
+
}
|
|
194
|
+
input.parseMenu = parseMenu;
|
|
195
|
+
})(exports.input || (exports.input = {}));
|
|
196
|
+
/**
|
|
197
|
+
* Output helpers for writing structured results and errors in bin command scripts.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* import { output } from "@hmcs/sdk/commands";
|
|
202
|
+
*
|
|
203
|
+
* output.succeed({ count: 42, status: "done" });
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
exports.output = void 0;
|
|
207
|
+
(function (output) {
|
|
208
|
+
/**
|
|
209
|
+
* Write a JSON-serialized result to stdout (fd 1).
|
|
210
|
+
*
|
|
211
|
+
* Serializes `data` with `JSON.stringify` and writes it followed by a newline
|
|
212
|
+
* to file descriptor 1 using synchronous I/O. This ensures the output is
|
|
213
|
+
* flushed before the process exits.
|
|
214
|
+
*
|
|
215
|
+
* @param data - The value to serialize as JSON and write to stdout
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```typescript
|
|
219
|
+
* import { output } from "@hmcs/sdk/commands";
|
|
220
|
+
*
|
|
221
|
+
* output.write({ count: 42, status: "done" });
|
|
222
|
+
* // stdout receives: {"count":42,"status":"done"}\n
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
function write(data) {
|
|
226
|
+
node_fs.writeFileSync(1, safeStringify(data) + "\n");
|
|
227
|
+
}
|
|
228
|
+
output.write = write;
|
|
229
|
+
/**
|
|
230
|
+
* Write a structured JSON error to stderr (fd 2).
|
|
231
|
+
*
|
|
232
|
+
* Serializes an object with `code` and `message` fields and writes it followed
|
|
233
|
+
* by a newline to file descriptor 2 using synchronous I/O.
|
|
234
|
+
*
|
|
235
|
+
* @param code - A machine-readable error code (e.g., `"NOT_FOUND"`, `"TIMEOUT"`)
|
|
236
|
+
* @param message - A human-readable error description
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* ```typescript
|
|
240
|
+
* import { output } from "@hmcs/sdk/commands";
|
|
241
|
+
*
|
|
242
|
+
* output.writeError("NOT_FOUND", "Entity 42 does not exist");
|
|
243
|
+
* // stderr receives: {"code":"NOT_FOUND","message":"Entity 42 does not exist"}\n
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
function writeError(code, message) {
|
|
247
|
+
node_fs.writeFileSync(2, JSON.stringify({ code, message }) + "\n");
|
|
248
|
+
}
|
|
249
|
+
output.writeError = writeError;
|
|
250
|
+
/**
|
|
251
|
+
* Write a JSON result to stdout and exit the process with code 0.
|
|
252
|
+
*
|
|
253
|
+
* This is a convenience wrapper that calls {@link output.write} followed by
|
|
254
|
+
* `process.exit(0)`. Use this as the final call in a successful bin command.
|
|
255
|
+
*
|
|
256
|
+
* @param data - The value to serialize as JSON and write to stdout
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* ```typescript
|
|
260
|
+
* import { input, output } from "@hmcs/sdk/commands";
|
|
261
|
+
*
|
|
262
|
+
* const data = await input.parse(schema);
|
|
263
|
+
* const result = await doWork(data);
|
|
264
|
+
* output.succeed({ processed: result.count });
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
function succeed(data) {
|
|
268
|
+
write(data);
|
|
269
|
+
process.exit(0);
|
|
270
|
+
}
|
|
271
|
+
output.succeed = succeed;
|
|
272
|
+
/**
|
|
273
|
+
* Write a structured error to stderr and exit the process.
|
|
274
|
+
*
|
|
275
|
+
* This is a convenience wrapper that calls {@link output.writeError} followed by
|
|
276
|
+
* `process.exit(exitCode)`. Use this when a bin command encounters a fatal error.
|
|
277
|
+
*
|
|
278
|
+
* @param code - A machine-readable error code (e.g., `"NOT_FOUND"`, `"TIMEOUT"`)
|
|
279
|
+
* @param message - A human-readable error description
|
|
280
|
+
* @param exitCode - Process exit code (default: `1`)
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```typescript
|
|
284
|
+
* import { output } from "@hmcs/sdk/commands";
|
|
285
|
+
*
|
|
286
|
+
* if (!response.ok) {
|
|
287
|
+
* output.fail("API_ERROR", `Server returned ${response.status}`);
|
|
288
|
+
* }
|
|
289
|
+
* ```
|
|
290
|
+
*/
|
|
291
|
+
function fail(code, message, exitCode = 1) {
|
|
292
|
+
writeError(code, message);
|
|
293
|
+
process.exit(exitCode);
|
|
294
|
+
}
|
|
295
|
+
output.fail = fail;
|
|
296
|
+
})(exports.output || (exports.output = {}));
|
|
297
|
+
|
|
298
|
+
exports.StdinParseError = StdinParseError;
|