/** * PARITY-SPOT-WORKFLOW B5/F2 (CC pretty.js:449105-449141 + `Pqi` :149631) — the script-persistence seam behind * the Workflow tool's `scriptPath`/`name` calling surface. CC persists EVERY invocation's script under the * session directory and returns the path in the tool result, so the model iterates by EDITING THE FILE and * re-invoking with `{scriptPath}` instead of resending the whole script; `{name}` resolves a saved workflow. * * Core is deployment-neutral: the tool takes this seam via `RunWorkflowToolDeps.scriptStore` (optional — when * absent, `scriptPath`/`name` calls get an honest structured error and inline `script` works as before). The * file-backed implementation below is the TOC default (mirrors CC's session-dir posture: dir 0o700 / file * 0o600, best-effort persist that never blocks a launch). */ /** * design/140 §6 1a — a named-registry entry's RESOLVED form: the script source plus the registration's * `defaultArgs` layer (the middle tier of the merge chain: call-time args > registered defaultArgs > * script-internal fallbacks). A registry that carries no defaults may keep returning a bare string. */ export interface NamedWorkflowResolution { script: string; /** Registration-time default args (a JSON value — this is where a control-plane/center下发的默认 lands). * Merged UNDER the call-time args by {@link mergeWorkflowArgs} at tool-resolve time (parse-time snapshot: * the run receives the merged VALUE; nothing re-queries the registry after launch). */ defaultArgs?: unknown; /** * 团队通道 [426] CORE-1 — the top-level key a BARE STRING call-time arg normalizes into, so the "裸 string = * " ergonomic entry (published by the built-in `team-discussion` script: a bare string args IS the * topic) composes with a registered object `defaultArgs` instead of colliding with it. When a `{name}` call * passes a raw string AND this resolution carries an object `defaultArgs`, the tool wraps the string as * `{ [stringArgKey]: }` BEFORE the object merge (see {@link normalizeStringArg} / the run-workflow * tool's resolve path). Defaults to `"topic"` (the built-in ergonomic contract). Ignored when `defaultArgs` * is not a plain object (a bare string then reaches the script verbatim — pre-[426] behavior preserved). */ stringArgKey?: string; } /** * design/140 §6 1b — one row of the named-workflow LISTING projection (the LLM-facing consumption face of * `meta.whenToUse`). Mirrors the agents-side roster entry (subagent.ts `agentWhenToUseText`/CC `tIl`): * `whenToUse` is shown when present, else `description`. */ export interface NamedWorkflowListing { name: string; description?: string; whenToUse?: string; } export interface WorkflowScriptStore { /** Persist THIS invocation's resolved script, keyed by its runId. Returns the persisted path (what the tool * reports back to the model). Failures should throw — the tool treats persistence as best-effort. */ persist(runId: string, script: string): Promise | string; /** Read a previously persisted script back. MUST refuse paths outside the store (the argument is * model-supplied — containment is the store's contract, not the tool's). */ load(scriptPath: string): Promise | string; /** Resolve a SAVED workflow name to its script source (undefined = unknown name). Optional — a deployment * without a named registry simply omits it. May return either the bare script source (legacy/simple form) * or a {@link NamedWorkflowResolution} carrying the registration's `defaultArgs` (design/140 §6 1a). A * deployment entry of the SAME NAME as a built-in workflow SHADOWS the built-in (design/140 §6 1c). */ resolveName?(name: string): Promise | string | NamedWorkflowResolution | undefined; /** * design/140 §6 1b — enumerate the registry's SAVED workflows for the listing projection (tool card / * roster faces). Optional: a store without a stable name registry omits it (the file store below does — * its directory mixes per-run persisted scripts with saved names, so enumeration would advertise every * past run as a "named workflow"). NOTE: only a SYNCHRONOUS return reaches the statically-built Workflow * tool card; an async store should precompute if it wants card visibility. */ list?(): NamedWorkflowListing[] | Promise; } /** * design/140 §6 1a — the default-args merge: **call-time args > registered defaultArgs** (the script's own * internal fallbacks remain the third tier, applied by the script itself). Semantics (locked by test): * - both sides plain objects → SHALLOW top-level merge (`{...defaults, ...call}`): a top-level key present in * the call args wins WHOLESALE — nested objects/arrays/scalars are replaced, never deep-merged; * - call args absent (`undefined`) → the registered defaults verbatim; * - call args a non-object (array / scalar / null) → the call args win wholesale (no structural mixing). * Pure value-in/value-out: the caller snapshots the RESULT into the run (parse-time discipline, design/140 §2 — * a resume replay never re-queries the registry; a post-launch registry change cannot reach an in-flight run). */ export declare function mergeWorkflowArgs(callArgs: unknown, defaultArgs: unknown): unknown; /** * 团队通道 [426] CORE-1 — NORMALIZE a bare-string call-time arg into `{ [key]: }` so the published * "裸 string = " ergonomic entry (built-in `team-discussion`: bare string args IS the topic) COMPOSES * with a registered object `defaultArgs` instead of colliding with it. * * The bug it fixes: {@link mergeWorkflowArgs}'s non-object branch lets a bare string win WHOLESALE — so a * named workflow whose registration carries object `defaultArgs` (center 配的 members/rounds/finalizer) had * its whole defaults block silently wiped the moment a caller used the ergonomic `{name, args: ""}` * form, and the collab template quietly ran as a generic advocate/skeptic. Wrapping the string here lets the * subsequent object merge preserve the defaults AND honor the topic. * * Applied ONLY when BOTH hold (otherwise return `callArgs` untouched — pre-[426] behavior byte-preserved): * - `callArgs` is a string (the ergonomic form), AND * - `defaultArgs` is a PLAIN OBJECT (there ARE object defaults to merge under; with no/scalar defaults a bare * string must still reach the script verbatim — the built-in's own `raw === "string"` fallback handles it). * `key` is the resolution's `stringArgKey` (a registry may declare which key its bare string maps to); the * caller passes the built-in default `"topic"` when the resolution omits it. */ export declare function normalizeStringArg(callArgs: unknown, defaultArgs: unknown, key?: string): unknown; /** * File-backed {@link WorkflowScriptStore}: scripts land as `/.js`; `resolveName` reads * `/.js` (same directory — a saved workflow is just a script file someone/some run left there). */ export declare function createFileWorkflowScriptStore(dir: string): WorkflowScriptStore; //# sourceMappingURL=workflow-script-store.d.ts.map