@zeroroot-ai/zerocool 0.2.1 → 0.3.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.
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * zerocool-dispatch — one sandboxed dispatched run, then exit.
4
+ *
5
+ * The third dispatched shape, and the one gibson launches (zerocool-plugins#57,
6
+ * gibson#1596, ADR-0016). `zerocool-agent` and `zerocool-serve` are long-lived
7
+ * hosts that enroll once, keep a host key, and POLL the daemon for work. This is
8
+ * the opposite: gibson runs an untrusted agent by launching an ephemeral setec
9
+ * sandbox per mission run and injecting the run's credentials as environment. So
10
+ * there is no enrollment, no host key, and no poll loop — the task and the grant
11
+ * are already in the environment when the process starts, and the process serves
12
+ * exactly one dispatch and exits so the sandbox is torn down.
13
+ *
14
+ * WHAT REPLACES THE BOOTSTRAP TOKEN. The poll-loop shapes authenticate as a
15
+ * long-lived COMPONENT: a human mints a one-time `GIBSON_BOOTSTRAP_TOKEN`, the
16
+ * first run trades it for a persistent host key, and every later run re-registers
17
+ * with that key (ADR-0045). A sandboxed run has neither. It authenticates with
18
+ * the PER-DISPATCH capability grant gibson mints for this run and injects as
19
+ * `GIBSON_CALLBACK_ENDPOINT` + `GIBSON_CALLBACK_TOKEN`. That grant carries exactly
20
+ * the authority of this dispatch, so this process never reads a bootstrap token
21
+ * and never touches a host key.
22
+ *
23
+ * THE CALLBACKS ARE GRANT-AUTHENTICATED. This process drives `opencode run`
24
+ * headless and passes the per-dispatch grant to the child (see
25
+ * {@link dispatchChildEnv}). The child's mission callbacks — findings, tool
26
+ * calls, knowledge reads — then reach the daemon's harness callback listener as
27
+ * the TASK, on the injected grant, not as some enrolled component (see
28
+ * `knowledge-source.ts`).
29
+ *
30
+ * THE OUTPUT IS A LIVE NDJSON STREAM. Every event opencode prints is forwarded
31
+ * to this process's stdout as it arrives, so the daemon can stream the run to the
32
+ * read-only console (a later slice consumes it). The last line is the terminal
33
+ * result. stdout is therefore a clean event stream — the driver's own logs go to
34
+ * stderr — and a clean exit lets the sandbox tear down.
35
+ *
36
+ * Environment (injected by the sandbox launch):
37
+ *
38
+ * GIBSON_CALLBACK_ENDPOINT per-dispatch harness callback dial target (required)
39
+ * GIBSON_CALLBACK_TOKEN per-dispatch capability grant (required)
40
+ * GIBSON_TASK_GOAL the task to pursue (required)
41
+ * GIBSON_CALLBACK_INSECURE "1" to dial the callback listener without TLS (kind)
42
+ * GIBSON_MISSION_RUN_ID / GIBSON_AGENT_RUN_ID / GIBSON_TRACE_ID provenance
43
+ * ZEROCOOL_WORKSPACE working directory (defaults to the cwd)
44
+ * ZEROCOOL_MODEL provider/model for opencode
45
+ * GIBSON_OPENCODE_SESSION_ID continue an earlier opencode session
46
+ * GIBSON_TIMEOUT_MS hard deadline for the run, in ms
47
+ */
48
+ import type { AgentOutcome } from "@zeroroot-ai/sdk";
49
+ import { runOpencode } from "./opencode-run.js";
50
+ /**
51
+ * The per-dispatch grant, as the sandbox injects it. The child authenticates its
52
+ * harness callbacks with this; {@link dispatchChildEnv} renders it back to env.
53
+ */
54
+ export interface CallbackGrant {
55
+ /** `ExecuteRequest.callback_endpoint` — a bare `host:port` or an http(s) URL. */
56
+ callbackEndpoint: string;
57
+ /** `ExecuteRequest.callback_token` — the task-scoped capability grant. */
58
+ callbackToken: string;
59
+ /** Dial the callback listener without TLS. Only for a local or kind daemon. */
60
+ insecure?: boolean;
61
+ /** Provenance the platform correlates the run by. Empty when the caller set none. */
62
+ missionRunId?: string;
63
+ agentRunId?: string;
64
+ traceId?: string;
65
+ }
66
+ /** Everything one sandboxed dispatch needs, read from the environment. */
67
+ export interface DispatchContext extends CallbackGrant {
68
+ /** `task.goal` — the natural-language objective the sandbox handed over. */
69
+ goal: string;
70
+ /** opencode edits files here; it is the run's workspace. */
71
+ workspace: string;
72
+ /** `provider/model`, e.g. `gibson/default`. Omitted lets opencode choose. */
73
+ model?: string;
74
+ /** Continue an earlier opencode session instead of starting a new one. */
75
+ sessionId?: string;
76
+ /** Hard deadline for the run, in ms. `0` when none was set. */
77
+ timeoutMs: number;
78
+ }
79
+ /**
80
+ * Render the per-dispatch grant back to environment for the opencode child, so
81
+ * the child's harness callbacks travel on the task grant rather than on any
82
+ * component identity. Empty fields are omitted rather than set blank.
83
+ *
84
+ * Shared with `serve-agent.ts`, which builds the same passthrough from a polled
85
+ * work item — one definition so the two dispatched shapes hand the child the
86
+ * same environment.
87
+ */
88
+ export declare function dispatchChildEnv(g: CallbackGrant): NodeJS.ProcessEnv;
89
+ /**
90
+ * Read one sandboxed dispatch's context from the environment.
91
+ *
92
+ * Deliberately never reads `GIBSON_BOOTSTRAP_TOKEN` or a host key: a sandboxed
93
+ * run is authenticated by its per-dispatch grant alone, and reaching for a
94
+ * bootstrap token here would reintroduce the enrollment handshake this shape
95
+ * exists to avoid.
96
+ *
97
+ * The grant and the goal are required. A missing piece throws with the reason,
98
+ * because a sandbox that launched this process without them is a defect in the
99
+ * launch, not something to guess around by running opencode with no task or by
100
+ * making unauthenticated calls.
101
+ */
102
+ export declare function readDispatchContext(env: NodeJS.ProcessEnv, opts?: {
103
+ cwd?: string;
104
+ }): DispatchContext;
105
+ /** Injectable seams, so a test drives a dispatch without spawning opencode. */
106
+ export interface DispatchDeps {
107
+ /** Overridable opencode driver. */
108
+ run?: typeof runOpencode;
109
+ /** Live tap for each NDJSON event opencode prints. */
110
+ onEvent?: (line: string) => void;
111
+ }
112
+ /**
113
+ * Run one dispatched Task headless and map it to a terminal outcome.
114
+ *
115
+ * The opencode child inherits the per-dispatch grant, so its findings, tool
116
+ * calls and knowledge reads authenticate as the task. Events stream live through
117
+ * `deps.onEvent`. A crashed or timed-out run throws — {@link main} turns that
118
+ * into a failed terminal result and a non-zero exit.
119
+ */
120
+ export declare function runDispatch(ctx: DispatchContext, deps?: DispatchDeps): Promise<AgentOutcome>;
121
+ /**
122
+ * Render a terminal outcome as the last NDJSON line on stdout.
123
+ *
124
+ * `type: "result"` marks it apart from the streamed opencode events on the same
125
+ * stream, so the sandbox launcher reads the run's result from the one line that
126
+ * carries it.
127
+ */
128
+ export declare function formatTerminalResult(outcome: AgentOutcome): string;
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+ import { runOpencode } from "./opencode-run.js";
3
+ /**
4
+ * Render the per-dispatch grant back to environment for the opencode child, so
5
+ * the child's harness callbacks travel on the task grant rather than on any
6
+ * component identity. Empty fields are omitted rather than set blank.
7
+ *
8
+ * Shared with `serve-agent.ts`, which builds the same passthrough from a polled
9
+ * work item — one definition so the two dispatched shapes hand the child the
10
+ * same environment.
11
+ */
12
+ export function dispatchChildEnv(g) {
13
+ return {
14
+ ...(g.callbackEndpoint ? { GIBSON_CALLBACK_ENDPOINT: g.callbackEndpoint } : {}),
15
+ ...(g.callbackToken ? { GIBSON_CALLBACK_TOKEN: g.callbackToken } : {}),
16
+ ...(g.insecure ? { GIBSON_CALLBACK_INSECURE: "1" } : {}),
17
+ ...(g.missionRunId ? { GIBSON_MISSION_RUN_ID: g.missionRunId } : {}),
18
+ ...(g.agentRunId ? { GIBSON_AGENT_RUN_ID: g.agentRunId } : {}),
19
+ ...(g.traceId ? { GIBSON_TRACE_ID: g.traceId } : {}),
20
+ };
21
+ }
22
+ /**
23
+ * Read one sandboxed dispatch's context from the environment.
24
+ *
25
+ * Deliberately never reads `GIBSON_BOOTSTRAP_TOKEN` or a host key: a sandboxed
26
+ * run is authenticated by its per-dispatch grant alone, and reaching for a
27
+ * bootstrap token here would reintroduce the enrollment handshake this shape
28
+ * exists to avoid.
29
+ *
30
+ * The grant and the goal are required. A missing piece throws with the reason,
31
+ * because a sandbox that launched this process without them is a defect in the
32
+ * launch, not something to guess around by running opencode with no task or by
33
+ * making unauthenticated calls.
34
+ */
35
+ export function readDispatchContext(env, opts = {}) {
36
+ const endpoint = env.GIBSON_CALLBACK_ENDPOINT;
37
+ const token = env.GIBSON_CALLBACK_TOKEN;
38
+ if (!endpoint) {
39
+ throw new Error("GIBSON_CALLBACK_ENDPOINT is not set. A sandboxed dispatched run is authenticated by " +
40
+ "the per-dispatch grant the sandbox launch injects, not by a bootstrap token — the " +
41
+ "launch must supply the callback endpoint and token.");
42
+ }
43
+ if (!token) {
44
+ throw new Error("GIBSON_CALLBACK_ENDPOINT is set but GIBSON_CALLBACK_TOKEN is not. The callbacks would " +
45
+ "have no grant to authenticate with; a sandboxed run must not fall back to any other " +
46
+ "identity, so this fails instead.");
47
+ }
48
+ const goal = env.GIBSON_TASK_GOAL?.trim();
49
+ if (!goal) {
50
+ throw new Error("GIBSON_TASK_GOAL is empty. The sandbox launch injects the task to pursue; running " +
51
+ "opencode against an empty prompt would report whatever it says back as a mission result.");
52
+ }
53
+ const timeoutRaw = env.GIBSON_TIMEOUT_MS ? Number(env.GIBSON_TIMEOUT_MS) : 0;
54
+ return {
55
+ callbackEndpoint: endpoint,
56
+ callbackToken: token,
57
+ insecure: env.GIBSON_CALLBACK_INSECURE === "1",
58
+ missionRunId: env.GIBSON_MISSION_RUN_ID ?? "",
59
+ agentRunId: env.GIBSON_AGENT_RUN_ID ?? "",
60
+ traceId: env.GIBSON_TRACE_ID ?? "",
61
+ goal,
62
+ workspace: env.ZEROCOOL_WORKSPACE ?? opts.cwd ?? process.cwd(),
63
+ ...(env.ZEROCOOL_MODEL ? { model: env.ZEROCOOL_MODEL } : {}),
64
+ ...(env.GIBSON_OPENCODE_SESSION_ID ? { sessionId: env.GIBSON_OPENCODE_SESSION_ID } : {}),
65
+ timeoutMs: Number.isFinite(timeoutRaw) && timeoutRaw > 0 ? timeoutRaw : 0,
66
+ };
67
+ }
68
+ /**
69
+ * Run one dispatched Task headless and map it to a terminal outcome.
70
+ *
71
+ * The opencode child inherits the per-dispatch grant, so its findings, tool
72
+ * calls and knowledge reads authenticate as the task. Events stream live through
73
+ * `deps.onEvent`. A crashed or timed-out run throws — {@link main} turns that
74
+ * into a failed terminal result and a non-zero exit.
75
+ */
76
+ export async function runDispatch(ctx, deps = {}) {
77
+ const run = deps.run ?? runOpencode;
78
+ const result = await run({
79
+ goal: ctx.goal,
80
+ dir: ctx.workspace,
81
+ ...(ctx.model ? { model: ctx.model } : {}),
82
+ ...(ctx.sessionId ? { sessionId: ctx.sessionId } : {}),
83
+ ...(ctx.timeoutMs > 0 ? { timeoutMs: ctx.timeoutMs } : {}),
84
+ env: dispatchChildEnv(ctx),
85
+ ...(deps.onEvent ? { onEvent: deps.onEvent } : {}),
86
+ });
87
+ return {
88
+ output: result.text,
89
+ success: true,
90
+ metadata: {
91
+ opencode_session_id: result.sessionId,
92
+ finish_reason: result.finishReason,
93
+ tokens_total: String(result.tokens.total),
94
+ tokens_output: String(result.tokens.output),
95
+ cost: String(result.cost),
96
+ },
97
+ };
98
+ }
99
+ /**
100
+ * Render a terminal outcome as the last NDJSON line on stdout.
101
+ *
102
+ * `type: "result"` marks it apart from the streamed opencode events on the same
103
+ * stream, so the sandbox launcher reads the run's result from the one line that
104
+ * carries it.
105
+ */
106
+ export function formatTerminalResult(outcome) {
107
+ return JSON.stringify({
108
+ type: "result",
109
+ success: outcome.success ?? true,
110
+ output: outcome.output ?? "",
111
+ ...(outcome.findingIds ? { finding_ids: outcome.findingIds } : {}),
112
+ metadata: outcome.metadata ?? {},
113
+ });
114
+ }
115
+ async function main() {
116
+ let ctx;
117
+ try {
118
+ ctx = readDispatchContext(process.env);
119
+ }
120
+ catch (e) {
121
+ // A launch defect, not a run failure. Say so on stderr and still emit a
122
+ // terminal result so the launcher never blocks waiting for one.
123
+ const message = e.message;
124
+ console.error(`[zerocool-dispatch] ${message}`);
125
+ process.stdout.write(`${formatTerminalResult({ success: false, output: message, metadata: { error: message } })}\n`);
126
+ process.exit(2);
127
+ return;
128
+ }
129
+ console.error(`[zerocool-dispatch] run mission=${ctx.missionRunId || "-"} agent=${ctx.agentRunId || "-"} ` +
130
+ `workspace=${ctx.workspace}; callbacks use the per-dispatch grant`);
131
+ try {
132
+ const outcome = await runDispatch(ctx, {
133
+ // Forward every opencode event to our stdout, live, for the console stream.
134
+ onEvent: (line) => process.stdout.write(`${line}\n`),
135
+ });
136
+ process.stdout.write(`${formatTerminalResult(outcome)}\n`);
137
+ console.error(`[zerocool-dispatch] done reason=${outcome.metadata?.finish_reason ?? "-"} ` +
138
+ `tokens=${outcome.metadata?.tokens_total ?? "-"}`);
139
+ process.exit(0);
140
+ }
141
+ catch (e) {
142
+ const message = e.message;
143
+ console.error(`[zerocool-dispatch] run failed: ${message}`);
144
+ process.stdout.write(`${formatTerminalResult({ success: false, output: message, metadata: { error: message } })}\n`);
145
+ process.exit(1);
146
+ }
147
+ }
148
+ // Only run when executed as the bin, so the functions above stay importable.
149
+ if (process.argv[1]?.endsWith("dispatch.js")) {
150
+ main().catch((e) => {
151
+ console.error(`[zerocool-dispatch] fatal: ${e.message}`);
152
+ process.exit(1);
153
+ });
154
+ }
@@ -56,7 +56,28 @@ export interface OpencodeRunOptions {
56
56
  env?: NodeJS.ProcessEnv;
57
57
  /** Binary to run. Overridable for tests and for a pinned install. */
58
58
  bin?: string;
59
+ /**
60
+ * Called with each complete NDJSON line as opencode prints it, live, before
61
+ * the run finishes. A dispatched sandbox forwards these to its own stdout so
62
+ * the daemon can stream the run to the read-only console. The same bytes are
63
+ * still buffered and parsed at close, so this is a tap, not a replacement —
64
+ * a slow or throwing sink never changes what the run returns.
65
+ */
66
+ onEvent?: (line: string) => void;
59
67
  }
68
+ /**
69
+ * Split a byte stream into complete lines across chunk boundaries.
70
+ *
71
+ * `spawn`'s `data` events do not align to newlines: one event can carry half a
72
+ * line, or several lines and a fragment. This buffers the fragment and calls
73
+ * `onLine` once per complete, non-empty line, so a live tap sees whole NDJSON
74
+ * events and never half of one. `flush` emits a trailing line with no final
75
+ * newline. Exported so the boundary handling is tested directly.
76
+ */
77
+ export declare function createLineStreamer(onLine: (line: string) => void): {
78
+ push: (chunk: string) => void;
79
+ flush: () => void;
80
+ };
60
81
  /** Build the argv for a headless run. Exported so a test can assert it. */
61
82
  export declare function opencodeArgs(opts: OpencodeRunOptions): string[];
62
83
  /**
@@ -46,6 +46,38 @@ export function parseOpencodeEvents(stdout) {
46
46
  result.text = chunks.join("");
47
47
  return result;
48
48
  }
49
+ /**
50
+ * Split a byte stream into complete lines across chunk boundaries.
51
+ *
52
+ * `spawn`'s `data` events do not align to newlines: one event can carry half a
53
+ * line, or several lines and a fragment. This buffers the fragment and calls
54
+ * `onLine` once per complete, non-empty line, so a live tap sees whole NDJSON
55
+ * events and never half of one. `flush` emits a trailing line with no final
56
+ * newline. Exported so the boundary handling is tested directly.
57
+ */
58
+ export function createLineStreamer(onLine) {
59
+ let pending = "";
60
+ const emit = (raw) => {
61
+ const line = raw.trim();
62
+ if (line)
63
+ onLine(line);
64
+ };
65
+ return {
66
+ push(chunk) {
67
+ pending += chunk;
68
+ let nl;
69
+ while ((nl = pending.indexOf("\n")) >= 0) {
70
+ emit(pending.slice(0, nl));
71
+ pending = pending.slice(nl + 1);
72
+ }
73
+ },
74
+ flush() {
75
+ const rest = pending;
76
+ pending = "";
77
+ emit(rest);
78
+ },
79
+ };
80
+ }
49
81
  /** Build the argv for a headless run. Exported so a test can assert it. */
50
82
  export function opencodeArgs(opts) {
51
83
  const args = ["run", "--format", "json", "--dir", opts.dir];
@@ -81,10 +113,28 @@ export async function runOpencode(opts) {
81
113
  });
82
114
  let stdout = "";
83
115
  let stderr = "";
84
- child.stdout.on("data", (d) => (stdout += d.toString()));
116
+ // A live tap for the daemon console, only when the caller asked for one. The
117
+ // streamer is guarded so a throwing sink cannot fail the run — the buffered
118
+ // parse below is the source of truth for the result.
119
+ const streamer = opts.onEvent
120
+ ? createLineStreamer((line) => {
121
+ try {
122
+ opts.onEvent?.(line);
123
+ }
124
+ catch {
125
+ // A broken console tap must not cost a mission its result.
126
+ }
127
+ })
128
+ : undefined;
129
+ child.stdout.on("data", (d) => {
130
+ const s = d.toString();
131
+ stdout += s;
132
+ streamer?.push(s);
133
+ });
85
134
  child.stderr.on("data", (d) => (stderr += d.toString()));
86
135
  child.on("error", (e) => reject(new Error(`could not run ${bin}: ${e.message}`)));
87
136
  child.on("close", (code, signal) => {
137
+ streamer?.flush();
88
138
  if (signal) {
89
139
  // Killed by the timeout. Say so with the deadline, because "terminated"
90
140
  // alone sends whoever reads the mission looking for a crash.
@@ -28,6 +28,7 @@ import { connectGibson, registerInstance, startAgentWorker, startHeartbeat, } fr
28
28
  import { existsSync } from "node:fs";
29
29
  import { homedir } from "node:os";
30
30
  import { join } from "node:path";
31
+ import { dispatchChildEnv } from "./dispatch.js";
31
32
  import { runOpencode } from "./opencode-run.js";
32
33
  /** Version reported to the daemon on registration. */
33
34
  const VERSION = "0.1.0";
@@ -54,21 +55,18 @@ export async function agentHandler(item, opts) {
54
55
  // pass it back — see the ADR on why this is not yet automatic.
55
56
  sessionId: item.context.opencode_session_id,
56
57
  timeoutMs: item.timeoutMs,
57
- env: {
58
- // The task-scoped callback seam. gibson mints these per dispatch
59
- // (`internal/engine/harness/implementation.go:1205-1210`) so a dispatched
60
- // run reaches the harness as the TASK rather than as this component.
61
- // Passed through to the child now; the plugin consuming them in
62
- // preference to the host-key grant is tracked in the ADR as the next
63
- // slice — today the child still authenticates as the component, which is
64
- // broader authority than the dispatch intends.
65
- ...(item.callbackEndpoint ? { GIBSON_CALLBACK_ENDPOINT: item.callbackEndpoint } : {}),
66
- ...(item.callbackToken ? { GIBSON_CALLBACK_TOKEN: item.callbackToken } : {}),
67
- // Provenance, so anything the child emits can be correlated to this run.
68
- ...(item.missionRunId ? { GIBSON_MISSION_RUN_ID: item.missionRunId } : {}),
69
- ...(item.agentRunId ? { GIBSON_AGENT_RUN_ID: item.agentRunId } : {}),
70
- ...(item.traceId ? { GIBSON_TRACE_ID: item.traceId } : {}),
71
- },
58
+ // The task-scoped callback seam. gibson mints the grant per dispatch
59
+ // (`internal/engine/harness/implementation.go:1205-1210`) so a dispatched run
60
+ // reaches the harness as the TASK rather than as this component. The same
61
+ // passthrough the sandboxed shape uses (`dispatch.ts`), so the child sees one
62
+ // environment however it was launched.
63
+ env: dispatchChildEnv({
64
+ callbackEndpoint: item.callbackEndpoint,
65
+ callbackToken: item.callbackToken,
66
+ missionRunId: item.missionRunId,
67
+ agentRunId: item.agentRunId,
68
+ traceId: item.traceId,
69
+ }),
72
70
  });
73
71
  return {
74
72
  output: run.text,
package/dist/serve.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,14 +1,26 @@
1
1
  {
2
2
  "name": "@zeroroot-ai/zerocool",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "opencode plugin: Gibson platform integration (zerocool). Zero-config LLM, tools, findings, knowledge, delegate/missions.",
5
5
  "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/zeroroot-ai/zerocool-plugins.git",
9
+ "directory": "packages/opencode-gibson"
10
+ },
11
+ "homepage": "https://github.com/zeroroot-ai/zerocool-plugins",
12
+ "bugs": "https://github.com/zeroroot-ai/zerocool-plugins/issues",
6
13
  "type": "module",
7
14
  "main": "dist/index.js",
8
15
  "types": "dist/index.d.ts",
9
16
  "files": [
10
17
  "dist"
11
18
  ],
19
+ "scripts": {
20
+ "build": "tsc -p tsconfig.json",
21
+ "typecheck": "tsc -p tsconfig.json --noEmit",
22
+ "test": "tsc -p tsconfig.test.json && node --test \"dist-test/**/*.test.js\""
23
+ },
12
24
  "dependencies": {
13
25
  "@zeroroot-ai/sdk": "^0.4.0"
14
26
  },
@@ -20,7 +32,8 @@
20
32
  },
21
33
  "bin": {
22
34
  "zerocool-serve": "dist/serve.js",
23
- "zerocool-agent": "dist/serve-agent.js"
35
+ "zerocool-agent": "dist/serve-agent.js",
36
+ "zerocool-dispatch": "dist/dispatch.js"
24
37
  },
25
38
  "publishConfig": {
26
39
  "access": "public"
@@ -30,10 +43,5 @@
30
43
  "types": "./dist/index.d.ts",
31
44
  "import": "./dist/index.js"
32
45
  }
33
- },
34
- "scripts": {
35
- "build": "tsc -p tsconfig.json",
36
- "typecheck": "tsc -p tsconfig.json --noEmit",
37
- "test": "tsc -p tsconfig.test.json && node --test \"dist-test/**/*.test.js\""
38
46
  }
39
- }
47
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 ZeroRoot
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.