omkit 0.0.1
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/LICENSE +21 -0
- package/README.md +144 -0
- package/dist/actions/chrome-page.d.ts +44 -0
- package/dist/actions/chrome-page.js +94 -0
- package/dist/actions/command.d.ts +26 -0
- package/dist/actions/command.js +32 -0
- package/dist/actions/healthcheck.d.ts +55 -0
- package/dist/actions/healthcheck.js +94 -0
- package/dist/actions/index.d.ts +22 -0
- package/dist/actions/index.js +14 -0
- package/dist/actions/prompt.d.ts +54 -0
- package/dist/actions/prompt.js +99 -0
- package/dist/actions/tail-log.d.ts +30 -0
- package/dist/actions/tail-log.js +124 -0
- package/dist/actions/until-log.d.ts +24 -0
- package/dist/actions/until-log.js +49 -0
- package/dist/actions/watch-dir.d.ts +35 -0
- package/dist/actions/watch-dir.js +159 -0
- package/dist/actions/watch.d.ts +33 -0
- package/dist/actions/watch.js +80 -0
- package/dist/core/action.d.ts +105 -0
- package/dist/core/action.js +133 -0
- package/dist/core/events.d.ts +23 -0
- package/dist/core/events.js +61 -0
- package/dist/core/helpers/AsyncQueue.d.ts +13 -0
- package/dist/core/helpers/AsyncQueue.js +50 -0
- package/dist/core/log-collector/LogsCollector.d.ts +63 -0
- package/dist/core/log-collector/LogsCollector.js +110 -0
- package/dist/core/log-collector/global.d.ts +7 -0
- package/dist/core/log-collector/global.js +7 -0
- package/dist/core/log-collector/render.d.ts +57 -0
- package/dist/core/log-collector/render.js +111 -0
- package/dist/core/markers.d.ts +9 -0
- package/dist/core/markers.js +13 -0
- package/dist/core/output.d.ts +55 -0
- package/dist/core/output.js +163 -0
- package/dist/core/process.d.ts +21 -0
- package/dist/core/process.js +73 -0
- package/dist/core/run.d.ts +95 -0
- package/dist/core/run.js +212 -0
- package/dist/core/spin.d.ts +58 -0
- package/dist/core/spin.js +29 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +25 -0
- package/package.json +59 -0
package/dist/core/run.js
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { relative } from "node:path";
|
|
2
|
+
import { log as logs } from "./log-collector/global.js";
|
|
3
|
+
import { createRenderer } from "./log-collector/render.js";
|
|
4
|
+
import { streamLog, writeLog } from "./output.js";
|
|
5
|
+
import { marker } from "./markers.js";
|
|
6
|
+
/** One run per process — a single world over the one global log. See {@link run}. */
|
|
7
|
+
let started = false;
|
|
8
|
+
/** Narrate a run-lifecycle milestone into the global log (renders as a `[run]` line). */
|
|
9
|
+
const narrate = (message) => logs.append({ source: "run", level: "run", message });
|
|
10
|
+
/** The entry script, relative to where node was invoked (so the log says what produced it). */
|
|
11
|
+
const scriptPath = () => {
|
|
12
|
+
const entry = process.argv[1];
|
|
13
|
+
return entry ? relative(process.cwd(), entry) : "(unknown)";
|
|
14
|
+
};
|
|
15
|
+
/** A constructed instance is an object carrying a `start` function. */
|
|
16
|
+
const isActionInstance = (value) => typeof value === "object" &&
|
|
17
|
+
value !== null &&
|
|
18
|
+
typeof value.start === "function";
|
|
19
|
+
/** An *uncalled* action: the callable `action(name).run(…)` returns before it's invoked. */
|
|
20
|
+
const isUncalledAction = (value) => typeof value === "function" && typeof value.actionName === "string";
|
|
21
|
+
/**
|
|
22
|
+
* Guard each launch argument: an action *instance* is required, not the action
|
|
23
|
+
* itself. Forgetting the trailing `()` is an easy slip (the callable has no
|
|
24
|
+
* `.start`), and silently treating it as something else would report a false
|
|
25
|
+
* green — so fail loudly with the fix.
|
|
26
|
+
*/
|
|
27
|
+
function assertInstance(value) {
|
|
28
|
+
if (isActionInstance(value))
|
|
29
|
+
return;
|
|
30
|
+
const hint = isUncalledAction(value)
|
|
31
|
+
? ` — that looks like an action that wasn't invoked; construct an instance by calling it: action("…").run(…)()`
|
|
32
|
+
: "";
|
|
33
|
+
throw new Error(`run() expects action instances; received ${typeof value}${hint}`);
|
|
34
|
+
}
|
|
35
|
+
export function run(...args) {
|
|
36
|
+
if (started) {
|
|
37
|
+
throw new Error("run() may only be called once per process — attach more actions to the existing run with its .run(…) method.");
|
|
38
|
+
}
|
|
39
|
+
// Peel an optional leading options bag off the variadic actions, keeping the
|
|
40
|
+
// bare `run(...actions)` call form working unchanged. Options are a plain
|
|
41
|
+
// object (no `.start`); a *function* first arg is never options — it's an
|
|
42
|
+
// uncalled action, which `assertInstance` below reports clearly.
|
|
43
|
+
const first = args[0];
|
|
44
|
+
const hasOptions = first !== undefined && !isActionInstance(first) && typeof first !== "function";
|
|
45
|
+
const options = hasOptions ? first : {};
|
|
46
|
+
const actions = (hasOptions ? args.slice(1) : args);
|
|
47
|
+
const failFast = options.failFast ?? true;
|
|
48
|
+
// Validate eagerly, before the one-run latch flips, so a bad argument throws
|
|
49
|
+
// cleanly and leaves the process's single run slot still usable.
|
|
50
|
+
for (const instance of actions)
|
|
51
|
+
assertInstance(instance);
|
|
52
|
+
started = true;
|
|
53
|
+
const controller = new AbortController();
|
|
54
|
+
// The log closes when the run tears down, so every `logs.subscribe(…)` ends on
|
|
55
|
+
// its own — no subscriber has to watch the signal.
|
|
56
|
+
logs.endOn(controller.signal);
|
|
57
|
+
// ── Lifecycle state ──────────────────────────────────────────────────────
|
|
58
|
+
// The single source of truth for "where in its life is this run". Only
|
|
59
|
+
// `beginClosing` and the finalize step below mutate it, and only forward.
|
|
60
|
+
let state = "open";
|
|
61
|
+
// Genuine failures (not teardown cascade). Frozen into the verdict at close.
|
|
62
|
+
const failures = [];
|
|
63
|
+
// Every launched action's promise lives here until it settles; the drain loop
|
|
64
|
+
// empties this set. Daemons keep it non-empty until the controller aborts.
|
|
65
|
+
const inFlight = new Set();
|
|
66
|
+
/**
|
|
67
|
+
* Move `open → closing`: abort the signal (unwinding procs, waits, and
|
|
68
|
+
* daemons), narrate the cause once, and stop accepting new actions. Idempotent
|
|
69
|
+
* — only the first caller transitions; later triggers (a second failure, a
|
|
70
|
+
* `cancel()` during teardown) are no-ops. This is the *only* path to abort, so
|
|
71
|
+
* every teardown reason flows through one place.
|
|
72
|
+
*/
|
|
73
|
+
const beginClosing = (reason) => {
|
|
74
|
+
if (state !== "open")
|
|
75
|
+
return;
|
|
76
|
+
state = "closing";
|
|
77
|
+
narrate(`tearing down · ${reason}`);
|
|
78
|
+
controller.abort();
|
|
79
|
+
};
|
|
80
|
+
/** Record a genuine fault and, under fail-fast, kick off teardown. */
|
|
81
|
+
const recordFailure = (action, error) => {
|
|
82
|
+
failures.push({ action, error });
|
|
83
|
+
if (failFast)
|
|
84
|
+
beginClosing(`failed: ${action}`);
|
|
85
|
+
};
|
|
86
|
+
// Ctrl-C tears the run down gracefully through the lifecycle, like cancel().
|
|
87
|
+
const onSigint = () => beginClosing("interrupted (SIGINT)");
|
|
88
|
+
process.once("SIGINT", onSigint);
|
|
89
|
+
// A throw or rejection that escaped every action's own handling. Without a
|
|
90
|
+
// handler Node prints it and exits *immediately* — before the run can flush its
|
|
91
|
+
// log, which leaves a silent, empty log directory and no verdict. So catch it,
|
|
92
|
+
// log it, fold it into the verdict, and drive teardown so the log still flushes
|
|
93
|
+
// and the exit code reflects the fault — degrading a stray throw to a recorded
|
|
94
|
+
// failure instead of a hard crash. Removed at finalize, so it only governs
|
|
95
|
+
// while this run owns the process.
|
|
96
|
+
const onFatal = (kind) => (error) => {
|
|
97
|
+
logs.append({
|
|
98
|
+
source: kind,
|
|
99
|
+
level: "error",
|
|
100
|
+
message: error instanceof Error ? (error.stack ?? error.message) : String(error),
|
|
101
|
+
});
|
|
102
|
+
// Genuine fault vs. teardown fallout: only one that surfaces *before* the
|
|
103
|
+
// signal aborts is the run's own (mirrors `launch`'s cascade rule); a throw
|
|
104
|
+
// during unwind is logged but doesn't pollute the verdict. Either way tear
|
|
105
|
+
// down — an uncaught fault leaves the process state undefined, so we always
|
|
106
|
+
// finish and flush, even under `failFast: false`.
|
|
107
|
+
if (!controller.signal.aborted)
|
|
108
|
+
failures.push({ action: kind, error });
|
|
109
|
+
beginClosing(kind);
|
|
110
|
+
};
|
|
111
|
+
const onUncaught = onFatal("uncaughtException");
|
|
112
|
+
const onUnhandled = onFatal("unhandledRejection");
|
|
113
|
+
process.on("uncaughtException", onUncaught);
|
|
114
|
+
process.on("unhandledRejection", onUnhandled);
|
|
115
|
+
narrate(`run started · ${scriptPath()}`);
|
|
116
|
+
// Start streaming log entries to disk immediately — incremental writes survive
|
|
117
|
+
// hard kills where the final writeLog never runs.
|
|
118
|
+
void streamLog(logs).catch(() => { });
|
|
119
|
+
const launch = (instance) => {
|
|
120
|
+
narrate(`launch ${instance.name}`);
|
|
121
|
+
// The action logs into the one shared store (entries carry their `source`;
|
|
122
|
+
// grouping is applied at render time) and gets the run's signal directly; the
|
|
123
|
+
// framework injects a `proc` bound to both, so there's no ambient context.
|
|
124
|
+
const promise = instance.start({ logs, signal: controller.signal }).catch((error) => {
|
|
125
|
+
// Always record the fault in the action's own log, under its name.
|
|
126
|
+
logs.append({
|
|
127
|
+
source: instance.name,
|
|
128
|
+
level: "error",
|
|
129
|
+
message: error instanceof Error ? (error.stack ?? error.message) : String(error),
|
|
130
|
+
});
|
|
131
|
+
// Genuine failure vs. teardown fallout: if the signal was already aborted
|
|
132
|
+
// when this surfaced, the rejection is almost certainly the abort killing
|
|
133
|
+
// the action (a cascade), not its own fault — so it must not pollute the
|
|
134
|
+
// verdict. The *first* real error is caught here before `recordFailure`
|
|
135
|
+
// triggers the abort, so `signal.aborted` is still false for it.
|
|
136
|
+
if (!controller.signal.aborted)
|
|
137
|
+
recordFailure(instance.name, error);
|
|
138
|
+
});
|
|
139
|
+
inFlight.add(promise);
|
|
140
|
+
void promise.finally(() => inFlight.delete(promise));
|
|
141
|
+
};
|
|
142
|
+
for (const instance of actions)
|
|
143
|
+
launch(instance);
|
|
144
|
+
// Drives the run to `closed`. The loop re-checks `inFlight` because actions can
|
|
145
|
+
// be added (or daemons can settle on abort) while we await. A synchronous
|
|
146
|
+
// `.run(…)` from a settling action's lifecycle event lands before that action's
|
|
147
|
+
// `finally` removes it, so `inFlight` never spuriously hits 0 mid-handoff.
|
|
148
|
+
const done = (async () => {
|
|
149
|
+
for (;;) {
|
|
150
|
+
if (inFlight.size === 0) {
|
|
151
|
+
// Nothing left to run. If still open, every action finished on its own —
|
|
152
|
+
// natural completion; tear down so daemons/listeners unwind uniformly.
|
|
153
|
+
// If already closing, teardown is simply complete.
|
|
154
|
+
if (state === "open")
|
|
155
|
+
beginClosing("completed");
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
await Promise.allSettled([...inFlight]);
|
|
159
|
+
}
|
|
160
|
+
// ── Finalize (reached exactly once) ──────────────────────────────────────
|
|
161
|
+
state = "closed";
|
|
162
|
+
process.off("SIGINT", onSigint);
|
|
163
|
+
process.off("uncaughtException", onUncaught);
|
|
164
|
+
process.off("unhandledRejection", onUnhandled);
|
|
165
|
+
narrate("finished");
|
|
166
|
+
const file = await writeLog(logs);
|
|
167
|
+
// Direct to the terminal — the file's already written, so this line isn't in it.
|
|
168
|
+
console.log(marker("run", `log → ${file}`));
|
|
169
|
+
const result = { ok: failures.length === 0, failures };
|
|
170
|
+
// One process = one run = one verdict; reflect pass/fail in the exit code so
|
|
171
|
+
// shells and CI see it without parsing the log. Only set it on failure, so a
|
|
172
|
+
// code a failing action's own handler may have set isn't clobbered to 0.
|
|
173
|
+
if (!result.ok)
|
|
174
|
+
process.exitCode = 1;
|
|
175
|
+
return result;
|
|
176
|
+
})();
|
|
177
|
+
// `done` resolves with the verdict and never rejects; guard anyway so a stray
|
|
178
|
+
// finalize error can't surface as an unhandled rejection.
|
|
179
|
+
done.catch(() => { });
|
|
180
|
+
const drain = (write = (message) => console.log(message)) => {
|
|
181
|
+
void (async () => {
|
|
182
|
+
// A renderer applies grouping/indentation as entries stream by; its state
|
|
183
|
+
// spans the replayed history and live entries as one continuous stream. The
|
|
184
|
+
// subscription ends itself when the run tears down (the collector closes it),
|
|
185
|
+
// so this loop simply runs to completion.
|
|
186
|
+
const render = createRenderer();
|
|
187
|
+
for await (const entry of logs.subscribe({ replay: true }))
|
|
188
|
+
write(render(entry));
|
|
189
|
+
})().catch(() => { });
|
|
190
|
+
return self;
|
|
191
|
+
};
|
|
192
|
+
const self = {
|
|
193
|
+
logs,
|
|
194
|
+
get state() {
|
|
195
|
+
return state;
|
|
196
|
+
},
|
|
197
|
+
done,
|
|
198
|
+
signal: controller.signal,
|
|
199
|
+
run(...more) {
|
|
200
|
+
if (state !== "open") {
|
|
201
|
+
throw new Error(`run.run(…) rejected: the run is "${state}", not "open". Launch actions before ` +
|
|
202
|
+
`teardown, or from a lifecycle event of an action that is still running.`);
|
|
203
|
+
}
|
|
204
|
+
for (const instance of more)
|
|
205
|
+
launch(instance);
|
|
206
|
+
return self;
|
|
207
|
+
},
|
|
208
|
+
cancel: () => beginClosing("cancelled"),
|
|
209
|
+
drain,
|
|
210
|
+
};
|
|
211
|
+
return self;
|
|
212
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type AnyActionInstance } from "./action.ts";
|
|
2
|
+
import { type Run, type RunOptions } from "./run.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Launch an action into the spin's run and get the same instance back, so you
|
|
5
|
+
* can `await` its `.done` / `.ref` or subscribe with `.on` / `.once`. A nod is
|
|
6
|
+
* how the body waves an action in.
|
|
7
|
+
*/
|
|
8
|
+
export type Nod = <I extends AnyActionInstance>(instance: I) => I;
|
|
9
|
+
/** Tunes a {@link spin} — the run's options plus how it drains. */
|
|
10
|
+
export interface SpinOptions extends RunOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Stream the log to the console automatically from the start. Default `true`.
|
|
13
|
+
* Set `false` when you need to drain later via {@link SpinContext.drain} —
|
|
14
|
+
* e.g. after an interactive `prompt`, so the stream doesn't write over it.
|
|
15
|
+
*/
|
|
16
|
+
drain?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** What a {@link spin} body receives. */
|
|
19
|
+
export interface SpinContext {
|
|
20
|
+
/** Launch an action into the run; returns the instance for awaiting/chaining. */
|
|
21
|
+
readonly nod: Nod;
|
|
22
|
+
/**
|
|
23
|
+
* Start streaming the run's log to the console now. Only needed when the spin
|
|
24
|
+
* was created with `drain: false`; idempotent, so it's safe to call regardless.
|
|
25
|
+
*/
|
|
26
|
+
readonly drain: Run["drain"];
|
|
27
|
+
/**
|
|
28
|
+
* Tear the run down (abort the signal, stopping daemons). Use it to end a run
|
|
29
|
+
* whose work is finished but which is held open by a daemon — e.g. once a
|
|
30
|
+
* one-shot build completes while a watcher is still running.
|
|
31
|
+
*/
|
|
32
|
+
readonly cancel: Run["cancel"];
|
|
33
|
+
/** The run's abort signal — honor it to stop early. */
|
|
34
|
+
readonly signal: AbortSignal;
|
|
35
|
+
}
|
|
36
|
+
/** The body of a {@link spin}: any (async) function — it isn't named or wrapped by you. */
|
|
37
|
+
export type SpinBody = (ctx: SpinContext) => void | Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Runs a linear orchestration. You pass a plain (async) function; tswm hosts it
|
|
40
|
+
* in a single in-flight action and hands it a {@link Nod}. Because that host
|
|
41
|
+
* stays in-flight while your body `await`s, the run never idles shut between
|
|
42
|
+
* steps — so you write `await` / `if` control flow instead of nested `done`
|
|
43
|
+
* callbacks. When the body returns, the daemons it nodded in keep the run alive
|
|
44
|
+
* until teardown.
|
|
45
|
+
*
|
|
46
|
+
* spin({ failFast: false }, async ({ nod }) => {
|
|
47
|
+
* if ((await nod(prompt({ … })).done) === "yes") await nod(test).done;
|
|
48
|
+
* nod(devServer); // fire-and-forget daemon
|
|
49
|
+
* const chrome = nod(chromedriver({ … }));
|
|
50
|
+
* nod(chromePage(chrome.ref)); // data deps via .ref
|
|
51
|
+
* });
|
|
52
|
+
*
|
|
53
|
+
* Auto-drains by default; pass `drain: false` and call `ctx.drain()` yourself to
|
|
54
|
+
* stream the log only from a chosen point (e.g. after a `prompt`). Returns the
|
|
55
|
+
* {@link Run}, so `.done` is available on it too.
|
|
56
|
+
*/
|
|
57
|
+
export declare function spin(body: SpinBody): Run;
|
|
58
|
+
export declare function spin(options: SpinOptions, body: SpinBody): Run;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { action } from "./action.js";
|
|
2
|
+
import { run } from "./run.js";
|
|
3
|
+
export function spin(a, b) {
|
|
4
|
+
const [options, body] = typeof a === "function" ? [{}, a] : [a, b];
|
|
5
|
+
const { drain: autoDrain = true, ...runOptions } = options;
|
|
6
|
+
// `run(...)` below assigns `host` synchronously, before the action's async body
|
|
7
|
+
// ever runs — so the closures here capture the run safely.
|
|
8
|
+
let host;
|
|
9
|
+
// One-shot drain: auto-drain and a manual ctx.drain() can't double-subscribe.
|
|
10
|
+
let drained = false;
|
|
11
|
+
const startDrain = (write) => {
|
|
12
|
+
if (!drained) {
|
|
13
|
+
drained = true;
|
|
14
|
+
host.drain(write);
|
|
15
|
+
}
|
|
16
|
+
return host;
|
|
17
|
+
};
|
|
18
|
+
const hosted = action("Spin").run(async ({ signal }) => {
|
|
19
|
+
const nod = (instance) => {
|
|
20
|
+
host.run(instance);
|
|
21
|
+
return instance;
|
|
22
|
+
};
|
|
23
|
+
await body({ nod, drain: startDrain, cancel: () => host.cancel(), signal });
|
|
24
|
+
});
|
|
25
|
+
host = run(runOptions, hosted());
|
|
26
|
+
if (autoDrain)
|
|
27
|
+
startDrain();
|
|
28
|
+
return host;
|
|
29
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tswm — the operational/runtime layer to tskb's knowledge layer.
|
|
3
|
+
*
|
|
4
|
+
* The core engine: define typed {@link action}s, launch them under one
|
|
5
|
+
* {@link run}, and share a single append-only log. Reusable actions built on
|
|
6
|
+
* this engine live at the `tswm/actions` entry point.
|
|
7
|
+
*
|
|
8
|
+
* This is a curated public surface — internal helpers (the async queue, the log
|
|
9
|
+
* renderer, marker prefixing) are intentionally not exported.
|
|
10
|
+
*/
|
|
11
|
+
export { action } from "./core/action.ts";
|
|
12
|
+
export type { Action, ActionBuilder, ActionInstance, AnyActionInstance, ActionContext, SystemGlobal, SystemEvents, InstanceEvents, NoEvents, Awaitable, } from "./core/action.ts";
|
|
13
|
+
export { run } from "./core/run.ts";
|
|
14
|
+
export type { Run, RunResult, RunOptions, RunState, ActionFailure } from "./core/run.ts";
|
|
15
|
+
export { spin } from "./core/spin.ts";
|
|
16
|
+
export type { Nod, SpinOptions, SpinContext, SpinBody } from "./core/spin.ts";
|
|
17
|
+
export { events } from "./core/events.ts";
|
|
18
|
+
export type { Emitter, EventHandler, EventMeta } from "./core/events.ts";
|
|
19
|
+
export { createProc } from "./core/process.ts";
|
|
20
|
+
export type { Proc } from "./core/process.ts";
|
|
21
|
+
export { LogsCollector } from "./core/log-collector/LogsCollector.ts";
|
|
22
|
+
export type { Logger, LogEntry, LogInput, SubscribeOptions, } from "./core/log-collector/LogsCollector.ts";
|
|
23
|
+
export { log } from "./core/log-collector/global.ts";
|
|
24
|
+
export { snapshot, captureSnapshot } from "./core/output.ts";
|
|
25
|
+
export type { SnapshotRef } from "./core/output.ts";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tswm — the operational/runtime layer to tskb's knowledge layer.
|
|
3
|
+
*
|
|
4
|
+
* The core engine: define typed {@link action}s, launch them under one
|
|
5
|
+
* {@link run}, and share a single append-only log. Reusable actions built on
|
|
6
|
+
* this engine live at the `tswm/actions` entry point.
|
|
7
|
+
*
|
|
8
|
+
* This is a curated public surface — internal helpers (the async queue, the log
|
|
9
|
+
* renderer, marker prefixing) are intentionally not exported.
|
|
10
|
+
*/
|
|
11
|
+
// ── Actions ────────────────────────────────────────────────────────────────
|
|
12
|
+
export { action } from "./core/action.js";
|
|
13
|
+
// ── Runs ───────────────────────────────────────────────────────────────────
|
|
14
|
+
export { run } from "./core/run.js";
|
|
15
|
+
// ── Spin (linear orchestration) ──────────────────────────────────────────────
|
|
16
|
+
export { spin } from "./core/spin.js";
|
|
17
|
+
// ── Events ─────────────────────────────────────────────────────────────────
|
|
18
|
+
export { events } from "./core/events.js";
|
|
19
|
+
// ── Child processes ────────────────────────────────────────────────────────
|
|
20
|
+
export { createProc } from "./core/process.js";
|
|
21
|
+
// ── The log ────────────────────────────────────────────────────────────────
|
|
22
|
+
export { LogsCollector } from "./core/log-collector/LogsCollector.js";
|
|
23
|
+
export { log } from "./core/log-collector/global.js";
|
|
24
|
+
// ── Snapshots ──────────────────────────────────────────────────────────────
|
|
25
|
+
export { snapshot, captureSnapshot } from "./core/output.js";
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "omkit",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A tiny runtime for developer workflows: typed actions that pass runtime capabilities and emit typed events, under one run and one shared log. The operational/runtime layer to tskb's knowledge layer.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"LICENSE"
|
|
11
|
+
],
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./actions": {
|
|
18
|
+
"types": "./dist/actions/index.d.ts",
|
|
19
|
+
"import": "./dist/actions/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc",
|
|
24
|
+
"dev": "tsc --watch",
|
|
25
|
+
"clean": "rimraf dist",
|
|
26
|
+
"typecheck": "tsc --noEmit",
|
|
27
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
28
|
+
},
|
|
29
|
+
"author": "Dimitar Mihaylov",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/mitk0936/tskb.git",
|
|
34
|
+
"directory": "packages/omkit"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=20.11"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"typescript",
|
|
41
|
+
"orchestration",
|
|
42
|
+
"actions",
|
|
43
|
+
"simulation",
|
|
44
|
+
"pipeline",
|
|
45
|
+
"process",
|
|
46
|
+
"watch",
|
|
47
|
+
"logging",
|
|
48
|
+
"developer-tools"
|
|
49
|
+
],
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"playwright-core": "^1.49.0",
|
|
52
|
+
"zx": "^8.8.5"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/node": "^24",
|
|
56
|
+
"rimraf": "^6.0.1",
|
|
57
|
+
"typescript": "^5.9.3"
|
|
58
|
+
}
|
|
59
|
+
}
|