omkit 0.0.5 → 0.0.6

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.
@@ -39,6 +39,12 @@ export interface ActionContext<Events extends object, Handle = void> extends Sys
39
39
  * one (e.g. CDP) follows the same pattern over `logs`/`signal`.
40
40
  */
41
41
  readonly proc: Proc;
42
+ /**
43
+ * Absolute path to this run's output folder (`logs/<name>/<date>/<time>/`) —
44
+ * created and shared across the run. Write action artifacts here so they land
45
+ * beside `run.log`; the same folder is on the `spin` context.
46
+ */
47
+ readonly artifactsFolder: string;
42
48
  }
43
49
  /** A constructed-but-not-yet-run action: what calling an `Action` produces. */
44
50
  export interface ActionInstance<Result = unknown, Events extends object = NoEvents, Handle = void> {
@@ -1,6 +1,7 @@
1
1
  import { events } from "./events.js";
2
2
  import { createProc } from "./process.js";
3
3
  import { fingerprint, read, write, resolvePaths } from "./folder-cache.js";
4
+ import { artifactsFolder } from "./output.js";
4
5
  /** A promise paired with its settlers, for the set-once handle. */
5
6
  const deferred = () => {
6
7
  let resolve;
@@ -82,7 +83,13 @@ const build = (name, exec) => {
82
83
  // `Promise.resolve().then` normalizes a sync result and routes a sync
83
84
  // throw to the `error` path, so exec may be sync or async.
84
85
  Promise.resolve()
85
- .then(() => exec({ ...system, emit, attach, proc: createProc(system.logs, system.signal) }, ...args))
86
+ .then(() => exec({
87
+ ...system,
88
+ emit,
89
+ attach,
90
+ proc: createProc(system.logs, system.signal),
91
+ artifactsFolder: artifactsFolder(),
92
+ }, ...args))
86
93
  .then((result) => {
87
94
  systemEmit("done", result);
88
95
  // Settle `ref` if the action finished without attaching, so awaiters
@@ -1,4 +1,13 @@
1
1
  import type { LogsCollector } from "./log-collector/LogsCollector.ts";
2
+ /**
3
+ * Absolute path to this run's output folder — `logs/<name>/<date>/<time>/`, where
4
+ * `run.log`, `run.jsonl`, and snapshots live. Exposed so actions can drop their
5
+ * own **artifacts** into the same per-run folder (one folder per run; one run per
6
+ * process). The folder is created on first access — synchronously, so a caller
7
+ * can write into it in the same tick — and the path is absolute so it's safe to
8
+ * hand to a child process with a different cwd.
9
+ */
10
+ export declare const artifactsFolder: () => string;
2
11
  /**
3
12
  * Drains the collected log to two files in the run's output folder (the common
4
13
  * `logs/<name>/<date>/<time>/` convention, local time):
@@ -1,4 +1,4 @@
1
- import { createWriteStream } from "node:fs";
1
+ import { createWriteStream, mkdirSync } from "node:fs";
2
2
  import { mkdir, writeFile } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { log } from "./log-collector/global.js";
@@ -24,6 +24,23 @@ const runDir = () => {
24
24
  };
25
25
  let made;
26
26
  const ensureDir = () => (made ??= mkdir(runDir(), { recursive: true }).then(() => { }));
27
+ let ensuredSync = false;
28
+ /**
29
+ * Absolute path to this run's output folder — `logs/<name>/<date>/<time>/`, where
30
+ * `run.log`, `run.jsonl`, and snapshots live. Exposed so actions can drop their
31
+ * own **artifacts** into the same per-run folder (one folder per run; one run per
32
+ * process). The folder is created on first access — synchronously, so a caller
33
+ * can write into it in the same tick — and the path is absolute so it's safe to
34
+ * hand to a child process with a different cwd.
35
+ */
36
+ export const artifactsFolder = () => {
37
+ const abs = path.resolve(runDir());
38
+ if (!ensuredSync) {
39
+ mkdirSync(abs, { recursive: true });
40
+ ensuredSync = true;
41
+ }
42
+ return abs;
43
+ };
27
44
  /** A compact header block for the top of run.log — legend + run identity. */
28
45
  const logHeader = () => {
29
46
  const now = new Date();
@@ -32,6 +32,12 @@ export interface SpinContext {
32
32
  readonly cancel: Run["cancel"];
33
33
  /** The run's abort signal — honor it to stop early. */
34
34
  readonly signal: AbortSignal;
35
+ /**
36
+ * Absolute path to this run's output folder (`logs/<name>/<date>/<time>/`),
37
+ * created up front. Hand it to actions (or use `ctx.artifactsFolder` inside
38
+ * one) to write artifacts beside `run.log`.
39
+ */
40
+ readonly artifactsFolder: string;
35
41
  }
36
42
  /** The body of a {@link spin}: any (async) function — it isn't named or wrapped by you. */
37
43
  export type SpinBody = (ctx: SpinContext) => void | Promise<void>;
package/dist/core/spin.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { action } from "./action.js";
2
2
  import { run } from "./run.js";
3
+ import { artifactsFolder } from "./output.js";
3
4
  export function spin(a, b) {
4
5
  const [options, body] = typeof a === "function" ? [{}, a] : [a, b];
5
6
  const { drain: autoDrain = true, ...runOptions } = options;
@@ -20,7 +21,13 @@ export function spin(a, b) {
20
21
  host.run(instance);
21
22
  return instance;
22
23
  };
23
- await body({ nod, drain: startDrain, cancel: () => host.cancel(), signal });
24
+ await body({
25
+ nod,
26
+ drain: startDrain,
27
+ cancel: () => host.cancel(),
28
+ signal,
29
+ artifactsFolder: artifactsFolder(),
30
+ });
24
31
  });
25
32
  host = run(runOptions, hosted());
26
33
  if (autoDrain)
package/dist/index.d.ts CHANGED
@@ -23,4 +23,5 @@ export type { Logger, LogEntry, LogInput, SubscribeOptions, } from "./core/log-c
23
23
  export { log } from "./core/log-collector/global.ts";
24
24
  export { snapshot, captureSnapshot } from "./core/output.ts";
25
25
  export type { SnapshotRef } from "./core/output.ts";
26
+ export { artifactsFolder } from "./core/output.ts";
26
27
  export { fingerprint, cacheDir } from "./core/folder-cache.ts";
package/dist/index.js CHANGED
@@ -23,6 +23,10 @@ export { LogsCollector } from "./core/log-collector/LogsCollector.js";
23
23
  export { log } from "./core/log-collector/global.js";
24
24
  // ── Snapshots ──────────────────────────────────────────────────────────────
25
25
  export { snapshot, captureSnapshot } from "./core/output.js";
26
+ // ── Artifacts ────────────────────────────────────────────────────────────────
27
+ // This run's output folder (absolute) — also on the `spin`/action `ctx`. Import
28
+ // it directly for artifact-writing helpers that aren't inside an action.
29
+ export { artifactsFolder } from "./core/output.js";
26
30
  // ── Folder cache ─────────────────────────────────────────────────────────────
27
31
  // Backs the `.withCache(...inputs)` method on instances (fingerprints an
28
32
  // action's input files/folders, not its outputs); exported for scripts that
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omkit",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
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
5
  "type": "module",
6
6
  "main": "./dist/index.js",