@hoplogic/hopjit 0.1.0

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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +99 -0
  3. package/dist/act-body-interpreter.d.ts +24 -0
  4. package/dist/act-body-interpreter.js +159 -0
  5. package/dist/act-body-parser.d.ts +10 -0
  6. package/dist/act-body-parser.js +577 -0
  7. package/dist/act-builtins.d.ts +12 -0
  8. package/dist/act-builtins.js +104 -0
  9. package/dist/ast-helpers.d.ts +26 -0
  10. package/dist/ast-helpers.js +58 -0
  11. package/dist/ast-runtime.d.ts +49 -0
  12. package/dist/ast-runtime.js +224 -0
  13. package/dist/ast-types.d.ts +260 -0
  14. package/dist/ast-types.js +4 -0
  15. package/dist/cli-types.d.ts +190 -0
  16. package/dist/cli-types.js +4 -0
  17. package/dist/cli.d.ts +26 -0
  18. package/dist/cli.js +623 -0
  19. package/dist/dispatcher.d.ts +92 -0
  20. package/dist/dispatcher.js +692 -0
  21. package/dist/doc-ref.d.ts +41 -0
  22. package/dist/doc-ref.js +214 -0
  23. package/dist/engine-traverse.d.ts +37 -0
  24. package/dist/engine-traverse.js +385 -0
  25. package/dist/engine.d.ts +141 -0
  26. package/dist/engine.js +1792 -0
  27. package/dist/errors.d.ts +47 -0
  28. package/dist/errors.js +34 -0
  29. package/dist/hoplog.d.ts +120 -0
  30. package/dist/hoplog.js +501 -0
  31. package/dist/parser.d.ts +7 -0
  32. package/dist/parser.js +802 -0
  33. package/dist/persistence.d.ts +60 -0
  34. package/dist/persistence.js +208 -0
  35. package/dist/prompt.d.ts +130 -0
  36. package/dist/prompt.js +1014 -0
  37. package/dist/provider-types.d.ts +134 -0
  38. package/dist/provider-types.js +3 -0
  39. package/dist/runtime-types.d.ts +84 -0
  40. package/dist/runtime-types.js +4 -0
  41. package/dist/tools.d.ts +16 -0
  42. package/dist/tools.js +141 -0
  43. package/dist/validator.d.ts +23 -0
  44. package/dist/validator.js +959 -0
  45. package/driver/codex/AGENTS.md +54 -0
  46. package/driver/hopskill-build/SKILL.md +137 -0
  47. package/driver/hopskill-build/references/spec-skeleton.md +132 -0
  48. package/driver/hopskill-build/references/step-type-cheatsheet.md +56 -0
  49. package/driver/hopskill-build/references/three-focus-rules.md +148 -0
  50. package/driver/hopspec-skill.md +187 -0
  51. package/driver/references/cli-discovery.md +36 -0
  52. package/driver/references/discovery.md +45 -0
  53. package/driver/references/driver-subagent.md +50 -0
  54. package/driver/references/parallel-worker.md +50 -0
  55. package/driver/references/step-execution-rules.md +47 -0
  56. package/package.json +52 -0
@@ -0,0 +1,187 @@
1
+ ---
2
+ name: hopspec
3
+ description: 驱动 HopStep 引擎执行 HopSpec 规约。CC 自身作为外层 LLM,hopjit CLI 管理执行状态和流控。
4
+ user_invocable: true
5
+ ---
6
+
7
+ %% @trace
8
+ id: hopspec-driver-skill
9
+ source: [[HopSpec V3配套HopJIT运行时能力]]
10
+ source_id: hopjit-runtime
11
+ type: intent
12
+ last_sync: 2026-07-08T00:52+0800
13
+ note: 复用模式 CC 驱动指令(源)。本 driver/ 目录是复用模式驱动指令的归属处,Codex 等其他 runtime 载体将来并列于此。部署副本=.claude/skills/hopspec/SKILL.md(开发期软链到本源,改源即生效)。节奏归引擎/caller 介入点契约见 source 的 ^anc-exec-engine-driver-roles / ^anc-exec-mode-invariants。2026-07-04 顶层驱动改造:主 agent 只编排介入点,执行段外包给 driver subagent(隔离主上下文,见 [[reuse-mode-prompt-flow]])。同日精简:subagent 模板 + 公共执行规则 + spec 发现前置外置 driver/references/(driver-subagent / parallel-worker / step-execution-rules / discovery),主体只留主 agent 编排 + 子命令表(303→181 行;消 list 与 §0 的 recent-dirs 重复)。同日 e2e 实测通过 + 修临时文件散落:driver/worker @file 临时文件改写 scratch_dir(随 .hopstate 隔离/清理),不再落项目根裸名污染 git。再修主 agent 抢跑:主 agent 全程不碰执行链(不自己 run/submit 执行步),run 也交首个 subagent(否则 advance 抢记首步 start → hoplog 重复块);主 agent 只 §0 前置 + 起 subagent + 处理介入点。2026-07-07 e2e 复跑(ppt-html work_zone 验证)暴露两处并固化:① for-each worker itemVar 通道简化——从"driver 手工从响应提取 params_for_child 拼 --params 透传"改为"引擎 fan-out 按 cid 落盘 + worker init 自动回填"(driver 零参与,parallel-worker.md 去掉 --params,见 design ^anc-exec-parallel-foreach-worker);② doc-ref 工作目录——doc-ref 按 CLI 进程 cwd 解析且 subagent Bash 命令间重置 cwd,故 worker/driver subagent 每条 node 命令前置 `cd <VAULT> &&` 锁 cwd(唯一允许的链式,driver-subagent/parallel-worker/step-execution-rules 同步)。2026-07-08 fan-out 调度代码化:满额窗口/补位/命令拼装从 skill NL 移进无状态 CLI 顾问(fanout-plan/fanout-next),主 agent 退为句柄执行器(起 subagent+收通知,照 CLI 给的 launch_command 原样执行、零调度计算)。载体决策依实测:专职调度 subagent 因"idle 即完成"跨窗口丢早批通知不可行,只有主 agent 稳定持句柄(design ^anc-exec-parallel-fanout-advisor)。结构性消除忘 --params/漏 cd/串台/重复派发。parallel-worker.md 改写为调顾问+照做
14
+ %%
15
+
16
+ # /hopspec — 驱动 HopStep 执行 HopSpec 规约
17
+
18
+ 子命令:`run <spec> [--params]` 执行 · `list` 列出可用 spec · `status` 查进度 · `resume` 恢复。
19
+
20
+ 驱动 HopStep 执行引擎(hopjit CLI)执行一个 HopSpec 规约文件。CC 自身作为推理 LLM,hopjit 管理执行状态、变量存储、retry/adaptive、None 传播等流控。
21
+
22
+ ## 前置条件
23
+
24
+ - `hopjit` CLI 可用(全局 `npm i -g hopjit` / 项目内 `npm i hopjit` / 开发期 `npm link` 或本地 `npm run build`)
25
+ - 如需 LLM 调用(reason/check 步骤由 dispatcher 内部执行时,即 standalone 模式):环境变量 `ANTHROPIC_AUTH_TOKEN` 或 `ANTHROPIC_API_KEY` 已设置。**复用模式(CC 当推理 LLM)不需要 API key。**
26
+
27
+ > **🔴 启动最前:CLI 自举探测**。skill 分发到任意项目后 hopjit 位置不定,故本 skill 用两个探测变量而非硬编码路径:
28
+ > - **`<CLI>`** = hopjit 调用前缀(`hopjit` 或 `node <abs>/cli.js`)
29
+ > - **`<PKG>`** = hopjit 包根(放 driver/、examples/ 的目录)
30
+ >
31
+ > 主 agent 在 `run`/`list` 等任何动作**之前**跑一次探测(四级:全局命令 → 项目 node_modules → 包内 dist → 开发期 fallback),固化这两个变量,后续全用它们。**探测算法见 `driver/references/cli-discovery.md`**(探到 `<PKG>` 后,本文档下方所有 `<PKG>/...` 引用即可定位)。
32
+
33
+ ## 琐碎子命令:list / status / resume
34
+
35
+ `/hopspec run` 是主体(下方执行流程)。其余三个各自简单:
36
+
37
+ - `/hopspec list [目录]` — 列出可执行 spec 供挑选。完整流程 + recent-dirs LRU 见 `<PKG>/driver/references/discovery.md`。
38
+ - `/hopspec status` — 跑 `<CLI> status --state-dir .hopstate [--instance <id>]`,展示进度 JSON。
39
+ - `/hopspec resume` — 跑 `<CLI> resume --state-dir .hopstate [--instance <id>]`,recover + 推进到下一介入点/终态,回主编排循环(§2)分派。
40
+
41
+ ## 执行流程
42
+
43
+ ### 0. 前置:定位 spec + 组装 params
44
+
45
+ `run` 前先定位 spec 文件、组装 `--params`——完整流程(spec 搜索、recent-dirs 维护、读 `## Inputs` 推断参数 + AskUserQuestion 确认)见 `<PKG>/driver/references/discovery.md`。这是 run 的**必要前置交互**,不属"自主展开"。
46
+
47
+ ### 1. 启动 + 驱动姿态(主 agent 编排,执行段外包 subagent)
48
+
49
+ **核心姿态(本 skill 的关键设计)**:`/hopspec run` 下,**主 agent(你)只做编排者,全程不碰执行链**——不自己调 `run`/`submit`(`run` 的 advance 会抢记首步 start → hoplog 重复;执行链全归 subagent)。你只:① 做 §0 前置(定位 spec + 组装 params,含问人);② **起 driver subagent 跑执行段**;③ 处理 subagent 冒泡回的**介入点**(paused 问人 / parallel fan-out / adaptive replan / 终态)。执行段每步累积 context 是"哑应答体"式机械搬运,放 subagent 独立窗口跑,主上下文只留介入点 + 摘要,不被污染。与 parallel worker 同范式,只是推广到顶层。
50
+
51
+ **启动**:§0 备好 spec 绝对路径 + params JSON 后,**起首个 driver subagent**(`Agent` 工具,prompt 模板见 `<PKG>/driver/references/driver-subagent.md`,填入 `<CLI>` 绝对路径 + `<STATE>` + `<SPEC>` + `<PARAMS>`)。subagent 自己跑 `run` 作首步(首个 `recordStepStart` 归它,不抢跑),跑到介入点/终态返回 JSON + **instance_id** + 摘要。**你记住它回报的 instance_id**——后续介入点注入用它。
52
+
53
+ **执行节奏归引擎**:主 agent 与 subagent 都**不主动推进**——只在引擎给的介入点应答。
54
+
55
+ **⚠️ Bash 命令纪律(硬约束,主 agent 与 subagent 都遵守)**:
56
+ - **每条 Bash 调用只做一件事**:不链式(`&&`)、不管道(`|`)、不变量赋值
57
+ - **直接写完整命令**:`<CLI> <子命令> <参数>`,不缩写、不 `$HOPJIT`
58
+ - **自己读 JSON**:CLI 返回 JSON 到 stdout,直接读懂按 `status` 分派,不 `| python3 -c` / `| node -e` 提取
59
+ - **理由**:管道到解释器触发 pipe_guard hook 弹框打断;直接命令走 `Bash(node *)` 预授权零弹窗
60
+
61
+ > 主 agent 自己**只**跑 §2 paused/adaptive 的 `submit_and_fetch_next --answer/--replan`(注入问人结果),**不跑 run、不跑执行步的 submit**。
62
+ > **不要 `rm -rf .hopstate`**——run 在 state-dir 下创建带唯一 instance_id 的新实例,旧实例不干扰。需要干净环境时用新的 `--state-dir` 名。
63
+
64
+ ### 2. 主 agent 编排循环(你只处理介入点)
65
+
66
+ 首个 subagent 返回后拿到 JSON(+ instance_id),按 `status` 分派。**编排循环**:处理完一个介入点 → 拿到下一步 JSON → 再分派,直到终态。
67
+
68
+ #### `step_ready` → **起 driver subagent 跑执行段**(你从不自己 run/submit 执行步)
69
+
70
+ step_ready 意味着一段**纯执行**(连续 reason/check/act/commit)。**用 `Agent` 工具起一个 driver subagent** 跑它——prompt 模板见 `<PKG>/driver/references/driver-subagent.md`:
71
+ - **首个执行段**:起首个 subagent 从 `run` 起(传 `<SPEC>` + `<PARAMS>`),它跑 run + 后续 submit 循环,回报 instance_id。
72
+ - **介入点后续接**(paused/adaptive 注入后又是 step_ready):起**续接 subagent** 从 `<INST>` 继续(传主 agent 记住的 instance_id)。
73
+
74
+ subagent **一直跑到下一个介入点**(paused / parallel_ready / adaptive_needed)或**终态**(completed / failed)才停,把那个 JSON + 摘要返回给你 → **回本编排循环继续分派**。
75
+
76
+ > 主 agent **从不自己 run、也不自己 submit 执行步**——那正是要外包的、且抢跑会污染 hoplog。你只在 subagent 返回介入点后接手。执行细则在 `references/step-execution-rules.md`,subagent 自会引用。
77
+
78
+ #### `paused` → **必须停下问人,禁止自己替答**(主 agent 专属)
79
+
80
+ ⚠️ **硬约束(违反即错误)**:paused 是 spec 作者**显式声明的介入点**——作者特意放了 confirm/ask,就是要**外部决策者**(人)来定。你**必须**用 `AskUserQuestion` 展示问题、等用户回答,**禁止**自己推理出答案就 submit。(这也是为什么 paused 归主 agent 而非 subagent——subagent 无权、也无法问真人。)
81
+
82
+ 按 `pause_reason` 分派:
83
+
84
+ **`confirm`(审批闸门)→ 必须问人批不批**:
85
+ 1. **必须**用 `AskUserQuestion` 展示 `presented_data.question` + `response_options`(approve/reject),等用户选
86
+ 2. 用户选定后注入(**带 `--instance <id>` 跨进程定位**):
87
+ ```bash
88
+ <CLI> submit_and_fetch_next <step_id> --answer '{"value":"<用户选择>"}' --state-dir .hopstate --instance <instance_id>
89
+ ```
90
+ 3. approve→映射 bool true;reject→全局中止。**禁止**自己判断该不该批
91
+ 4. 注入后拿到下一步 JSON → **回编排循环分派**(若又是 step_ready → 起新 subagent 续)
92
+
93
+ **`ask`(数据收集)→ 必须问人要值**:
94
+ 1. **🔴 呈交硬约束(present_inputs)**:若 `presented_data.present_inputs` **非空**(如 `["raw_outline", "draft"]`),你**必须**在调 `AskUserQuestion` **之前**先用普通 text 消息(markdown 段落/引用块/代码块)把 `context` 里这些字段的**原文完整 dump** 给用户——**禁止**只给标签、省略号或摘要后就问。这是 spec 作者显式声明的"必须看完才能答"的呈现契约(见 design ^anc-exec-hitl-presentation),缩略 = 让用户在没看清的状态下拍板,**等于违反 ask 语义**。
95
+
96
+ **`context` 字段两种形态**(人通道 ^anc-exec-deflate):
97
+ - **原值**(小于 5K 字符):直接是字符串/对象,原样 dump 即可,长内容用 ` ``` ` 围栏避免被 markdown 渲染破坏
98
+ - **`{$file, preview}` 复合**(≥ 5K 字符,引擎自动卸载):preview = 头 5K 字符 + "...[完整内容见文件]"。你**必须**完整 dump preview 给 user(已经是 user 可读量),**并提示** "完整内容见 `{$file 路径}`",让 user 知完整在哪。user 想看完整时你 `Read` 文件再展示
99
+
100
+ **禁止二次摘要**:preview 已经是引擎按"人友好阈值"卸载的产物,你不应再压缩它。**省略 `present_inputs`** 时按现行行为(可缩略提示)。
101
+ 2. **必须**用 `AskUserQuestion` 展示 `presented_data.question`,并把 `output_schema`(要填的变量+类型)、`default_value`(前序推断默认值)、`context`(候选来源)一并呈现给用户
102
+ 3. 选项构造:若有推断默认值,第一项给"采用默认:<default_value>";再列其它候选(来自 context);用户可选"Other"自由填
103
+ 4. 用户给值后注入(用用户提供的**真实值**,不是 approve;带 `--instance`):
104
+ ```bash
105
+ <CLI> submit_and_fetch_next <step_id> --answer '{"value":"<用户提供的真实数据值>"}' --state-dir .hopstate --instance <instance_id>
106
+ ```
107
+ **值大时(如整份大纲/草稿)**:把 `{"value":"..."}` 整个写到 paused 响应给的 `work_zone` 目录下(如 `<work_zone>/answer_<step_id>.json`),再整包 `--answer @<work_zone>/answer_<step_id>.json`。`@` 只贴 `--answer` 参数最前面,绝不写进 JSON 字段值;只写 work_zone、不写 /tmp。
108
+ 5. **禁止**把 approve 当数据值——ask 要的是业务值(如"技术规范"),不是审批信号。用户若想采用默认,把 default_value 的真实内容作为 value 注入
109
+ 6. 注入后拿到下一步 JSON → **回编排循环分派**
110
+
111
+ > **例外**:`require_human: false`(未强制真人)且问题确实可由上下文无歧义推断时,才允许主 agent 代答——但 confirm/ask 默认倾向问人,拿不准就问。`require_human: true` 时**绝对必须**真人回答,零例外。
112
+
113
+ #### `adaptive_needed` → 重规划(主 agent)
114
+ 读失败上下文(`failure.reason` + `subtask_contract`),生成新步骤 markdown,提交(带 `--instance`):
115
+ ```bash
116
+ <CLI> submit_and_fetch_next <subtask_id> --replan '<新步骤 markdown>' --state-dir .hopstate --instance <instance_id>
117
+ ```
118
+ 返回值即重规划后的下一步 → **回编排循环分派**。
119
+
120
+ #### `completed` → 展示最终 outputs,结束
121
+ ```
122
+ 执行完成。输出:
123
+ {outputs 内容}
124
+ ```
125
+
126
+ #### `failed` → 展示失败信息,结束
127
+ ```
128
+ 执行失败。步骤 {failed_step_id}:{failure_reason}
129
+ ```
130
+
131
+ #### `parallel_ready` → 并行 fan-out(主 agent 编排)
132
+
133
+ 主 agent 是唯一 fan-out 编排者。fan-out 流程 + worker prompt 模板见 `<PKG>/driver/references/parallel-worker.md`:读 `children[]`(引擎已排除含 confirm 子树,直接全 fan-out)→ **满额滑动窗口调度**(后台 worker:初始起 `max_concurrent` 个,任一完成就立即补起下一个,始终保持满额,批间无屏障)→ 全部返回后 `join_parallel` → 拿下一步 JSON **回本编排循环分派**。
134
+
135
+ > driver subagent 遇 parallel_ready **不自己 fan-out**,冒泡回主 agent 由此处理——避免 subagent 内再嵌 subagent。worker(驱动一棵 child 子树)与 driver subagent(驱动顶层执行段)是同范式两种粒度。
136
+
137
+ ### 3. 异常处理
138
+
139
+ > 执行段异常主要由 driver subagent 就地处理(模板已含 SCHEMA_MISMATCH 重试、步骤失败 `--failure`,细则见 `references/step-execution-rules.md`)。主 agent 侧共通规则:
140
+
141
+ - hopjit 命令返回非零 exit code → 读 stderr,报告错误。
142
+ - `submit_and_fetch_next` 返回 `SCHEMA_MISMATCH` → 输出不符 schema,修正后重 submit 同一步(引擎未推进)。
143
+ - 全部 retry 耗尽 → 引擎自动传播 fail,submit 最终返回 `failed`(subagent 冒泡回主 agent 报告)。
144
+
145
+ > **调试用** `<CLI> debug_step`(推进一步、不消化、不自动推进)——仅人工逐步排查时用,正常驱动只用 run + submit_and_fetch_next。
146
+
147
+ ## 进度展示
148
+
149
+ 执行段在 driver subagent 内,主 agent 不再逐步显示每步——**主 agent 在介入点粒度报进度**:subagent 返回时把它带回的执行摘要转述一行,再报当前介入点/终态。
150
+ ```
151
+ ▸ 已执行 N 步至 <介入点/终态>(<subagent 执行摘要>)
152
+ ```
153
+ subagent 内部**自己**可按需简报每步(`✓ Step {step_id} [{step_type}] {summary}`),但那些留在 subagent 窗口、不进主对话——这正是隔离主上下文的目的。
154
+
155
+ ## 输出纪律(硬约束)
156
+
157
+ `/hopspec run` 的职责是**驱动执行 + 报告结果**,不是借机做研究。输出严格限于:
158
+ 1. 每步一行进度(如上 `✓ Step ...`,被引擎消化的步骤无需逐行报)
159
+ 2. 终态结果:`执行完成。输出:\n {outputs}` 或 `执行失败。步骤 X:{reason}`
160
+
161
+ **禁止**:未经要求就翻 hoplog/state.json、做多次运行对比、写根因分析表格、长篇解释引擎内部行为。
162
+ - 引擎"一次返回 completed"是**正常优化**(纯计算 body 被引擎消化,节奏归引擎,见 `^anc-exec-advance-to-caller`),**不是异常**,不要为此展开调查。
163
+ - **例外(允许且应做)**:第 0 节的 spec 定位与参数组装确认是**必要前置交互**,不属"自主展开"——run 之前该搜 spec、读 Inputs、组装参数并经 AskUserQuestion 确认。纪律约束的是**执行过程与执行后**的多余分析,不是启动前的准备。
164
+ - 确有疑点(如 status 非预期、报错),**一句话指出**即可,需要深查先问用户,不自主展开。
165
+
166
+ ## 约束
167
+
168
+ - `.hopstate/` 目录存放执行状态,应加入 `.gitignore`
169
+ - 不要修改 spec 文件本身——执行过程只读 spec,状态全在 .hopstate
170
+ - reason/check 步骤:CC 直接推理,不再额外调 LLM API(避免双重收费)
171
+ - act/commit 步骤:有 hop_python body 则**严格按 body 执行、不自由发挥**(执行期无推理);无 body 才按自然语言描述用工具执行。操作范围受 spec 中 SandboxConfig 约束
172
+
173
+ ## 示例
174
+
175
+ ```bash
176
+ # 执行一个数据质量评估 spec
177
+ /hopspec run <PKG>/examples/data-quality.md
178
+
179
+ # 带参数执行
180
+ /hopspec run my-spec.md --params '{"input_data": "data.csv", "threshold": 0.8}'
181
+
182
+ # 查看进度
183
+ /hopspec status
184
+
185
+ # 从中断恢复
186
+ /hopspec resume
187
+ ```
@@ -0,0 +1,36 @@
1
+ # CLI 自举探测(`<CLI>` / `<PKG>` 定位)
2
+
3
+ > hopspec skill 分发到任意项目后,hopjit 引擎可能装在不同位置(全局 npm / 项目 node_modules / 开发期本地 dist)。主 agent 在 `/hopspec run` 或 `/hopskill-build` **启动最前**跑一次探测,把结果固化为两个会话变量,后续所有命令/引用用它们——**不再硬编码 `PJ/AgentHOP/code/hopstep/...` 路径**。
4
+
5
+ ## 两个变量
6
+
7
+ - **`<CLI>`** = hopjit 命令行调用前缀。两种形态:
8
+ - `hopjit`(全局或本地 bin 命中,直接可执行,**不带 `node`**)
9
+ - `node <绝对路径>/cli.js`(包内 dist 或开发期 fallback)
10
+ - **`<PKG>`** = hopjit 包根绝对路径(放 `driver/`、`examples/` 的目录)。用于引用 skill reference 文档、example spec:`<PKG>/driver/references/...`、`<PKG>/examples/...`。
11
+
12
+ ## 探测算法(四级,按优先级;每条独立 Bash,不链式)
13
+
14
+ 主 agent 逐条尝试,命中即固化变量、停止。**探到的路径一律转成绝对路径**(worker/subagent 跨 cwd 执行,相对路径会漂)。
15
+
16
+ > **包名 vs 命令名**:npm 包名是 `@hoplogic/hopjit`(安装用),bin 命令名是 `hopjit`(执行用)。故 `command -v hopjit` 用命令名,`node_modules/@hoplogic/hopjit` 用包名。
17
+
18
+ 1. **全局命令**:`command -v hopjit`
19
+ - 有输出 → `<CLI> = hopjit`;`<PKG>` 由 `npm root -g` + `/@hoplogic/hopjit` 得(`<npm root -g>/@hoplogic/hopjit`)。
20
+ 2. **项目本地 bin**:测试 `node_modules/.bin/hopjit` 是否存在
21
+ - 存在 → `<CLI> = node_modules/.bin/hopjit`(转绝对);`<PKG> = <项目>/node_modules/@hoplogic/hopjit`。
22
+ 3. **包内 dist**(装了包但没 link bin):测试 `node_modules/@hoplogic/hopjit/dist/cli.js` 是否存在
23
+ - 存在 → `<CLI> = node <项目>/node_modules/@hoplogic/hopjit/dist/cli.js`(绝对);`<PKG> = <项目>/node_modules/@hoplogic/hopjit`。
24
+ 4. **开发期 fallback**:测试 `PJ/AgentHOP/code/hopstep/dist/cli.js` 是否存在(hopjit 仓库内开发/dogfooding)
25
+ - 存在 → `<CLI> = node <绝对>/PJ/AgentHOP/code/hopstep/dist/cli.js`;`<PKG> = <绝对>/PJ/AgentHOP/code/hopstep`。
26
+
27
+ 四级全不命中 → 报错并提示用户:`npm i -g @hoplogic/hopjit`(全局)或在项目内 `npm i @hoplogic/hopjit`,或开发期 `npm link` / 确认已 `npm run build`。
28
+
29
+ ## 用法
30
+
31
+ 探到后:
32
+ - 命令类调用(run/submit_and_fetch_next/join_parallel/validate/list/status/resume/fanout-plan/fanout-next)一律写 `<CLI> <子命令> <参数>`。
33
+ - 文档/example 引用一律写 `<PKG>/driver/references/<file>` 或 `<PKG>/examples/<spec>`。
34
+ - 传给 driver subagent / parallel worker 的 prompt 里,`<CLI>` 原样嵌入(它可能是 `hopjit` 或 `node .../cli.js`,subagent 不关心形态、照抄执行)。
35
+
36
+ > **为何固化绝对路径**:worker 是后台 subagent,其 Bash 在命令间重置 cwd;`<CLI>` 含相对路径会在 worker 里解析失败。探测阶段一次性转绝对,下游零歧义。
@@ -0,0 +1,45 @@
1
+ # spec 发现与前置:list / recent-dirs / spec 定位 / params 组装
2
+
3
+ > hopspec skill 的抽出片段——`/hopspec list` 的呈现流程、`recent-dirs` LRU(list 与 run 前置共用)、`run` 前的 spec 定位与 params 组装。主体按需引用,不常驻。
4
+
5
+ ## recent-dirs LRU(list 与 run 共用底座)
6
+
7
+ `.hopspec/recent-dirs.json` = 当前项目下最近用过的 spec 目录 LRU 列表(最多 10 个)。格式:
8
+ ```json
9
+ { "dirs": ["<最近用的 spec 目录>", "<更早的>", "..."] }
10
+ ```
11
+ - **位置**:`.hopspec/` 在项目根下(相对 cwd,sandbox 默认可写),与 `.hopstate/`(状态)/`.hoplog/`(日志)同族,应一并 `.gitignore`。
12
+ - **维护(成功定位/选定目录后)**:把本次目录提到列表最前(已存在则移队首,不存在则插队首),保留最多 10;`.hopspec/` 不存在则 `mkdir -p .hopspec`。
13
+ - **按项目隔离**、**不写死任何目录**——首次无文件走全库搜,用过自动进 LRU 下次优先命中,换项目/新 spec 库自适应。
14
+
15
+ ## `/hopspec list [目录]` — 列出可执行 spec
16
+
17
+ 供用户挑选后 `run`。流程:
18
+
19
+ 1. **确定搜索范围**:
20
+ - 显式给了 `<目录>` → 用它(并记入 recent-dirs)。
21
+ - 否则读 recent-dirs.json:**有记录** → 用这些近期目录(常态,不全库扫);**空/不存在(首次)** → 用 `AskUserQuestion` 问用户:(a) 指定一个 spec 目录(推荐,之后记入 recent-dirs)/ (b) 全库扫一遍(慢)。
22
+ 2. **对每个范围目录调引擎扫描**:`node <CLI> list <目录>` → 返回 `{status,dir,specs:[{file,id,goal}]}`。扫描/parseSpec/判定可执行 spec 全由引擎确定性完成,你不手动 glob/grep。
23
+ 3. **合并各目录 `specs`**,表格列出 `文件名 [Id] — Goal`,recent-dirs 命中的目录优先排前标「最近」。
24
+ 4. 提示:`用 /hopspec run <文件名> 执行`。
25
+
26
+ > **可执行 spec 判定归引擎**(`hopjit list` 内部,见 [[../design/hop-cli#^anc-cli-list]]):goal 非空 + steps 非空 + 排除设计文档(`%% @trace` / `design/` 路径 / `## impl`)。你只消费引擎吐的 `specs`。
27
+ > **全库扫**(用户选 b):对全库相关目录分别调 `hopjit list`,或先 `find` 出候选目录再逐个 list。
28
+ > 输出只列清单,不展开分析(遵循输出纪律)。
29
+
30
+ ## `run` 前置:spec 定位
31
+
32
+ 用户给的 spec 可能是路径、文件名、或模糊描述。按序解析:
33
+ 1. 现成可读路径 → 直接用。
34
+ 2. 否则搜索:先按 recent-dirs.json 顺序在这些目录找文件名匹配的 `.md`;仍未命中 → 文件名 glob 全库搜(`find . -name "<名>*.md"`,跳过 node_modules/dist/.git),或按描述关键词匹配 spec 标题/Id。
35
+ 3. 命中唯一 → 用;多个 → `AskUserQuestion` 让用户选;零命中 → 报告找不到,列 recent-dirs 里的目录及其 `.md` 供选。
36
+
37
+ 定位成功后**维护 recent-dirs**(见上,把本次 spec 所在目录提队首)。
38
+
39
+ ## `run` 前置:params 组装
40
+
41
+ - 用户已给 `--params '<json>'` → 直接用。
42
+ - **未给或不全** → 读 spec 的 `## Inputs` 段(变量名 + 类型 + `#` 注释),据此:① 从对话上下文推断各 Input 值;② 推断不出的给合理默认/示例;③ 用 `AskUserQuestion` 把组装出的参数提交用户确认(展示每个 Input 名/类型/拟用值),确认或修正后再 `run`。
43
+ - 无 `## Inputs` 段 → 无需 params,直接 run。
44
+
45
+ > spec/params 前置是 run 的**必要交互**,不属"自主展开"(见主体输出纪律的例外)。
@@ -0,0 +1,50 @@
1
+ # driver subagent 模板(顶层执行段外包)
2
+
3
+ > 主 agent 用 `Agent` 工具起 driver subagent 跑执行段——**主 agent 自己从不 run/submit**(否则 advance 抢记首步 start,hoplog 重复;执行链全归 subagent)。subagent 独立窗口跑,遇介入点/终态即返回 JSON,隔离主上下文。执行细则见 `step-execution-rules.md`。
4
+
5
+ **两种起法**:
6
+ - **首个 subagent(从 run 起)**:spec 尚未 init。subagent 自己跑 `run` 作首步(首个 recordStepStart 归它,无抢跑),从 run 输出里拿 `instance_id` 回报主 agent。主 agent 传入 `<SPEC>` 绝对路径 + `<PARAMS>`(主 agent §0 已备好的 JSON)。
7
+ - **续接 subagent(从 submit 起)**:主 agent 处理完介入点(如 paused 注入 answer)后要续跑执行段,起新 subagent 从已有 `<INST>` 继续。主 agent 传入 `<INST>`。
8
+
9
+ **路径协议**(主 agent 启动时已知,直接嵌入 prompt):
10
+ - `<CLI>` = 主 agent 由 `references/cli-discovery.md` 探测确定的调用前缀——**可能是 `hopjit`(全局/本地 bin,直接可执行)或 `node <绝对路径>/cli.js`(包内 dist / 开发期 fallback)**。subagent 原样使用主 agent 传入的 `<CLI>`,不自己拼路径。
11
+ - `<STATE>` = `--state-dir` 绝对路径
12
+ - `<SPEC>` = spec 文件绝对路径(首个 subagent 用)
13
+ - `<PARAMS>` = 主 agent §0 组装的参数 JSON(首个 subagent 用)
14
+ - `<INST>` = instance_id(续接 subagent 由主 agent 传入;首个 subagent 从 run 输出取得)
15
+ - `<VAULT>` = 项目/vault 根绝对路径(doc-ref 解析基准,见下)
16
+
17
+ > **⚠️ doc-ref 工作目录(spec 含 doc-ref 时必带)**:doc-ref 章节注入按 CLI 进程 cwd 解析引用路径,且 subagent 的 Bash 在命令间会把 cwd 重置。故**每条 node 命令都前置 `cd <VAULT> &&`** 锁定 cwd——这是唯一允许的链式(仅锁 cwd)。spec 不含 doc-ref 时可省略。
18
+
19
+ ## Prompt 模板(填入实际值)
20
+
21
+ ```
22
+ 你是 HopSpec driver subagent,负责驱动执行段到下一个介入点或终态。
23
+
24
+ 【首步】
25
+ - 若你是首个 subagent(主 agent 给了 <SPEC> + <PARAMS>):先跑(前置 cd 锁 cwd)
26
+ cd <VAULT> && node <CLI> run <SPEC> --state-dir <STATE> --log-dir <STATE>/../.hoplog --log-level debug --params '<PARAMS>'
27
+ 读返回 JSON,记住其中的 instance_id(后续 submit 用它做 <INST>,并在最终回报主 agent)。然后按下方 status 分派。
28
+ - 若你是续接 subagent(主 agent 给了 <INST>):直接进循环,用 submit_and_fetch_next 从 <INST> 领下一步。
29
+
30
+ 循环:读返回 JSON 的 status 分派:
31
+
32
+ - step_ready → 按 step_type 执行后提交,带 --instance <INST>。**提交只有一种方式(机械照做)**:把完整 output JSON 对象写到 step_ready 响应给的 **`output_path`**(引擎算好的确切路径,落在你的独占 work_zone 内),再整包 @file 提交(前置 cd 锁 cwd):
33
+ cd <VAULT> && node <CLI> submit_and_fetch_next <step_id> --output @<output_path> --state-dir <STATE> --instance <INST>
34
+ **🔴 只写 work_zone**:output_path 在响应给的独占工作区内,**禁写 /tmp/项目根/自选绝对路径——引擎校验越界即拒绝(WORK_ZONE_VIOLATION)**。**`@` 只贴 `--output` 参数最前面**;**绝不把 `@` 写进 JSON 字段值**(`{"pages":"@/path"}` 错,不解析、谎报类型)。列表类型 `[T]` 必须真数组。
35
+ 执行规则见 step-execution-rules.md(reason/check 推理产出 output_schema JSON;act 有 body 严格逐行执行/无 body 按描述执行;commit 同 act)。提交后继续循环。
36
+
37
+ - paused → **立即停止循环**,把这个 paused JSON **原样完整返回**(不问人、不自己填答案——你无权问真人,HITL 归主 agent)。
38
+
39
+ - parallel_ready → **立即停止循环**,把这个 parallel_ready JSON 原样返回(并行 fan-out 归主 agent 编排,你不自己起 worker)。
40
+
41
+ - adaptive_needed → **立即停止循环**,把这个 adaptive_needed JSON 原样返回(重规划归主 agent)。
42
+
43
+ - completed / failed → 停止,返回该终态 JSON。
44
+
45
+ 返回给主 agent:最终那个 JSON(paused / parallel_ready / adaptive_needed / completed / failed)+ **instance_id**(首个 subagent 必报,主 agent 后续介入点注入要用)+ 一行执行摘要("执行了 N 步:step_id[type]…直到 <停止原因>")。
46
+
47
+ Bash 纪律 + SCHEMA_MISMATCH/失败处理见 step-execution-rules.md。
48
+ ```
49
+
50
+ > 设计原理(为何冒泡、为何不自嵌套 fan-out、状态外置如何让退出无损)见 [[../../design/reuse-mode-prompt-flow#^anc-exec-reuse-subagent-driver]]。
@@ -0,0 +1,50 @@
1
+ # parallel fan-out + worker 模板
2
+
3
+ > 主 agent 遇 `parallel_ready` 时按本文件 fan-out 并发驱动 child,全部返回后 join。worker 执行细则见 `step-execution-rules.md`。parallel worker 与 driver subagent 是同一 subagent 范式的两种粒度——worker 驱动**一棵 child 子树**,driver subagent 驱动**顶层执行段直到介入点**。
4
+
5
+ ## fan-out 流程(主 agent 做)——CLI 调度顾问出决策、你只起 subagent
6
+
7
+ **核心姿态**:你是**句柄执行器**(唯一能可靠起 subagent、收完成通知的主体),**不自己算调度、不自己拼命令**。调度决策全由 CLI 顾问(`fanout-plan`/`fanout-next`)给——它读 `.hopstate` 无状态复原窗口,返回"该起哪几个 + 每个的完整启动命令 / 该 join 了 / 等"。你照着起、照着做。(原理见 design `^anc-exec-parallel-fanout-advisor`:满额窗口/补位/防重复派发/命令拼装全在 CLI,消除手拼漏 `--params`/`cd`、串台等 flaky 失效。)
8
+
9
+ **为什么调度归 CLI 而句柄归你**:实测(嵌套/并发探针)——subagent 能起子 subagent 但"idle 即完成",跨窗口周期会丢早批 worker 通知,**不能**当常驻调度器;只有主 agent(顶层循环)稳定持句柄。故职责分离:CLI 算、你执行。
10
+
11
+ 1. **拿初始批**:`parallel_ready` 后调一次
12
+ ```bash
13
+ node <CLI> fanout-plan <parallel_step_id> --state-dir <STATE> --instance <instance_id>
14
+ ```
15
+ 返回 `{ action:"launch", workers:[{child_step_id, launch_command}], max_concurrent, remaining }`。**confirm 子树引擎已排除**(`^anc-exec-parallel-confirm-exclude`),你无需判断。
16
+ 2. **起 workers**:对返回的每个 worker,用**后台** subagent(`Agent` 工具 `run_in_background: true`)起它——prompt 用下方模板,**启动命令直接用 `launch_command`(CLI 已拼好:含 `cd <VAULT>`、`--parallel-child`、log-dir,不含 `--params`;你原样复制,不改不拼)**。**subagent 的 label 用 `child_step_id`**(完成通知靠它回读,见下)。
17
+ 3. **补位循环**:每收到一个 worker 完成通知,读通知里的 label 得 `child_step_id` 与 `status`,调
18
+ ```bash
19
+ node <CLI> fanout-next <parallel_step_id> --done <child_step_id> --status <completed|failed> --state-dir <STATE> --instance <instance_id>
20
+ ```
21
+ 按返回 `action` 做:
22
+ - `launch` → 起返回的 worker(同第 2 步,后台 subagent + launch_command)。
23
+ - `wait` → 不动,继续等下一个完成通知。
24
+ - `join` → 全部终态,执行返回的 `command`(即 `join_parallel ...`)。
25
+ **不要自己数窗口、算补哪个**——CLI 已算好,`launch`/`wait`/`join` 照做即可。worker 失败不阻塞其余(`--status failed` 照传,join 时引擎把该 child 聚合输出写 None)。
26
+ 4. **join 后**:`fanout-next` 返回的 `join` 命令执行后,引擎 merge 返回下一步 JSON → **回主 agent 编排循环分派**(若 step_ready → 起 driver subagent 续执行段)。
27
+
28
+ ## worker prompt 模板(填入实际值)
29
+
30
+ **路径协议**:`<CLI>` = `node <绝对路径>/dist/cli.js`;`<STATE>` = `--state-dir` 绝对路径。`<LAUNCH_COMMAND>` = `fanout-plan`/`fanout-next` 返回的该 child 的 `launch_command`(CLI 已拼好:含 `cd <VAULT>`、`--parallel-child`、log-dir,不含 `--params`)。`<VAULT>` = 项目/vault 根(doc-ref 解析基准)。
31
+
32
+ > **⚠️ doc-ref 工作目录**:doc-ref 按 CLI 进程 cwd 解析引用路径,且 subagent 的 Bash 在命令间会重置 cwd。`launch_command` 已含前置 `cd <VAULT> &&`;worker 后续自己的 submit 命令也**须同样前置 `cd <VAULT> &&`** 锁 cwd(唯一允许的链式)。
33
+
34
+ ```
35
+ 你是 HopSpec parallel worker,负责驱动 child <child_step_id>(<summary>)到终态。
36
+
37
+ 启动命令(一条,直接执行——这是调度顾问给你的 launch_command,原样复制、不改不拼):
38
+ <LAUNCH_COMMAND>
39
+
40
+ 执行后读 JSON 的 status 分派,循环直到 completed / failed:
41
+ - step_ready → 按 step_type 执行(规则见 step-execution-rules.md),然后提交。**提交只有一种方式(机械照做)**:把完整 output JSON 对象写到 step_ready 响应给的本 child **`output_path`**(引擎算好的确切路径,落在本 child 独占 work_zone 内,大字段如 slide_html 也放里面当真值),再整包 @file 提交(同样前置 cd 锁 cwd):
42
+ cd <VAULT> && node <CLI> submit_and_fetch_next <step_id> --output @<output_path> --state-dir <STATE> --instance <instance_id>/parallel/<child_step_id>
43
+ **🔴 只写本 child 的 work_zone(响应给的 output_path)**:**禁写 /tmp/自选绝对路径——引擎校验越界即拒绝(WORK_ZONE_VIOLATION)**。实测事故:多 worker 写共享 `/tmp/out_*.json` 互相覆盖串台(s5 变 s4);用响应给的 output_path 每 child 目录带 id、天然不撞。**`@` 只贴 `--output` 参数最前面**;**绝不把 `@` 写进 JSON 字段值**(`{"slide_html":"@/path"}` 错)。列表类型必须真数组。
44
+ - completed → 报告完成
45
+ - failed → 报告失败
46
+
47
+ Bash 纪律:除唯一允许的前置 `cd <VAULT> &&`(锁 cwd,spec 含 doc-ref 时必带)外,每条只做一件事,不管道不链式,直接写完整 node 命令。
48
+ ```
49
+
50
+ > 设计原理(worker/driver subagent 同范式、confirm 子树引擎排除、串并等价)见 [[../../design/parallel-execution]] / [[../../design/reuse-mode-prompt-flow#^anc-exec-reuse-subagent-driver]]。
@@ -0,0 +1,47 @@
1
+ # step_ready 执行规则(driver / worker 共用)
2
+
3
+ > 本文件是 hopspec skill 的抽出片段——`step_ready` 时按 `step_type` 怎么执行、怎么提交、异常怎么处理。driver subagent(`driver-subagent.md`)、parallel worker(`parallel-worker.md`)、主 agent 都引用此规则,消除重复。
4
+
5
+ ## 按 step_type 执行
6
+
7
+ **reason / check**:你自身就是推理 LLM。依据 `context`(task_context / progress_summary / inputs / instruction / output_schema)推理,产出符合 output_schema 的 JSON(key 对应 output_schema 的 name)。
8
+ - **check 步骤**:固定双输出 bool(判定)+ text(说明)。判定 false → 引擎自动触发带反馈重跑/adaptive,**你只如实回判定**,不自己决定重试。
9
+
10
+ **act**(无推理、执行期不自由发挥):看 `context.instruction` 是否含 ` ```hop_python ` 围栏 body:
11
+ - **有 body**:**严格按 body 逐行执行**——赋值 / 内置函数(`len` / `split` / `trim` / `to_string`…)/ 工具调用 `tool_name(arg:value)` → 你的 Read/Write/Bash / `if-elif-else` 确定性分支。取赋给 `+→` 输出名的最终值。执行期不自由发挥。
12
+ > 纯计算 body(无工具调用)引擎已自动消化,不会交给你——你只会收到含工具调用的 act。
13
+ - **无 body**:读自然语言描述,用 Bash/Read/Write 执行。
14
+
15
+ **commit**:与 act 同源(副作用不可逆)。展示不可逆操作描述,按 body 严格执行(有 body)或按描述执行。
16
+
17
+ ## 提交(一条命令)
18
+
19
+ ```bash
20
+ node <CLI> submit_and_fetch_next <step_id> --output '<结果 JSON>' --state-dir <STATE> --instance <INST>
21
+ ```
22
+ - 输出 JSON:`{"var_name": value, ...}`,key 对应 output_schema 的 name。**列表类型 `[T]` 必须是真数组**(`{"pages": [ ... ]}`,不是把数组写成字符串),否则 SCHEMA_MISMATCH。
23
+
24
+ **提交 output 只有一种方式(机械照做,不要自己判断长短):**
25
+
26
+ 1. 把完整 output JSON 对象写到 step_ready 响应给你的 **`output_path`**(引擎已算好的确切路径,形如 `<work_zone>/out_<step_id>.json`)。文件内容形如 `{"pages":[...], "component_set":"..."}`——**所有字段都在这一个文件里**。
27
+ 2. 用整包 `@file` 提交(`@` 后就是那个 `output_path`):
28
+ ```bash
29
+ node <CLI> submit_and_fetch_next <step_id> --output @<output_path> --state-dir <STATE> --instance <INST>
30
+ ```
31
+
32
+ - **🔴 独占工作区,只写这里**:`output_path` 落在你的 **work_zone**(响应给出的独占工作区)内。**禁止**写 `/tmp`、项目根或任何自选绝对路径——**引擎会校验 `--output` 路径在 work_zone 内,越界直接拒绝提交(WORK_ZONE_VIOLATION)**。后果(实测事故):多个并行 worker 写共享 `/tmp/out_*.json` 会**互相覆盖、串台**——你的产出被别人的覆盖、check 可能漏检、最终产物损坏。用响应给的 `output_path` 就零风险。
33
+ - **`@` 只能贴在 `--output` 参数最前面**(`--output @文件`=整个 output 在文件里)。CLI 只认「整个参数值以 @ 开头」,其它位置的 `@` 都不解析。
34
+ - **绝不把 `@` 写进 JSON 字段值**:`--output '{"pages":"@/path"}'` 是错的——`@/path` 不会被读文件、原样存字符串谎报类型。**大字段也放进那个文件里当真值**(真数组/真对象/真字符串)。
35
+ - 提交后引擎返回下一步 JSON,继续循环。
36
+
37
+ ## 异常处理
38
+
39
+ - **SCHEMA_MISMATCH** → 你的输出不符合 schema,**修正后重新 submit 同一步**(引擎未推进,停在原步)。
40
+ - **步骤执行失败** → `node <CLI> submit_and_fetch_next <step_id> --failure "<原因>" --state-dir <STATE> --instance <INST>`,引擎内部处理 retry/adaptive 并返回下一步。
41
+ - **全部 retry 耗尽** → 引擎自动传播 fail,submit 最终返回 `failed`。
42
+
43
+ ## Bash 命令纪律(硬约束)
44
+
45
+ - 每条 Bash 调用只做一件事:一条 `node ...`,不管道(`|`)、不变量赋值。**唯一允许的链式**是前置 `cd <VAULT> &&` 锁定 cwd(spec 含 doc-ref 时必带——doc-ref 按 CLI 进程 cwd 解析引用路径,且 subagent Bash 在命令间会重置 cwd);除此之外不 `&&`。
46
+ - 直接写完整命令 `[cd <VAULT> && ] node <CLI> <子命令> <参数>`,不缩写、不用 shell 变量。
47
+ - 自己读 stdout 的 JSON 按 `status` 分派,不 `| python3 -c` / `| node -e` 提取字段(管道触发 pipe_guard 弹框打断)。
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@hoplogic/hopjit",
3
+ "version": "0.1.0",
4
+ "description": "HopJIT execution engine for HopSpec v3 — structured execution runtime for LLM agents (CC / Codex reuse-mode drivers)",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Lenx Wei",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "keywords": [
12
+ "hopspec",
13
+ "hopjit",
14
+ "llm",
15
+ "agent",
16
+ "workflow",
17
+ "execution-engine",
18
+ "claude"
19
+ ],
20
+ "bin": {
21
+ "hopjit": "dist/cli.js"
22
+ },
23
+ "files": [
24
+ "dist/",
25
+ "driver/",
26
+ "README.md",
27
+ "LICENSE"
28
+ ],
29
+ "scripts": {
30
+ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
31
+ "build": "npm run clean && tsc",
32
+ "test": "vitest run",
33
+ "dev": "vitest --watch",
34
+ "prepack": "npm run clean && tsc",
35
+ "prepublishOnly": "npm run clean && tsc"
36
+ },
37
+ "dependencies": {
38
+ "@anthropic-ai/sdk": "^0.111.0",
39
+ "commander": "^13.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/js-yaml": "^4.0.9",
43
+ "@types/node": "^22.0.0",
44
+ "@vitest/coverage-v8": "^3.2.4",
45
+ "js-yaml": "^5.2.1",
46
+ "typescript": "^5.7.0",
47
+ "vitest": "^3.0.0"
48
+ },
49
+ "engines": {
50
+ "node": ">=20"
51
+ }
52
+ }