/**
 * ============================================================
 *  src/workflows/types.ts —— workflow runner 核心类型
 * ------------------------------------------------------------
 *  ralph-loop 让 LLM 自规划；workflow 反过来 —— 外层确定性 step 列表
 *  驱动执行，LLM 只在 llm: / skill: 节点出场。本文件定义 YAML 解析
 *  后的内存形态（WorkflowDef / StepDef），以及运行时上下文（VarStack /
 *  RunContext）和 UI 事件（WorkflowEvent）。
 *
 *  与 src/types.ts 关系：WorkflowEvent 是插件**私有**事件，结构上满足
 *  framework 的 PluginEvent 开放契约（type: string + 任意 payload），
 *  经 plugin.ts -> pluginRunner 原样透传给 UI；UI 不识别即静默忽略。
 *  src/types.ts 的 LoopEvent union **不**包含 workflow_*，框架零插件耦合。
 * ============================================================
 */
// ---------------- 2. 变量栈（loop scope 用） ----------------
/**
 * 简单的多帧变量栈：
 *   - 最外层（frame 0）放 inputs + 全局变量
 *   - 进入 loop 时 push() 新帧，存当前迭代的 as / as_idx
 *   - 退出 loop 时 pop()
 *
 * get(key) 从栈顶往下找第一个匹配的 frame，类似 JS 的 lexical scope。
 */
export class VarStack {
    frames = [{}];
    set(key, val) {
        this.frames[this.frames.length - 1][key] = val;
    }
    /** 写到栈底（root frame），用于 inputs / 全局常量 */
    setGlobal(key, val) {
        this.frames[0][key] = val;
    }
    get(key) {
        for (let i = this.frames.length - 1; i >= 0; i--) {
            if (key in this.frames[i])
                return this.frames[i][key];
        }
        return undefined;
    }
    has(key) {
        for (let i = this.frames.length - 1; i >= 0; i--) {
            if (key in this.frames[i])
                return true;
        }
        return false;
    }
    push() {
        this.frames.push({});
    }
    pop() {
        if (this.frames.length > 1)
            this.frames.pop();
    }
    /** ADR-05: parallel 用——给子 fork 一份深拷贝栈；子 fork 的 set/push/pop 不污染父栈。 */
    fork() {
        const child = new VarStack();
        child.frames = this.frames.map((f) => ({ ...f }));
        return child;
    }
    /** 合并所有帧为一个普通对象（外层覆盖内层），用于 vars 持久化与事件 */
    snapshot() {
        return Object.assign({}, ...this.frames);
    }
}
