@orkestrel/workflow 0.0.3 → 0.0.5

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.
@@ -1844,6 +1844,91 @@ var Workflow = class {
1844
1844
  }
1845
1845
  };
1846
1846
  //#endregion
1847
+ //#region src/core/WorkflowManager.ts
1848
+ /**
1849
+ * The store-backed registry of {@link WorkflowInterface}s keyed by `id`, in insertion order —
1850
+ * the additive manager tier mirroring the `@orkestrel/agent` line's `ConversationManager` /
1851
+ * `WorkspaceManager`. Event-free (a registry, like its twins); the observability lives on each
1852
+ * {@link WorkflowInterface}.
1853
+ *
1854
+ * @remarks
1855
+ * - **Registry.** Workflows live in an insertion-ordered `Map` keyed by `id`. `add(definition)`
1856
+ * mints a live {@link WorkflowInterface} through {@link createWorkflow} (flowing the manager's
1857
+ * `functions` registry in) and stores it under `definition.id` — an already-present id
1858
+ * OVERWRITES (last write wins). `count` is the map size, `workflow(id)` looks one up,
1859
+ * `workflows()` lists them in insertion order.
1860
+ * - **Durable open / save.** `open(id)` returns an already-registered workflow directly; on a
1861
+ * registry MISS with a `store` set it rehydrates through {@link restoreWorkflow} (flowing the
1862
+ * manager's `functions` registry in so the rehydrated tree is RUNNABLE), registers it, and
1863
+ * returns it — lenient (`undefined`) with no store or a store miss. `save(id)` persists a
1864
+ * registered workflow's `snapshot()` to the `store` — lenient (`false`) with no store or an
1865
+ * unknown id.
1866
+ * - **Removal.** `remove` drops one by id, or a batch (§9.2, array overload FIRST) — `true` when
1867
+ * any was removed. `clear` empties the registry.
1868
+ * - **No active pointer.** Unlike its `ConversationManager` / `WorkspaceManager` twins, there is
1869
+ * no `active` / `switch` — nothing in the workflow domain renders "the current workflow".
1870
+ *
1871
+ * @example
1872
+ * ```ts
1873
+ * const manager = new WorkflowManager({
1874
+ * functions: { compile: async (controller) => `built ${controller.task.id}` },
1875
+ * })
1876
+ * const workflow = manager.add(definition) // minted, registered, RUNNABLE
1877
+ * manager.workflow(workflow.id) // the same workflow
1878
+ * manager.count // 1
1879
+ * ```
1880
+ */
1881
+ var WorkflowManager = class {
1882
+ #workflows = /* @__PURE__ */ new Map();
1883
+ #functions;
1884
+ #store;
1885
+ constructor(options) {
1886
+ this.#functions = options?.functions;
1887
+ this.#store = options?.store;
1888
+ }
1889
+ get count() {
1890
+ return this.#workflows.size;
1891
+ }
1892
+ workflow(id) {
1893
+ return this.#workflows.get(id);
1894
+ }
1895
+ workflows() {
1896
+ return [...this.#workflows.values()];
1897
+ }
1898
+ add(definition) {
1899
+ const workflow = createWorkflow(definition, { functions: this.#functions });
1900
+ this.#workflows.set(workflow.id, workflow);
1901
+ return workflow;
1902
+ }
1903
+ async open(id) {
1904
+ const existing = this.#workflows.get(id);
1905
+ if (existing !== void 0) return existing;
1906
+ if (this.#store === void 0) return void 0;
1907
+ const snapshot = await this.#store.get(id);
1908
+ if (snapshot === void 0) return void 0;
1909
+ const workflow = restoreWorkflow(snapshot, { functions: this.#functions });
1910
+ this.#workflows.set(workflow.id, workflow);
1911
+ return workflow;
1912
+ }
1913
+ async save(id) {
1914
+ const workflow = this.#workflows.get(id);
1915
+ if (this.#store === void 0 || workflow === void 0) return false;
1916
+ await this.#store.set(workflow.snapshot());
1917
+ return true;
1918
+ }
1919
+ remove(ids) {
1920
+ if ((0, _orkestrel_contract.isArray)(ids)) {
1921
+ let removed = false;
1922
+ for (const id of ids) if (this.#workflows.delete(id)) removed = true;
1923
+ return removed;
1924
+ }
1925
+ return this.#workflows.delete(ids);
1926
+ }
1927
+ clear() {
1928
+ this.#workflows.clear();
1929
+ }
1930
+ };
1931
+ //#endregion
1847
1932
  //#region src/core/Controller.ts
1848
1933
  /**
1849
1934
  * The per-unit handle a runner handler receives — wraps the unit's identity,
@@ -2805,6 +2890,40 @@ function createWorkflowRunner(options) {
2805
2890
  return new WorkflowRunner(options?.scheduler ?? createScheduler());
2806
2891
  }
2807
2892
  /**
2893
+ * Create a {@link WorkflowManagerInterface} — the store-backed registry of
2894
+ * {@link WorkflowInterface}s, the additive manager tier mirroring the `@orkestrel/agent`
2895
+ * line's `createConversationManager` / `createWorkspaceManager`.
2896
+ *
2897
+ * @remarks
2898
+ * `options.functions` flows into every workflow the manager mints (`add`, via
2899
+ * {@link createWorkflow}) or hydrates (`open`'s registry-miss path, via
2900
+ * {@link restoreWorkflow}), so a hydrated workflow is RUNNABLE rather than a dead snapshot
2901
+ * mirror. `options.store` is the EXACT analogue of the twins' `store` seam — omitted ⇒ the
2902
+ * manager is registry-only (`open` resolves only what is registered, `save` is a no-op). This
2903
+ * is PURELY ADDITIVE: direct {@link WorkflowStoreInterface} use and
2904
+ * {@link restoreWorkflow} remain valid — the manager is one more caller-driven persistence
2905
+ * seam, not a replacement.
2906
+ *
2907
+ * @param options - The optional `store` seam and the `functions` registry threaded into every mint/hydrate
2908
+ * @returns A working {@link WorkflowManagerInterface}
2909
+ *
2910
+ * @example
2911
+ * ```ts
2912
+ * import { createMemoryWorkflowStore, createWorkflowManager } from '@src/core'
2913
+ *
2914
+ * const manager = createWorkflowManager({
2915
+ * store: createMemoryWorkflowStore(),
2916
+ * functions: { compile: async (controller) => `built ${controller.task.id}` },
2917
+ * })
2918
+ * const workflow = manager.add(definition) // minted, registered, RUNNABLE
2919
+ * await manager.save(workflow.id) // persisted to the store
2920
+ * const reopened = await manager.open(workflow.id) // already registered — no store hit
2921
+ * ```
2922
+ */
2923
+ function createWorkflowManager(options) {
2924
+ return new WorkflowManager(options);
2925
+ }
2926
+ /**
2808
2927
  * Create the safe cross-environment cooperative-yield default — a
2809
2928
  * {@link SchedulerInterface} built on `setTimeout` / `clearTimeout` alone, so it
2810
2929
  * runs unchanged in both the browser and Node.
@@ -2915,6 +3034,7 @@ exports.TaskManager = TaskManager;
2915
3034
  exports.WORKFLOW_STATUSES = WORKFLOW_STATUSES;
2916
3035
  exports.Workflow = Workflow;
2917
3036
  exports.WorkflowError = WorkflowError;
3037
+ exports.WorkflowManager = WorkflowManager;
2918
3038
  exports.WorkflowRunner = WorkflowRunner;
2919
3039
  exports.assertSnapshot = assertSnapshot;
2920
3040
  exports.buildPhaseContext = buildPhaseContext;
@@ -2929,6 +3049,7 @@ exports.createRunner = createRunner;
2929
3049
  exports.createScheduler = createScheduler;
2930
3050
  exports.createWorkflow = createWorkflow;
2931
3051
  exports.createWorkflowContract = createWorkflowContract;
3052
+ exports.createWorkflowManager = createWorkflowManager;
2932
3053
  exports.createWorkflowRunner = createWorkflowRunner;
2933
3054
  exports.definitionToSnapshot = definitionToSnapshot;
2934
3055
  exports.deriveBoundary = deriveBoundary;