@ifrankwang/openspec-agents 0.121.0 → 0.122.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.
@@ -34170,28 +34170,6 @@ var SIMPLE_WORKFLOW_PATH = resolveWorkflowFilePath(import.meta.url, "task-simple
34170
34170
  function resolveWorkflowPath(state) {
34171
34171
  return state.mode === "simple" ? SIMPLE_WORKFLOW_PATH : TASK_WORKFLOW_PATH;
34172
34172
  }
34173
- var WORKFLOW_MODE_CONFIG_FILE = "openspec/workflow.yaml";
34174
- function readWorkflowModeConfig(worktree) {
34175
- const configPath = pathResolve(worktree, WORKFLOW_MODE_CONFIG_FILE);
34176
- if (!existsSync2(configPath))
34177
- return "full";
34178
- let raw;
34179
- try {
34180
- raw = yaml.load(readFileSync2(configPath, "utf-8"));
34181
- } catch (err) {
34182
- fail(`${WORKFLOW_MODE_CONFIG_FILE} 解析失败:${err.message}`);
34183
- }
34184
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
34185
- fail(`${WORKFLOW_MODE_CONFIG_FILE} 配置非法:顶层必须是 YAML 映射对象`);
34186
- }
34187
- const mode = raw.mode;
34188
- if (mode === undefined)
34189
- return "full";
34190
- if (mode !== "full" && mode !== "simple") {
34191
- fail(`${WORKFLOW_MODE_CONFIG_FILE} 配置非法:mode 值域为 full/simple,收到 ${JSON.stringify(mode)}`);
34192
- }
34193
- return mode;
34194
- }
34195
34173
  var workflowFileCache = new Map;
34196
34174
  function loadWorkflowFile(filePath) {
34197
34175
  let wf = workflowFileCache.get(filePath);
@@ -35752,6 +35730,9 @@ async function initExecute(params, ctx) {
35752
35730
  args.recovery = parsed;
35753
35731
  }
35754
35732
  assertValidRecovery(args.recovery);
35733
+ if (args.mode !== undefined && args.mode !== "full" && args.mode !== "simple") {
35734
+ throw new Error(`mode 参数不合法,合法值:full、simple。传入值:"${String(args.mode)}"。`);
35735
+ }
35755
35736
  const parsedGroups = await parseAllTaskGroupsFromMd(ctx.worktree, args.change_id);
35756
35737
  if (parsedGroups.length === 0) {
35757
35738
  throw new Error(`无法从 tasks.md 解析出任务组,请检查文件 openspec/changes/${args.change_id}/tasks.md。`);
@@ -35784,7 +35765,7 @@ async function initExecute(params, ctx) {
35784
35765
  workItems: [],
35785
35766
  createdAt: new Date().toISOString(),
35786
35767
  updatedAt: new Date().toISOString(),
35787
- mode: readWorkflowModeConfig(ctx.worktree)
35768
+ mode: args.mode ?? "simple"
35788
35769
  };
35789
35770
  } else {
35790
35771
  state.baseBranch = state.baseBranch || baseBranch;
@@ -36833,7 +36814,12 @@ var orchInitSchema = {
36833
36814
  type: "string",
36834
36815
  description: "基准分支名(如 main、develop),用于计算 merge-base 和 worktree fork 源。未传则自动从当前 git 分支推导。"
36835
36816
  },
36836
- recovery: recoverySchema
36817
+ recovery: recoverySchema,
36818
+ mode: {
36819
+ type: "string",
36820
+ enum: ["full", "simple"],
36821
+ description: "流程模式选择:full=完整流程(analyze→implement→三重审查+收尾验证);simple=精简流程(implement→quality_review→done,缺省)。仅新建编排状态(首次 opx_orch_init)时生效;已开始的变更沿用固化模式,不支持中途切换。"
36822
+ }
36837
36823
  },
36838
36824
  required: ["change_id", "task_group_id"],
36839
36825
  additionalProperties: false
@@ -37024,7 +37010,7 @@ function jsonSchemaToZod(schema2) {
37024
37010
  var AGENT_ARG = "_agent";
37025
37011
  var TOOL_SPECS = {
37026
37012
  opx_orch_init: {
37027
- description: "初始化编排会话。传入变更 ID 和任务组 ID,工具自动解析 tasks.md 提取全部任务组并解析目标组子任务。可通过 recovery 参数恢复到指定阶段。无 recovery 重复初始化当前任务组时保留其阶段和进度;切换到其它任务组时初始化该组。",
37013
+ description: "初始化编排会话。传入变更 ID 和任务组 ID,工具自动解析 tasks.md 提取全部任务组并解析目标组子任务。可通过 recovery 参数恢复到指定阶段。无 recovery 重复初始化当前任务组时保留其阶段和进度;切换到其它任务组时初始化该组。可选 mode 参数(full/simple,缺省 simple)选择流程模式,仅新建状态生效。",
37028
37014
  schema: orchInitSchema,
37029
37015
  execute: (args, ctx) => initExecute(args, ctx)
37030
37016
  },
@@ -37084,7 +37070,7 @@ async function ensureDefaultUnattended(args, ctx) {
37084
37070
  }
37085
37071
  } catch {}
37086
37072
  }
37087
- var PKG_VERSION = "0.121.0";
37073
+ var PKG_VERSION = "0.122.0";
37088
37074
  function buildMcpServer(worktree, opts = {}) {
37089
37075
  const mcp = new McpServer({ name: "openspec-agents", version: PKG_VERSION });
37090
37076
  for (const [name, spec] of Object.entries(TOOL_SPECS)) {
package/README.md CHANGED
@@ -15,7 +15,7 @@ OpenSpec 把需求、设计、任务拆解成规范文档后,实施阶段仍
15
15
 
16
16
  ## 编排流程
17
17
 
18
- 实施流程按变更开始时固化的模式执行,配置源为仓库根 `openspec/workflow.yaml`(`mode: full | simple`,缺省 full)。模式在变更开始时由 `opx_orch_init` 固化存档:已开始的变更不受后续配置改动影响,恢复(recovery)沿用固化模式,旧变更(状态无模式存档)一律按 full 处理,不支持中途切换。
18
+ 实施流程按变更开始时固化的模式执行:模式经 `opx_orch_init` 的 `mode` 参数在变更开始时固化(`full` 完整流程 / `simple` 精简流程,不传缺省 simple)。已开始的变更不受后续参数影响;恢复(recovery)沿用固化模式;旧变更(状态无模式存档)一律按 full 处理,不支持中途切换。
19
19
 
20
20
  ### full 模式
21
21
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ifrankwang/openspec-agents",
3
- "version": "0.121.0",
3
+ "version": "0.122.0",
4
4
  "type": "module",
5
5
  "main": "./src/core/index.ts",
6
6
  "exports": {
@@ -37,7 +37,7 @@ interface ToolSpec {
37
37
  const TOOL_SPECS: Record<string, ToolSpec> = {
38
38
  opx_orch_init: {
39
39
  description:
40
- "初始化编排会话。传入变更 ID 和任务组 ID,工具自动解析 tasks.md 提取全部任务组并解析目标组子任务。可通过 recovery 参数恢复到指定阶段。无 recovery 重复初始化当前任务组时保留其阶段和进度;切换到其它任务组时初始化该组。",
40
+ "初始化编排会话。传入变更 ID 和任务组 ID,工具自动解析 tasks.md 提取全部任务组并解析目标组子任务。可通过 recovery 参数恢复到指定阶段。无 recovery 重复初始化当前任务组时保留其阶段和进度;切换到其它任务组时初始化该组。可选 mode 参数(full/simple,缺省 simple)选择流程模式,仅新建状态生效。",
41
41
  schema: orchInitSchema,
42
42
  execute: (args, ctx) => initExecute(args as any, ctx),
43
43
  },
@@ -10,7 +10,7 @@ import { parseAllTaskGroupsFromMd, parseTasksMdForGroup, extractRelevantSpecsFro
10
10
  import type { ParsedTask } from "../tasks-md.ts"
11
11
  import { assertOrchestrator, findTaskGroup } from "../derive.ts"
12
12
  import { assertPathWithin } from "../paths.ts"
13
- import { loadWorkflowFile, resolveWorkflowPath, readWorkflowModeConfig, type LoadedWorkflow } from "../workflow/loader.ts"
13
+ import { loadWorkflowFile, resolveWorkflowPath, type LoadedWorkflow } from "../workflow/loader.ts"
14
14
  import { createInitialWorkItem, isBlockingSeverity, isTerminalPhase, recommendForItem, resetInternalRetryCount, adjudicateStep, clearStepTags } from "../workflow/engine.ts"
15
15
  import { renderWorkflowStatusView } from "../workflow/status.ts"
16
16
  import { taskChildrenOf } from "../task-children.ts"
@@ -293,6 +293,10 @@ export async function initExecute(params: InitParams, ctx: ToolContext): Promise
293
293
  (args as any).recovery = parsed
294
294
  }
295
295
  assertValidRecovery(args.recovery)
296
+ // mode 值域校验:值域外一律拒绝(无论 state 是否已存在),错误早于任何状态变更且不落盘
297
+ if (args.mode !== undefined && args.mode !== "full" && args.mode !== "simple") {
298
+ throw new Error(`mode 参数不合法,合法值:full、simple。传入值:"${String(args.mode)}"。`)
299
+ }
296
300
 
297
301
  const parsedGroups = await parseAllTaskGroupsFromMd(ctx.worktree, args.change_id)
298
302
  if (parsedGroups.length === 0) {
@@ -331,10 +335,9 @@ export async function initExecute(params: InitParams, ctx: ToolContext): Promise
331
335
  workItems: [],
332
336
  createdAt: new Date().toISOString(),
333
337
  updatedAt: new Date().toISOString(),
334
- // 新建 state 时固化模式:读取 <worktree>/openspec/workflow.yaml(缺失视为 full,
335
- // 值域外 / YAML 解析失败抛错);state 已存在(recovery/重复初始化/切换任务组)不读配置,
338
+ // 新建 state 时固化模式:取 init 参数 mode(缺省 simple);state 已存在不读参数,
336
339
  // 沿用 state 既有 mode;旧 state 缺 mode 由消费端读时兜底 full,不写回。
337
- mode: readWorkflowModeConfig(ctx.worktree),
340
+ mode: args.mode ?? "simple",
338
341
  }
339
342
  } else {
340
343
  state.baseBranch = state.baseBranch || baseBranch
@@ -213,6 +213,12 @@ export const orchInitSchema: JSONSchema = {
213
213
  description: "基准分支名(如 main、develop),用于计算 merge-base 和 worktree fork 源。未传则自动从当前 git 分支推导。",
214
214
  },
215
215
  recovery: recoverySchema,
216
+ mode: {
217
+ type: "string",
218
+ enum: ["full", "simple"],
219
+ description:
220
+ "流程模式选择:full=完整流程(analyze→implement→三重审查+收尾验证);simple=精简流程(implement→quality_review→done,缺省)。仅新建编排状态(首次 opx_orch_init)时生效;已开始的变更沿用固化模式,不支持中途切换。",
221
+ },
216
222
  },
217
223
  required: ["change_id", "task_group_id"],
218
224
  additionalProperties: false,
@@ -1,4 +1,4 @@
1
- import type { BuildPhaseTarget, ReviewLayer, ReviewVerifyStep } from "../types.ts"
1
+ import type { BuildPhaseTarget, ReviewLayer, ReviewVerifyStep, WorkflowMode } from "../types.ts"
2
2
 
3
3
  export interface ToolContext {
4
4
  worktree: string
@@ -28,6 +28,8 @@ export interface InitParams {
28
28
  * 恢复后 currentStep 落在第一个未全部通过的 verify step,可能早于被重置的 step。 */
29
29
  reset_steps?: ReviewVerifyStep[]
30
30
  }
31
+ /** 流程模式(full/simple),仅新建编排状态时生效;已开始的变更沿用固化模式,不支持中途切换。 */
32
+ mode?: WorkflowMode
31
33
  }
32
34
 
33
35
  export interface SetWorktreeParams {
package/src/core/types.ts CHANGED
@@ -135,7 +135,7 @@ export interface OrchestrateState {
135
135
  createdAt: string
136
136
  updatedAt: string
137
137
  unattended?: boolean
138
- /** 变更开始时固化的流程模式(opx_orch_init 从 <repo>/openspec/workflow.yaml 读取后写入)。
139
- * 缺失即旧变更,一律按 full 处理(读时兜底,不写回);已存在的 state 不再被配置改动覆盖。 */
138
+ /** 变更开始时固化的流程模式(经 opx_orch_init 的 mode 参数写入,缺省 simple)。
139
+ * 缺失即旧变更,一律按 full 处理(读时兜底,不写回);已存在的 state 不再被参数改动覆盖。 */
140
140
  mode?: WorkflowMode
141
141
  }
@@ -13,7 +13,7 @@ import type {
13
13
  } from "./types.ts"
14
14
  import { WORK_ITEM_PHASES, stepAgentIds } from "./types.ts"
15
15
  import { DIMENSION_AGENT_MAP } from "../constants.ts"
16
- import type { OrchestrateState, WorkflowMode } from "../types.ts"
16
+ import type { OrchestrateState } from "../types.ts"
17
17
 
18
18
  const SPECIAL_TRANSITIONS = ["done", "halt"] as const
19
19
  const PHASE_NAMES = new Set<string>(WORK_ITEM_PHASES)
@@ -63,38 +63,6 @@ export function resolveWorkflowPath(state: Pick<OrchestrateState, "mode">): stri
63
63
  return state.mode === "simple" ? SIMPLE_WORKFLOW_PATH : TASK_WORKFLOW_PATH
64
64
  }
65
65
 
66
- /** 项目级模式配置文件路径(<worktree>/openspec/workflow.yaml,与 openspec/config.yaml 同级)。 */
67
- const WORKFLOW_MODE_CONFIG_FILE = "openspec/workflow.yaml"
68
-
69
- /**
70
- * 读取项目级流程模式配置(<worktree>/openspec/workflow.yaml):
71
- * - 文件缺失 → "full"(缺省)
72
- * - YAML 解析失败 → 抛错
73
- * - 顶层非 YAML 映射对象 → 抛错
74
- * - mode 字段缺失 → "full"(缺省)
75
- * - mode 值域外(非 full/simple)→ 抛错
76
- * 仅由 opx_orch_init 新建 state 时调用;已存在的 state 不读配置,沿用既有 mode。
77
- */
78
- export function readWorkflowModeConfig(worktree: string): WorkflowMode {
79
- const configPath = pathResolve(worktree, WORKFLOW_MODE_CONFIG_FILE)
80
- if (!existsSync(configPath)) return "full"
81
- let raw: unknown
82
- try {
83
- raw = yaml.load(readFileSync(configPath, "utf-8"))
84
- } catch (err) {
85
- fail(`${WORKFLOW_MODE_CONFIG_FILE} 解析失败:${(err as Error).message}`)
86
- }
87
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
88
- fail(`${WORKFLOW_MODE_CONFIG_FILE} 配置非法:顶层必须是 YAML 映射对象`)
89
- }
90
- const mode = (raw as { mode?: unknown }).mode
91
- if (mode === undefined) return "full"
92
- if (mode !== "full" && mode !== "simple") {
93
- fail(`${WORKFLOW_MODE_CONFIG_FILE} 配置非法:mode 值域为 full/simple,收到 ${JSON.stringify(mode)}`)
94
- }
95
- return mode
96
- }
97
-
98
66
  const workflowFileCache = new Map<string, LoadedWorkflow>()
99
67
 
100
68
  /** 读取 workflow YAML 文件并解析,进程内按路径缓存(submit / status 共用)。 */