@devcxl/opencode-cabbage 1.0.0 → 1.2.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 (126) hide show
  1. package/README.md +19 -25
  2. package/README.zh.md +17 -23
  3. package/assets/agents/dev-lifecycle.md +208 -68
  4. package/assets/agents/team/architect.md +22 -4
  5. package/assets/agents/team/developer.md +13 -6
  6. package/assets/agents/team/goal-verify.md +4 -1
  7. package/assets/agents/team/researcher.md +59 -0
  8. package/assets/agents/team/reviewer.md +34 -18
  9. package/assets/commands/setup.md +1 -1
  10. package/assets/prompts/bootstrap.md +10 -9
  11. package/assets/prompts/stage-contract.md +25 -25
  12. package/assets/skills/flow-code/SKILL.md +23 -25
  13. package/assets/skills/flow-design/SKILL.md +94 -26
  14. package/assets/skills/flow-release/SKILL.md +41 -17
  15. package/assets/skills/flow-requirements/SKILL.md +19 -13
  16. package/assets/skills/flow-research/SKILL.md +77 -0
  17. package/assets/skills/flow-review/SKILL.md +55 -25
  18. package/assets/skills/flow-setup/SKILL.md +27 -24
  19. package/assets/skills/flow-tasks/SKILL.md +178 -35
  20. package/assets/skills/flow-tdd/SKILL.md +68 -40
  21. package/dist/kernel/context.js +12 -1
  22. package/dist/kernel/context.js.map +1 -1
  23. package/dist/kernel/permission.d.ts +1 -1
  24. package/dist/kernel/permission.js +9 -1
  25. package/dist/kernel/permission.js.map +1 -1
  26. package/dist/kernel/profile.js +5 -2
  27. package/dist/kernel/profile.js.map +1 -1
  28. package/dist/kernel/session-index.d.ts +12 -27
  29. package/dist/kernel/session-index.js +46 -80
  30. package/dist/kernel/session-index.js.map +1 -1
  31. package/dist/plugin/bootstrap.d.ts +0 -1
  32. package/dist/plugin/bootstrap.js +0 -3
  33. package/dist/plugin/bootstrap.js.map +1 -1
  34. package/dist/plugin/goal.d.ts +57 -6
  35. package/dist/plugin/goal.js +234 -86
  36. package/dist/plugin/goal.js.map +1 -1
  37. package/dist/plugin/prompt-lint.js +3 -12
  38. package/dist/plugin/prompt-lint.js.map +1 -1
  39. package/dist/plugin/prompts.d.ts +0 -1
  40. package/dist/plugin/prompts.js +0 -4
  41. package/dist/plugin/prompts.js.map +1 -1
  42. package/dist/plugin/server.d.ts +2 -5
  43. package/dist/plugin/server.js +260 -136
  44. package/dist/plugin/server.js.map +1 -1
  45. package/dist/plugin/skills.d.ts +7 -1
  46. package/dist/plugin/skills.js +75 -12
  47. package/dist/plugin/skills.js.map +1 -1
  48. package/dist/plugin.d.ts +0 -1
  49. package/dist/plugin.js +1 -4
  50. package/dist/plugin.js.map +1 -1
  51. package/dist/util/gh.d.ts +3 -9
  52. package/dist/util/gh.js +9 -11
  53. package/dist/util/gh.js.map +1 -1
  54. package/dist/util/paths.d.ts +6 -14
  55. package/dist/util/paths.js +12 -67
  56. package/dist/util/paths.js.map +1 -1
  57. package/package.json +5 -5
  58. package/assets/prompts/ADR-FORMAT.md +0 -45
  59. package/assets/prompts/PRD-FORMAT.md +0 -17
  60. package/assets/templates/gitignore +0 -5
  61. package/dist/kernel/caller.d.ts +0 -48
  62. package/dist/kernel/caller.js +0 -88
  63. package/dist/kernel/caller.js.map +0 -1
  64. package/dist/kernel/flow.d.ts +0 -166
  65. package/dist/kernel/flow.js +0 -387
  66. package/dist/kernel/flow.js.map +0 -1
  67. package/dist/kernel/legacy.d.ts +0 -19
  68. package/dist/kernel/legacy.js +0 -34
  69. package/dist/kernel/legacy.js.map +0 -1
  70. package/dist/kernel/records.d.ts +0 -87
  71. package/dist/kernel/records.js +0 -197
  72. package/dist/kernel/records.js.map +0 -1
  73. package/dist/kernel/release.d.ts +0 -104
  74. package/dist/kernel/release.js +0 -229
  75. package/dist/kernel/release.js.map +0 -1
  76. package/dist/kernel/review.d.ts +0 -34
  77. package/dist/kernel/review.js +0 -81
  78. package/dist/kernel/review.js.map +0 -1
  79. package/dist/kernel/setup.d.ts +0 -70
  80. package/dist/kernel/setup.js +0 -324
  81. package/dist/kernel/setup.js.map +0 -1
  82. package/dist/kernel/slug.d.ts +0 -23
  83. package/dist/kernel/slug.js +0 -67
  84. package/dist/kernel/slug.js.map +0 -1
  85. package/dist/kernel/task.d.ts +0 -208
  86. package/dist/kernel/task.js +0 -788
  87. package/dist/kernel/task.js.map +0 -1
  88. package/dist/kernel/tdd/adapter.d.ts +0 -49
  89. package/dist/kernel/tdd/adapter.js +0 -293
  90. package/dist/kernel/tdd/adapter.js.map +0 -1
  91. package/dist/kernel/tdd/digest.d.ts +0 -17
  92. package/dist/kernel/tdd/digest.js +0 -301
  93. package/dist/kernel/tdd/digest.js.map +0 -1
  94. package/dist/kernel/tdd/evaluator.d.ts +0 -38
  95. package/dist/kernel/tdd/evaluator.js +0 -185
  96. package/dist/kernel/tdd/evaluator.js.map +0 -1
  97. package/dist/kernel/tdd/evidence.d.ts +0 -42
  98. package/dist/kernel/tdd/evidence.js +0 -48
  99. package/dist/kernel/tdd/evidence.js.map +0 -1
  100. package/dist/kernel/tdd/state.d.ts +0 -79
  101. package/dist/kernel/tdd/state.js +0 -363
  102. package/dist/kernel/tdd/state.js.map +0 -1
  103. package/dist/kernel/types.d.ts +0 -180
  104. package/dist/kernel/types.js +0 -2
  105. package/dist/kernel/types.js.map +0 -1
  106. package/dist/kernel/worktree.d.ts +0 -45
  107. package/dist/kernel/worktree.js +0 -127
  108. package/dist/kernel/worktree.js.map +0 -1
  109. package/dist/plugin/flow-control.d.ts +0 -80
  110. package/dist/plugin/flow-control.js +0 -254
  111. package/dist/plugin/flow-control.js.map +0 -1
  112. package/dist/plugin/release-control.d.ts +0 -37
  113. package/dist/plugin/release-control.js +0 -304
  114. package/dist/plugin/release-control.js.map +0 -1
  115. package/dist/plugin/setup-control.d.ts +0 -45
  116. package/dist/plugin/setup-control.js +0 -80
  117. package/dist/plugin/setup-control.js.map +0 -1
  118. package/dist/plugin/task-control.d.ts +0 -90
  119. package/dist/plugin/task-control.js +0 -201
  120. package/dist/plugin/task-control.js.map +0 -1
  121. package/dist/plugin/tdd-checkpoint.d.ts +0 -118
  122. package/dist/plugin/tdd-checkpoint.js +0 -581
  123. package/dist/plugin/tdd-checkpoint.js.map +0 -1
  124. package/dist/util/shell.d.ts +0 -1
  125. package/dist/util/shell.js +0 -4
  126. package/dist/util/shell.js.map +0 -1
@@ -2,10 +2,15 @@
2
2
  * Flow → session 轻量索引(替代 session-state.json)。
3
3
  * 路径:.opencode/opencode-cabbage/session-index.json
4
4
  * 作用:parentIssueNumber → sessionID 绑定;双 session 检测(R7)。
5
+ * 并发:全部 read-modify-write 按 projectDir 走 KeyedMutex 串行,防丢失更新。
5
6
  */
6
7
  import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
7
8
  import path from "node:path";
8
9
  import { PLUGIN_ID } from "../util/paths.js";
10
+ import { KeyedMutex } from "./mutex.js";
11
+ const VALID_STATUSES = ["active", "paused", "completed", "cancelled"];
12
+ /** 按 projectDir 串行化索引读写(防并发 bind/update 互覆盖) */
13
+ const indexMutex = new KeyedMutex();
9
14
  export function sessionIndexPath(projectDir) {
10
15
  return path.join(projectDir, ".opencode", PLUGIN_ID, "session-index.json");
11
16
  }
@@ -22,99 +27,60 @@ export async function readIndex(projectDir) {
22
27
  return { flows: {} };
23
28
  }
24
29
  }
25
- /** 原子写:先写临时文件再 rename。 */
30
+ /** 原子写:先写临时文件(PID 后缀防跨进程 tmp 冲突)再 rename。 */
26
31
  export async function writeIndex(projectDir, index) {
27
32
  const target = sessionIndexPath(projectDir);
28
- const tmp = `${target}.tmp`;
33
+ const tmp = `${target}.${process.pid}.tmp`;
29
34
  await mkdir(path.dirname(target), { recursive: true });
30
35
  await writeFile(tmp, JSON.stringify(index, null, 2), "utf8");
31
36
  await rename(tmp, target);
32
37
  }
33
- export function getFlowSession(index, parentIssueNumber) {
34
- return index.flows[String(parentIssueNumber)] ?? null;
35
- }
36
38
  /**
37
- * 绑定 parentIssueNumber → sessionID。
38
- * 双 session 检测(§10.3):该 flow 已被另一 active session 绑定时拒绝。
39
+ * 绑定 parentIssueNumber → sessionID(goal create 时建立,供插件重启后的 autoResume 恢复)。
40
+ * 已绑定其它 session 时更新绑定(覆盖式,无双 session 强制)。
39
41
  */
40
42
  export async function bindSession(projectDir, parentIssueNumber, sessionID) {
41
- const index = await readIndex(projectDir);
42
- const key = String(parentIssueNumber);
43
- const existing = index.flows[key];
44
- if (existing && existing.sessionID !== sessionID && existing.status === "active") {
45
- return {
46
- ok: false,
47
- code: "FLOW_SESSION_CONFLICT",
48
- message: `Flow #${parentIssueNumber} is already bound to active session "${existing.sessionID}". Use flow_control takeover with user confirmation to take over.`,
49
- };
50
- }
51
- const entry = {
52
- sessionID,
53
- status: "active",
54
- continuationCount: existing && existing.sessionID === sessionID ? existing.continuationCount : 0,
55
- updatedAt: Date.now(),
56
- };
57
- index.flows[key] = entry;
58
- await writeIndex(projectDir, index);
59
- return { ok: true, entry };
60
- }
61
- /**
62
- * 接管绑定:旧 session 置 paused,新 session 绑定 active(R7)。
63
- * 旧 session 为另一 active session 时要求 userConfirmed(§10.3);
64
- * 调用方还需将旧 session 的 goal status 置 paused(goalClient 层)。
65
- */
66
- export async function takeoverSession(projectDir, parentIssueNumber, newSessionID, userConfirmed) {
67
- const index = await readIndex(projectDir);
68
- const key = String(parentIssueNumber);
69
- const existing = index.flows[key];
70
- if (existing && existing.sessionID !== newSessionID && existing.status === "active" && !userConfirmed) {
71
- return {
72
- ok: false,
73
- code: "TAKEOVER_NOT_CONFIRMED",
74
- message: `Flow #${parentIssueNumber} is bound to active session "${existing.sessionID}". Takeover requires user confirmation (user_confirmed: true).`,
43
+ return indexMutex.runExclusive(projectDir, async () => {
44
+ const index = await readIndex(projectDir);
45
+ const key = String(parentIssueNumber);
46
+ const existing = index.flows[key];
47
+ const entry = {
48
+ sessionID,
49
+ status: "active",
50
+ continuationCount: existing && existing.sessionID === sessionID ? existing.continuationCount : 0,
51
+ updatedAt: Date.now(),
75
52
  };
76
- }
77
- if (existing) {
78
- if (existing.sessionID === newSessionID) {
79
- const entry = { ...existing, status: "active", updatedAt: Date.now() };
80
- index.flows[key] = entry;
81
- await writeIndex(projectDir, index);
82
- return { ok: true, entry };
83
- }
84
- existing.status = "paused";
85
- existing.updatedAt = Date.now();
86
- }
87
- const entry = {
88
- sessionID: newSessionID,
89
- status: "active",
90
- continuationCount: 0,
91
- updatedAt: Date.now(),
92
- };
93
- index.flows[key] = entry;
94
- await writeIndex(projectDir, index);
95
- return { ok: true, entry };
53
+ index.flows[key] = entry;
54
+ await writeIndex(projectDir, index);
55
+ });
96
56
  }
97
- /** 更新已绑定 flow 的状态/计数;flow 未绑定时返回 null 且不创建 entry。 */
57
+ /** 更新已绑定 flow 的状态/计数/goal 完成标记;flow 未绑定时返回 null 且不创建 entry。 */
98
58
  export async function updateFlowSession(projectDir, parentIssueNumber, patch) {
99
- const index = await readIndex(projectDir);
100
- const key = String(parentIssueNumber);
101
- const existing = index.flows[key];
102
- if (!existing)
59
+ if (patch.status !== undefined && !VALID_STATUSES.includes(patch.status)) {
103
60
  return null;
104
- const entry = { ...existing, ...patch, updatedAt: Date.now() };
105
- index.flows[key] = entry;
106
- await writeIndex(projectDir, index);
107
- return entry;
61
+ }
62
+ return indexMutex.runExclusive(projectDir, async () => {
63
+ const index = await readIndex(projectDir);
64
+ const key = String(parentIssueNumber);
65
+ const existing = index.flows[key];
66
+ if (!existing)
67
+ return null;
68
+ const entry = { ...existing, ...patch, updatedAt: Date.now() };
69
+ index.flows[key] = entry;
70
+ await writeIndex(projectDir, index);
71
+ return entry;
72
+ });
108
73
  }
109
- /** 解绑:仅当 sessionID 与当前绑定匹配时删除 entry。 */
110
- export async function unbindSession(projectDir, parentIssueNumber, sessionID) {
111
- const index = await readIndex(projectDir);
112
- const key = String(parentIssueNumber);
113
- const existing = index.flows[key];
114
- if (!existing || existing.sessionID !== sessionID)
115
- return false;
116
- delete index.flows[key];
117
- await writeIndex(projectDir, index);
118
- return true;
74
+ /** 删除 flow 的索引 entry(goal cancel 时调用,避免重启 autoResume 恢复已取消 goal)。 */
75
+ export async function removeFlowSession(projectDir, parentIssueNumber) {
76
+ return indexMutex.runExclusive(projectDir, async () => {
77
+ const index = await readIndex(projectDir);
78
+ const key = String(parentIssueNumber);
79
+ if (!index.flows[key])
80
+ return false;
81
+ delete index.flows[key];
82
+ await writeIndex(projectDir, index);
83
+ return true;
84
+ });
119
85
  }
120
86
  //# sourceMappingURL=session-index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-index.js","sourceRoot":"","sources":["../../src/kernel/session-index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-index.js","sourceRoot":"","sources":["../../src/kernel/session-index.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,2 @@
1
1
  export declare function initBootstrap(): Promise<void>;
2
2
  export declare function getBootstrapContent(): string;
3
- export declare function resetBootstrap(): void;
@@ -11,7 +11,4 @@ export async function initBootstrap() {
11
11
  export function getBootstrapContent() {
12
12
  return _bootstrapCache ?? _fallbackContent;
13
13
  }
14
- export function resetBootstrap() {
15
- _bootstrapCache = undefined;
16
- }
17
14
  //# sourceMappingURL=bootstrap.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/plugin/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,IAAI,eAAmC,CAAA;AAEvC,MAAM,gBAAgB,GAAG,YAAY,CACnC,IAAI,CAAC,IAAI,CACP,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,EACnE,QAAQ,EAAE,SAAS,EAAE,cAAc,CACpC,EACD,OAAO,CACR,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,WAAW,CAAC,CAAA;IAC7C,eAAe,GAAG,OAAO,IAAI,SAAS,CAAA;AACxC,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,eAAe,IAAI,gBAAgB,CAAA;AAC5C,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,eAAe,GAAG,SAAS,CAAA;AAC7B,CAAC"}
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/plugin/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,IAAI,eAAmC,CAAA;AAEvC,MAAM,gBAAgB,GAAG,YAAY,CACnC,IAAI,CAAC,IAAI,CACP,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,EACnE,QAAQ,EAAE,SAAS,EAAE,cAAc,CACpC,EACD,OAAO,CACR,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,WAAW,CAAC,CAAA;IAC7C,eAAe,GAAG,OAAO,IAAI,SAAS,CAAA;AACxC,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,eAAe,IAAI,gBAAgB,CAAA;AAC5C,CAAC"}
@@ -2,25 +2,73 @@ import type { ToolContext, ToolResult } from "@opencode-ai/plugin";
2
2
  import { createOpencodeClient } from "@opencode-ai/sdk/v2";
3
3
  import type { Session } from "@opencode-ai/sdk/v2";
4
4
  export type GoalStatus = "active" | "paused" | "complete";
5
+ /** 用户最后使用的会话配置快照:续接注入时显式传回,防止 idle 后回落/切换默认 agent 与模型 */
6
+ export interface GoalSessionProfile {
7
+ agent: string;
8
+ model?: {
9
+ providerID: string;
10
+ modelID: string;
11
+ };
12
+ }
5
13
  /** 最小化 goal(§10.2):目标与验收条件从 Flow Record(Parent Issue body)读取 */
6
14
  export interface GoalData {
7
15
  parentIssueNumber: number;
8
16
  status: GoalStatus;
9
17
  continuationCount: number;
18
+ /** 用户最后使用的 agent/模型(create 或用户消息时快照) */
19
+ sessionProfile?: GoalSessionProfile;
20
+ /** 可选 token 预算(护栏):tokensUsed 达限后自动 pause,防止长跑成本失控 */
21
+ tokenBudget?: number;
22
+ /** 已用 token(快照法:最新完成 assistant 轮 input+cache.read+output − baseline,单调不减) */
23
+ tokensUsed?: number;
24
+ /** 记账基线:create 时点最新完成 assistant 轮的快照(compaction 不做分段,护栏非账单) */
25
+ tokensBaseline?: number;
26
+ /** goal 创建时刻(ms):记账基线初始化与诊断用 */
27
+ createdAt?: number;
28
+ /** 状态原因:'resumed' 是 UI/resume 的 kickoff 信号(首次 tick 豁免 blocked 检测后消费清除) */
29
+ statusReason?: string;
10
30
  }
11
- export declare function createGoal(parentIssueNumber: number): GoalData;
31
+ export declare function createGoal(parentIssueNumber: number, sessionProfile?: GoalSessionProfile, tokenBudget?: number): GoalData;
12
32
  export declare function canTransitionTo(goal: GoalData, target: GoalStatus): boolean;
13
33
  export declare function formatGoal(goal: GoalData): string;
14
34
  export declare const MAX_CONTINUATIONS = 50;
35
+ /**
36
+ * 单条消息的 token 快照 = input + reasoning + cache.read + output。
37
+ * 与 OpenChamber 记账同源:OpenCode 每轮的 cache.read 已含此前所有轮次付费 token,
38
+ * 最新完成轮的快照即整段成本,无需跨消息求和。reasoning 也计费,护栏方向偏严。
39
+ */
40
+ export declare function snapshotTokenTotal(tokens: unknown): number;
41
+ /** token 预算护栏:达到或超过预算即应暂停(null 表示未设预算) */
42
+ export declare function budgetReached(goal: GoalData): boolean;
43
+ /**
44
+ * 识别 agent 在续接回复中输出的显式阻塞报告(continuationPrompt 要求格式:
45
+ * 无法推进时必须输出 [BLOCKED: <原因>])。大小写与空白容错。
46
+ */
47
+ export declare const BLOCKED_REPORT_RE: RegExp;
48
+ export declare function isBlockedReport(text: string): boolean;
49
+ /**
50
+ * 识别 agent 的显式完成报告(continuationPrompt 要求格式:[DONE: <摘要>])。
51
+ * 命中 → goal 暂停并提示用户派 goal-verify 做最终独立验证(与 [BLOCKED:] 对称)。
52
+ */
53
+ export declare const DONE_REPORT_RE: RegExp;
54
+ export declare function isDoneReport(text: string): boolean;
15
55
  export declare function continuationPrompt(parentIssueNumber: number): string;
16
- export declare function verifyAgentPrompt(): string;
17
56
  export declare function createGoalClient(serverUrl: URL, v1Client: any): import("@opencode-ai/sdk/v2").OpencodeClient;
18
57
  export declare function readGoal(client: ReturnType<typeof createOpencodeClient>, sessionID: string): Promise<{
19
58
  goal: GoalData | null;
20
59
  session: Session | null;
21
60
  }>;
22
61
  export declare function writeGoal(client: ReturnType<typeof createOpencodeClient>, sessionID: string, goal: GoalData | null, existingSession?: Session | null): Promise<void>;
23
- export declare function createGoalTool(client: ReturnType<typeof createOpencodeClient>): {
62
+ /**
63
+ * 带锁的 goal 读-改-写单一入口:同一 sessionID 的操作串行,杜绝并发丢失更新。
64
+ * fn 接收当前 goal 与 session,返回写回的 goal(null 表示删除)与调用方结果 value。
65
+ * 当前无 goal 且 fn 也返回 null 时跳过写回(避免对不存在 goal 的无谓删除/写入)。
66
+ */
67
+ export declare function mutateGoal<T>(client: ReturnType<typeof createOpencodeClient>, sessionID: string, fn: (goal: GoalData | null, session: Session | null) => Promise<{
68
+ goal: GoalData | null;
69
+ value: T;
70
+ }>): Promise<T>;
71
+ export declare function createGoalTool(client: ReturnType<typeof createOpencodeClient>, projectDirFallback?: string): {
24
72
  description: string;
25
73
  args: {
26
74
  op: import("zod").ZodEnum<{
@@ -30,11 +78,14 @@ export declare function createGoalTool(client: ReturnType<typeof createOpencodeC
30
78
  resume: "resume";
31
79
  cancel: "cancel";
32
80
  pause: "pause";
81
+ edit: "edit";
33
82
  }>;
34
- parent_issue_number: import("zod").ZodNumber;
83
+ parent_issue_number: import("zod").ZodOptional<import("zod").ZodNumber>;
84
+ token_budget: import("zod").ZodOptional<import("zod").ZodNumber>;
35
85
  };
36
86
  execute(args: {
37
- op: "complete" | "create" | "get" | "resume" | "cancel" | "pause";
38
- parent_issue_number: number;
87
+ op: "complete" | "create" | "get" | "resume" | "cancel" | "pause" | "edit";
88
+ parent_issue_number?: number | undefined;
89
+ token_budget?: number | undefined;
39
90
  }, context: ToolContext): Promise<ToolResult>;
40
91
  };