@hncode/hncode-sdk 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/index.d.ts ADDED
@@ -0,0 +1,436 @@
1
+ // Type definitions for hncode plugins.
2
+ //
3
+ // A plugin is an ESM module exported as `{ name, version, install }`. `install`
4
+ // receives the host `api` object — that object is what this file describes, so an
5
+ // editor can complete `api.` and type-check the handlers.
6
+ //
7
+ // Usage:
8
+ // /** @type {import('@hncode/hncode-sdk').HncodePlugin} *​/
9
+ // export default { name: 'x', version: '1.0.0', install(api) { ... } };
10
+ //
11
+ // or, in TypeScript:
12
+ // import type { HncodePlugin } from '@hncode/hncode-sdk';
13
+ // const plugin: HncodePlugin = { ... };
14
+
15
+ import type { PatchTarget } from './targets.js';
16
+
17
+ export type { PatchTarget };
18
+
19
+ // ---------------------------------------------------------------------------
20
+ // Tools
21
+ // ---------------------------------------------------------------------------
22
+
23
+ /** JSON-Schema-ish parameter description (OpenAI `function.parameters` shape). */
24
+ export interface ToolParameters {
25
+ type: 'object';
26
+ properties?: Record<string, unknown>;
27
+ required?: string[];
28
+ [key: string]: unknown;
29
+ }
30
+
31
+ /** A tool the model can call. Same shape as hncode's built-in tool specs. */
32
+ export interface ToolSpec {
33
+ /** Unique tool name; `registerTool` throws on a duplicate. */
34
+ name: string;
35
+ description?: string;
36
+ parameters?: ToolParameters;
37
+ /**
38
+ * Run the tool. Return a string, or `{ text, media? }` for multimodal output.
39
+ * Throwing is fine — the agent converts it into an error result for the model.
40
+ */
41
+ execute(args: Record<string, unknown>, ctx: AgentContext): unknown | Promise<unknown>;
42
+ [key: string]: unknown;
43
+ }
44
+
45
+ /** The context handed to a tool's `execute`. */
46
+ export interface AgentContext {
47
+ /** Working directory of the session. */
48
+ cwd?: string;
49
+ workspace?: string;
50
+ /** Abort signal — long-running tools should honour it. */
51
+ signal?: AbortSignal;
52
+ /** Mutable map of background tasks (shared across a session). */
53
+ tasks?: Record<string, unknown>;
54
+ /** Live todo list (TodoList tool). */
55
+ todoState?: Array<{ title: string; status?: string }>;
56
+ /** Whether tools may touch paths outside the workspace. */
57
+ allowExternal?: boolean;
58
+ /** The most recent tool result (set by the agent after each call). */
59
+ lastResult?: unknown;
60
+ /** Call with a chunk to stream live output to the matching "Using …" row. */
61
+ onOutput?: (chunk: string) => void;
62
+ [key: string]: unknown;
63
+ }
64
+
65
+ // ---------------------------------------------------------------------------
66
+ // Commands
67
+ // ---------------------------------------------------------------------------
68
+
69
+ /** Context passed to a command's `run`. */
70
+ export interface CommandContext {
71
+ /** The live TUI state (prefer the documented fields; the rest is internal). */
72
+ state: Record<string, any>;
73
+ /** The host object. */
74
+ h: Record<string, any>;
75
+ /** Resolved config. */
76
+ cfg: Record<string, any>;
77
+ /** The current session. */
78
+ session: Record<string, any>;
79
+ /** Print an info line (transient banner). */
80
+ app: (message: string) => void;
81
+ /** Print an error line (transient banner). */
82
+ appErr: (message: string) => void;
83
+ [key: string]: unknown;
84
+ }
85
+
86
+ /** A slash command. */
87
+ export interface CommandSpec {
88
+ /** Without the leading slash; `registerCommand` throws on a duplicate. */
89
+ name: string;
90
+ description?: string;
91
+ /** Shown in completion, e.g. '[on|off]'. */
92
+ argumentHint?: string;
93
+ /** Sorting weight in the `/` menu (higher = earlier). */
94
+ priority?: number;
95
+ aliases?: string[];
96
+ run: (arg: string, ctx: CommandContext) => unknown | Promise<unknown>;
97
+ }
98
+
99
+ // ---------------------------------------------------------------------------
100
+ // Patching
101
+ // ---------------------------------------------------------------------------
102
+
103
+ /** Handler for a symbol patch: any combination of before/after/around. */
104
+ export interface PatchHandler {
105
+ /** Runs before the call. Return an array to REPLACE the argument list. */
106
+ before?: (this: any, ...args: any[]) => any[] | void;
107
+ /** Runs after the call. Return a non-undefined value to REPLACE the result. */
108
+ after?: (this: any, result: any, args: any[]) => any;
109
+ /** Full control: call `original`, return the result. */
110
+ around?: (this: any, original: (...a: any[]) => any, args: any[], thisArg: any) => any;
111
+ }
112
+
113
+ /** The legacy chain signature used by the nine abstract seams. */
114
+ export type SeamHandler = (ctx: any, next: (ctx: any) => any) => any;
115
+
116
+ // ---------------------------------------------------------------------------
117
+ // Skills
118
+ // ---------------------------------------------------------------------------
119
+
120
+ export interface SkillResult {
121
+ ok: boolean;
122
+ name?: string;
123
+ path?: string;
124
+ replaced?: boolean;
125
+ error?: string;
126
+ }
127
+
128
+ export interface SkillInfo {
129
+ name: string;
130
+ description?: string;
131
+ [key: string]: unknown;
132
+ }
133
+
134
+ // ---------------------------------------------------------------------------
135
+ // UI option shapes
136
+ // ---------------------------------------------------------------------------
137
+
138
+ export interface PickerItem {
139
+ label: string;
140
+ sub?: string;
141
+ /** Marks the currently-selected row with a "current" tag. */
142
+ current?: boolean;
143
+ [key: string]: unknown;
144
+ }
145
+
146
+ export interface PickerOptions {
147
+ title?: string;
148
+ items: PickerItem[];
149
+ hint?: string;
150
+ searchable?: boolean;
151
+ /** Keep the composer text instead of clearing it when the picker opens. */
152
+ keepInput?: boolean;
153
+ onPick?: (item: PickerItem) => boolean | void;
154
+ onCancel?: () => void;
155
+ [key: string]: unknown;
156
+ }
157
+
158
+ export interface FormField {
159
+ key: string;
160
+ label: string;
161
+ value?: string;
162
+ kind?: string;
163
+ [key: string]: unknown;
164
+ }
165
+
166
+ export interface FormOptions {
167
+ title?: string;
168
+ fields: FormField[];
169
+ hint?: string;
170
+ onSubmit?: (values: Record<string, string>, type: string) => void;
171
+ onCancel?: () => void;
172
+ [key: string]: unknown;
173
+ }
174
+
175
+ /** A subagent that is running RIGHT NOW, as reported by `api.subagents()`. */
176
+ export interface RunningSubagent {
177
+ /** The agent id — the handle `Agent` prints and `AgentSwarm` reports. */
178
+ id: string;
179
+ /** The run id, valid only while the run is live. */
180
+ runId: string;
181
+ /** The background task id, when the run was detached. */
182
+ taskId: string;
183
+ /** 'coder' | 'explore' | 'plan' | 'researcher'. */
184
+ type: string;
185
+ description: string;
186
+ startedAt: number;
187
+ }
188
+
189
+ /** The answer every subagent-control call gives. */
190
+ export interface SubagentResult {
191
+ ok: boolean;
192
+ message: string;
193
+ }
194
+
195
+ export interface EditorOptions {
196
+ title?: string;
197
+ text?: string;
198
+ caretRow?: number;
199
+ caretCol?: number;
200
+ hint?: string;
201
+ onSave?: (value: string) => void;
202
+ [key: string]: unknown;
203
+ }
204
+
205
+ /**
206
+ * The logger handed to a plugin as `api.log`. Callable like `console.log`, and also
207
+ * carrying `log` / `info` / `warn` / `error` — both shapes work.
208
+ */
209
+ export interface PluginLogger {
210
+ (...args: unknown[]): void;
211
+ log: (...args: unknown[]) => void;
212
+ info: (...args: unknown[]) => void;
213
+ warn: (...args: unknown[]) => void;
214
+ error: (...args: unknown[]) => void;
215
+ }
216
+
217
+ // ---------------------------------------------------------------------------
218
+ // The API
219
+ // ---------------------------------------------------------------------------
220
+
221
+ /** Every method and property the host injects into `install(api)`. */
222
+ export interface HncodePluginApi {
223
+ /** Register a tool. Throws on a duplicate name. Returns an unregister fn. */
224
+ registerTool(spec: ToolSpec): () => void;
225
+ /** Register a slash command. Throws on a duplicate name. Returns an unregister fn. */
226
+ registerCommand(cmd: CommandSpec): () => void;
227
+ /** Register a lifecycle hook. Returns an unregister fn. */
228
+ registerHook(name: string, fn: (...args: any[]) => any): () => void;
229
+ /** Merge default config values (applied before user overrides). Returns an
230
+ * unregister fn that drops the keys this call added. */
231
+ registerConfig(defaults: Record<string, unknown>): () => void;
232
+
233
+ /** The lazily-injected agent context, or undefined before the first turn. */
234
+ readonly ctx: AgentContext | undefined;
235
+
236
+ // ---- services ----
237
+ /**
238
+ * Publish a value other plugins can `inject` / `get`. Declare the same names in
239
+ * the module's `provides` export — the loader reads that to work out the load
240
+ * order, since ordering must be known before any install runs. Throws when the
241
+ * name is already provided. Returns an unregister fn.
242
+ */
243
+ provide(name: string, value: unknown): () => void;
244
+ /** A provided service, or undefined. */
245
+ get(name: string): any;
246
+ /** Whether a service is available right now. */
247
+ has(name: string): boolean;
248
+ /** Like get(), but throws when the service is missing. */
249
+ require(name: string): any;
250
+ /** Names of every currently-provided service. */
251
+ readonly serviceNames: string[];
252
+
253
+ // ---- teardown ----
254
+ /**
255
+ * Register a cleanup function, run by unloadPlugins() (and on reload) before the
256
+ * registrations are undone. For resources the register* calls do not know about:
257
+ * timers, child processes, watchers, files. Returns an unregister fn.
258
+ */
259
+ onDispose(fn: () => void | Promise<void>): () => void;
260
+
261
+ /** Publish a skill from an in-memory SKILL.md string. */
262
+
263
+ /** Publish a skill from an in-memory SKILL.md string. */
264
+ addSkill(content: string, name?: string): SkillResult;
265
+ /** Installed skills. */
266
+ readonly skills: SkillInfo[];
267
+ /** Delete an installed skill by name. */
268
+ removeSkill(name: string): SkillResult;
269
+
270
+ // ---- runtime control ----
271
+ /** Queue a prompt as if the user typed it. `opts.skillBody` / `opts.bubbleText` supported. */
272
+ sendPrompt(text: string, opts?: { skillBody?: string; bubbleText?: string }): unknown;
273
+ /** Append a message to the transcript. Returns null in a headless host. */
274
+ addMessage(role: string, text: string): unknown;
275
+ /** The conversation messages. */
276
+ getMessages(): unknown[];
277
+ /** Start a fresh session. */
278
+ clearSession(): void;
279
+ /** Persist a session object. */
280
+ saveSession(session: unknown): void;
281
+ /** Quit the host. */
282
+ quit(): void;
283
+
284
+ // ---- UI ----
285
+ /** Show a transient notice. */
286
+ notice(text: string, kind?: 'info' | 'warn' | 'error'): void;
287
+ /** Open the scrollable info panel. */
288
+ openPanel(content: string | string[]): void;
289
+ /** Open the modal text editor. */
290
+ openEditor(opts: EditorOptions): void;
291
+ /** Open a searchable picker. */
292
+ openPicker(opts: PickerOptions): void;
293
+ /** Open a form. */
294
+ openForm(opts: FormOptions): void;
295
+ /** Open the background-tasks panel. */
296
+ openTasksPanel(): void;
297
+ /** Open the plugin/skill registry browser: 'plugins' | 'skills'. */
298
+ openRegistryBrowser(kind: 'plugins' | 'skills'): void;
299
+
300
+ // ---- config ----
301
+ getConfig(key: string): unknown;
302
+ setConfig(key: string, val: unknown): void;
303
+ /** Persist a config value to disk. Returns true on success. */
304
+ persistConfig(key: string, val: unknown): boolean;
305
+
306
+ // ---- filesystem (encoding-aware, error-tolerant) ----
307
+ readFile(file: string, enc?: BufferEncoding): string | null;
308
+ writeFile(file: string, data: string, enc?: BufferEncoding): boolean;
309
+ readJSON<T = unknown>(file: string, fallback?: T): T | null;
310
+ writeJSON(file: string, obj: unknown): boolean;
311
+
312
+ // ---- keybinds & widgets ----
313
+ /** Claim a global shortcut using the TUI's token format ('c-k', 'f9'). */
314
+ registerKeybind(key: string, fn: () => void): () => void;
315
+ /** Render extra status-bar text. */
316
+ registerTuiWidget(fn: () => string): () => void;
317
+ /**
318
+ * Whether a shortcut is already claimed — by the user's keybindings file, by another
319
+ * plugin, or by a built-in. `registerKeybind` overwrites silently, so check first if you
320
+ * care. Accepts any spelling `normalizeKey` understands ('ctrl+t' as well as 'c-t').
321
+ */
322
+ isKeyBound(key: string): boolean;
323
+ /** Every currently-claimed shortcut token. */
324
+ readonly boundKeys: string[];
325
+
326
+ // ---- UI: the file tree ----
327
+ /**
328
+ * Open the workspace file browser. `filter` narrows the tree the way `/files <filter>`
329
+ * does. Returns whether it actually opened — false for an empty workspace or a headless
330
+ * host, so a plugin can tell instead of waiting on a panel that never appeared.
331
+ */
332
+ openFileTree(filter?: string): boolean;
333
+ /** Close the file-tree browser if it is open. */
334
+ closeFileTree(): void;
335
+
336
+ // ---- theme ----
337
+ /** Every theme name this build knows. A build-time fact, no host needed. */
338
+ readonly themeNames: string[];
339
+ /** The theme in force, or null when no host has one. */
340
+ getTheme(): string | null;
341
+ /**
342
+ * Switch the colour theme. Returns false for an unknown name — the check runs before the
343
+ * host is called, so a bad name cannot half-change the screen.
344
+ */
345
+ setTheme(name: string): boolean;
346
+
347
+ // ---- subagents ----
348
+ /** The subagents running RIGHT NOW. A finished one is not listed. */
349
+ subagents(): RunningSubagent[];
350
+ /** Send a message to a running subagent, addressed by agent id, run id or task id. */
351
+ messageSubagent(ref: string, text: string): SubagentResult;
352
+ /** Stop one running subagent, or every one when `ref` is omitted. */
353
+ interruptSubagent(ref?: string): SubagentResult;
354
+ /** Interrupt a subagent AND drop it from the running list at once. */
355
+ closeSubagent(ref: string): SubagentResult;
356
+
357
+ // ---- patching ----
358
+ /**
359
+ * Wrap an exported function or class method in hncode's own src/, or register
360
+ * a legacy seam. `target` is a `PatchTarget` ("file.js#symbol") or a seam name.
361
+ * Returns an unregister fn.
362
+ */
363
+ patch(target: PatchTarget | string, handler: PatchHandler | SeamHandler): () => void;
364
+ /** Every currently-registered patch target. */
365
+ readonly patchSeams: string[];
366
+
367
+ // ---- introspection ----
368
+ // What THIS load has registered so far. Useful for a plugin that wants to avoid
369
+ // colliding with a name, or that reports what it found. These were on the host all
370
+ // along and missing from these types, so `api.tools` did not complete.
371
+ /** Every registered tool spec, including other plugins'. */
372
+ readonly tools: ToolSpec[];
373
+ /** Every registered slash command. */
374
+ readonly commands: CommandSpec[];
375
+ /** Registered hooks, keyed by hook name. */
376
+ readonly hooks: Record<string, Array<(...args: any[]) => any>>;
377
+ /** Plugin-supplied config defaults (before user overrides). */
378
+ readonly config: Record<string, unknown>;
379
+ /** The plugins loaded this session, in install order. */
380
+ readonly plugins: Array<{ name: string; version: string }>;
381
+
382
+ /**
383
+ * A console-like logger. Mirrors to the chat AND to the terminal.
384
+ *
385
+ * CALLABLE (`api.log('x')`) as well as carrying the four methods
386
+ * (`api.log.warn('x')`), exactly like `console`. There are no separate `api.info`
387
+ * / `api.warn` / `api.error` members.
388
+ */
389
+ log: PluginLogger;
390
+ }
391
+
392
+ /** The object a plugin module exports by default. */
393
+ export interface HncodePlugin {
394
+ name: string;
395
+ /** Semver, e.g. "1.0.0". Required. */
396
+ version: string;
397
+ install: (api: HncodePluginApi) => void | Promise<void>;
398
+ /**
399
+ * Names of the services install() registers with `api.provide()`. The loader
400
+ * reads this to work out the load order, so a provided service has to be declared
401
+ * here and not only at the provide() call site.
402
+ */
403
+ provides?: string[];
404
+ /**
405
+ * Names of the services this plugin needs. Its install() runs only after all of
406
+ * them are provided; a plugin whose dependencies can never be satisfied is skipped
407
+ * with an error notice instead of starting half-wired.
408
+ */
409
+ inject?: string[];
410
+ /** Called by unloadPlugins() (and by a reload) before the registrations are undone. */
411
+ dispose?: (api: HncodePluginApi) => void | Promise<void>;
412
+ }
413
+
414
+ // ---- runtime helpers (index.js) ----
415
+ /** The hooks the host actually fires. */
416
+ export declare const HOOK_NAMES: [
417
+ 'onStartup',
418
+ 'onShutdown',
419
+ 'onTurnStart',
420
+ 'onTurnEnd',
421
+ 'onBeforeRequest',
422
+ 'onAfterRequest',
423
+ 'onToolExecute',
424
+ 'onToolResult',
425
+ 'onNewMessage',
426
+ 'onSessionSave',
427
+ ];
428
+ /** Union of the hook names above, for typing a handler map. */
429
+ export type HookName = typeof HOOK_NAMES[number];
430
+ export declare const LEGACY_SEAMS: string[];
431
+ export declare const NOTICE_KINDS: string[];
432
+ export declare const SCOPES: string[];
433
+ export declare const LEGACY_SEAM_SET: Set<string>;
434
+ export declare const HOOK_NAME_SET: Set<string>;
435
+ export declare function definePlugin<T extends HncodePlugin>(plugin: T): T;
436
+ export declare function parsePatchTarget(target: string): { file: string; base: string; method: string | null; id: string } | null;
package/index.js ADDED
@@ -0,0 +1,109 @@
1
+ // @hncode/hncode-sdk — runtime helpers and types for hncode plugins.
2
+ //
3
+ // WHY THIS IS A SEPARATE, DEPENDENCY-FREE PACKAGE
4
+ // ----------------------------------------------
5
+ // A plugin runs INSIDE the hncode process: the host injects the `api` object into
6
+ // `install(api)`. So a plugin never needs to import hncode itself, and hncode is
7
+ // not (and must not become) a dependency of this package — that would pull the
8
+ // whole CLI, its entry point and its install scripts into every plugin.
9
+ //
10
+ // What a plugin DOES need at author time is the shape of `api` (for completion and
11
+ // type-checking) and, for `api.patch`, the list of symbols it may target. Both live
12
+ // here: `index.d.ts` describes the API, `targets.*` lists the patchable symbols.
13
+ //
14
+ // This file is the RUNTIME half. It exports small, dependency-free constants and
15
+ // helpers that a plugin can `import` for real (not just for types).
16
+
17
+ /**
18
+ * Lifecycle hooks accepted by `api.registerHook(name, fn)`.
19
+ * Kept in sync with the names the host actually FIRES — see src/plugin.js's
20
+ * registerHook and the runHooks() call sites in src/tui.js.
21
+ */
22
+ export const HOOK_NAMES = [
23
+ 'onStartup',
24
+ 'onShutdown',
25
+ 'onTurnStart',
26
+ 'onTurnEnd',
27
+ 'onBeforeRequest',
28
+ 'onAfterRequest',
29
+ 'onToolExecute',
30
+ 'onToolResult',
31
+ 'onNewMessage',
32
+ 'onSessionSave',
33
+ ];
34
+
35
+ /**
36
+ * The legacy abstract "seams" accepted by `api.patch(seam, fn)` with the old
37
+ * chain signature `(ctx, next)`. Everything else passed to `api.patch` is a
38
+ * symbol target like "llm.js#LLM.requestText".
39
+ */
40
+ export const LEGACY_SEAMS = [
41
+ 'systemPrompt',
42
+ 'llmRequest',
43
+ 'llmHeaders',
44
+ 'llmBody',
45
+ 'llmResponse',
46
+ 'toolDispatch',
47
+ 'toolResult',
48
+ 'beforeRender',
49
+ 'afterRender',
50
+ ];
51
+
52
+ /** Notice/severity kinds accepted by `api.notice(text, kind)`. */
53
+ export const NOTICE_KINDS = ['info', 'warn', 'error'];
54
+
55
+ /** Config scopes accepted by hncode's personal-preference / memory files. */
56
+ export const SCOPES = ['global', 'project'];
57
+
58
+ /**
59
+ * Wrap a plugin object with light validation. Purely a convenience: it returns
60
+ * its argument unchanged (so `export default definePlugin({...})` type-checks and
61
+ * runs the same), but it throws early on the mistakes hncode would otherwise
62
+ * reject at load time anyway — a missing name/version, or an install that is not
63
+ * a function. Failing here gives a clearer message and a stack that points at the
64
+ * plugin file rather than at hncode's loader.
65
+ *
66
+ * @template {import('./index.d.ts').HncodePlugin} T
67
+ * @param {T} plugin
68
+ * @returns {T}
69
+ */
70
+ export function definePlugin(plugin) {
71
+ if (!plugin || typeof plugin !== 'object') {
72
+ throw new Error('definePlugin: expected an object');
73
+ }
74
+ if (!plugin.name || typeof plugin.name !== 'string') {
75
+ throw new Error('definePlugin: `name` is required');
76
+ }
77
+ if (!plugin.version || typeof plugin.version !== 'string') {
78
+ throw new Error('definePlugin: `version` is required (semver, e.g. "1.0.0")');
79
+ }
80
+ if (typeof plugin.install !== 'function') {
81
+ throw new Error('definePlugin: `install(api)` must be a function');
82
+ }
83
+ return plugin;
84
+ }
85
+
86
+ /**
87
+ * Split a patch target into its parts, so a plugin can build targets from values
88
+ * instead of string concatenation. Returns null when the target is not a symbol
89
+ * target (e.g. a legacy seam).
90
+ *
91
+ * parsePatchTarget('llm.js#LLM.requestText')
92
+ * -> { file: 'llm.js', base: 'LLM', method: 'requestText', id: 'llm.js#LLM.requestText' }
93
+ * parsePatchTarget('git.js#commit')
94
+ * -> { file: 'git.js', base: 'commit', method: null, id: 'git.js#commit' }
95
+ *
96
+ * @param {string} target
97
+ * @returns {{ file: string, base: string, method: string | null, id: string } | null}
98
+ */
99
+ export function parsePatchTarget(target) {
100
+ const m = /^([^#]+)#([A-Za-z_$][\w$]*)(?:\.([A-Za-z_$][\w$]*))?$/.exec(String(target || '').trim());
101
+ if (!m) return null;
102
+ return { file: m[1], base: m[2], method: m[3] || null, id: `${m[1]}#${m[2]}${m[3] ? '.' + m[3] : ''}` };
103
+ }
104
+
105
+ /** The nine legacy seams as a Set, for membership tests in a plugin. */
106
+ export const LEGACY_SEAM_SET = new Set(LEGACY_SEAMS);
107
+
108
+ /** The hook names as a Set. */
109
+ export const HOOK_NAME_SET = new Set(HOOK_NAMES);
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@hncode/hncode-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Runtime helpers and TypeScript types for writing hncode plugins.",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "types": "index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./index.d.ts",
11
+ "default": "./index.js"
12
+ },
13
+ "./targets": {
14
+ "types": "./targets.d.ts",
15
+ "default": "./targets.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "index.js",
20
+ "index.d.ts",
21
+ "targets.js",
22
+ "targets.d.ts",
23
+ "README.md",
24
+ "LICENSE"
25
+ ],
26
+ "scripts": {
27
+ "gen": "node scripts/gen-targets.mjs",
28
+ "prepublishOnly": "node scripts/gen-targets.mjs"
29
+ },
30
+ "keywords": [
31
+ "hncode",
32
+ "plugin",
33
+ "sdk",
34
+ "types"
35
+ ],
36
+ "engines": {
37
+ "node": ">=20"
38
+ },
39
+ "license": "PolyForm-Noncommercial-1.0.0",
40
+ "author": "NiceHello666",
41
+ "dependencies": {}
42
+ }