clikit-plugin 0.2.45 → 0.2.47

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 (177) hide show
  1. package/AGENTS.md +69 -3
  2. package/README.md +128 -92
  3. package/command/commit.md +1 -1
  4. package/command/create.md +65 -8
  5. package/command/debug.md +1 -1
  6. package/command/design.md +183 -43
  7. package/command/handoff.md +1 -1
  8. package/command/import-plan.md +2 -2
  9. package/command/init.md +1 -1
  10. package/command/issue.md +3 -4
  11. package/command/pr.md +1 -1
  12. package/command/research.md +5 -7
  13. package/command/resume.md +1 -1
  14. package/command/ship.md +29 -32
  15. package/command/start.md +38 -27
  16. package/command/{status-beads.md → status.md} +2 -3
  17. package/command/verify.md +132 -48
  18. package/dist/.tsbuildinfo +1 -1
  19. package/dist/agents/index.d.ts +0 -0
  20. package/dist/agents/index.d.ts.map +0 -0
  21. package/dist/beads-context.test.d.ts +2 -0
  22. package/dist/beads-context.test.d.ts.map +1 -0
  23. package/dist/cli.d.ts +0 -0
  24. package/dist/cli.d.ts.map +0 -0
  25. package/dist/cli.js +5 -0
  26. package/dist/cli.test.d.ts +0 -0
  27. package/dist/cli.test.d.ts.map +0 -0
  28. package/dist/clikit.schema.json +32 -11
  29. package/dist/clilog.test.d.ts +0 -0
  30. package/dist/clilog.test.d.ts.map +0 -0
  31. package/dist/commands/index.d.ts +0 -0
  32. package/dist/commands/index.d.ts.map +0 -0
  33. package/dist/config.d.ts +15 -7
  34. package/dist/config.d.ts.map +1 -1
  35. package/dist/config.test.d.ts +0 -0
  36. package/dist/config.test.d.ts.map +0 -0
  37. package/dist/hooks/beads-context.d.ts +2 -0
  38. package/dist/hooks/beads-context.d.ts.map +1 -1
  39. package/dist/hooks/empty-message-sanitizer.d.ts +0 -0
  40. package/dist/hooks/empty-message-sanitizer.d.ts.map +0 -0
  41. package/dist/hooks/error-logger.d.ts +0 -0
  42. package/dist/hooks/error-logger.d.ts.map +0 -0
  43. package/dist/hooks/git-guard.d.ts +0 -0
  44. package/dist/hooks/git-guard.d.ts.map +0 -0
  45. package/dist/hooks/index.d.ts +0 -2
  46. package/dist/hooks/index.d.ts.map +1 -1
  47. package/dist/hooks/memory-digest.d.ts +1 -0
  48. package/dist/hooks/memory-digest.d.ts.map +1 -1
  49. package/dist/hooks/security-check.d.ts +0 -0
  50. package/dist/hooks/security-check.d.ts.map +0 -0
  51. package/dist/hooks/subagent-question-blocker.d.ts +0 -0
  52. package/dist/hooks/subagent-question-blocker.d.ts.map +0 -0
  53. package/dist/hooks/todo-beads-sync.d.ts +1 -0
  54. package/dist/hooks/todo-beads-sync.d.ts.map +1 -1
  55. package/dist/hooks/todo-enforcer.d.ts +1 -1
  56. package/dist/hooks/todo-enforcer.d.ts.map +1 -1
  57. package/dist/hooks/truncator.d.ts +0 -0
  58. package/dist/hooks/truncator.d.ts.map +0 -0
  59. package/dist/index.d.ts +0 -0
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +250 -576
  62. package/dist/skills/index.d.ts +0 -0
  63. package/dist/skills/index.d.ts.map +0 -0
  64. package/dist/tools/cass-memory.d.ts +0 -0
  65. package/dist/tools/cass-memory.d.ts.map +0 -0
  66. package/dist/tools/context-summary.d.ts +0 -0
  67. package/dist/tools/context-summary.d.ts.map +0 -0
  68. package/dist/tools/index.d.ts +0 -3
  69. package/dist/tools/index.d.ts.map +1 -1
  70. package/dist/tools/memory-db.d.ts +0 -0
  71. package/dist/tools/memory-db.d.ts.map +0 -0
  72. package/dist/tools/memory.d.ts +0 -0
  73. package/dist/tools/memory.d.ts.map +0 -0
  74. package/dist/tools/observation.d.ts +0 -0
  75. package/dist/tools/observation.d.ts.map +0 -0
  76. package/dist/types.d.ts +0 -0
  77. package/dist/types.d.ts.map +0 -0
  78. package/memory/_digest.md +1 -1
  79. package/memory/_templates/handoff.md +0 -0
  80. package/memory/_templates/plan.md +35 -0
  81. package/memory/_templates/prd.md +0 -0
  82. package/memory/_templates/research.md +0 -0
  83. package/memory/_templates/review.md +0 -0
  84. package/memory/_templates/spec.md +12 -0
  85. package/memory/beads/.gitkeep +0 -0
  86. package/memory/handoffs/.gitkeep +0 -0
  87. package/memory/memory.db +0 -0
  88. package/memory/plans/.gitkeep +0 -0
  89. package/memory/prds/.gitkeep +0 -0
  90. package/memory/research/.gitkeep +0 -0
  91. package/memory/reviews/.gitkeep +0 -0
  92. package/memory/specs/.gitkeep +0 -0
  93. package/package.json +4 -4
  94. package/skill/beads/SKILL.md +42 -43
  95. package/skill/beads/mcp.json +26 -0
  96. package/skill/beads/references/api-reference.md +64 -0
  97. package/skill/chrome-devtools/SKILL.md +22 -23
  98. package/skill/chrome-devtools/mcp.json +17 -0
  99. package/skill/chrome-devtools/references/tool-reference.md +63 -0
  100. package/skill/condition-based-waiting/SKILL.md +28 -66
  101. package/skill/deep-research/SKILL.md +34 -103
  102. package/skill/deep-research/mcp.json +21 -0
  103. package/skill/deep-research/references/lsp-ops.md +44 -0
  104. package/skill/defense-in-depth/SKILL.md +29 -69
  105. package/skill/executing-plans/SKILL.md +25 -34
  106. package/skill/finishing-a-development-branch/SKILL.md +28 -89
  107. package/skill/playwright/SKILL.md +27 -22
  108. package/skill/playwright/mcp.json +20 -0
  109. package/skill/playwright/references/tool-reference.md +64 -0
  110. package/skill/receiving-code-review/SKILL.md +16 -27
  111. package/skill/requesting-code-review/SKILL.md +22 -26
  112. package/skill/ritual-workflow/SKILL.md +22 -82
  113. package/skill/root-cause-tracing/SKILL.md +30 -54
  114. package/skill/session-management/SKILL.md +21 -40
  115. package/skill/source-code-research/SKILL.md +33 -102
  116. package/skill/source-code-research/mcp.json +13 -0
  117. package/skill/source-code-research/references/quick-ref.md +65 -0
  118. package/skill/systematic-debugging/SKILL.md +28 -41
  119. package/skill/systematic-debugging/references/patterns.md +71 -0
  120. package/skill/test-driven-development/SKILL.md +16 -40
  121. package/skill/testing-anti-patterns/SKILL.md +36 -64
  122. package/skill/testing-anti-patterns/references/decision-matrix.md +55 -0
  123. package/skill/using-git-worktrees/SKILL.md +27 -103
  124. package/skill/vercel-react-best-practices/SKILL.md +50 -139
  125. package/skill/vercel-react-best-practices/references/patterns.md +70 -0
  126. package/skill/verification-before-completion/SKILL.md +19 -37
  127. package/skill/writing-plans/SKILL.md +20 -32
  128. package/skill/writing-skills/SKILL.md +52 -41
  129. package/skill/writing-skills/references/skill-anatomy.md +210 -0
  130. package/src/agents/AGENTS.md +48 -18
  131. package/src/agents/build.md +342 -93
  132. package/src/agents/explore.md +77 -60
  133. package/src/agents/index.ts +0 -0
  134. package/src/agents/oracle.md +154 -64
  135. package/src/agents/plan.md +275 -110
  136. package/src/agents/research.md +72 -54
  137. package/src/agents/review.md +183 -62
  138. package/src/agents/vision.md +7 -5
  139. package/command/plan.md +0 -152
  140. package/command/review-codebase.md +0 -228
  141. package/command/review.md +0 -135
  142. package/command/vision.md +0 -210
  143. package/dist/hooks/swarm-enforcer.d.ts +0 -31
  144. package/dist/hooks/swarm-enforcer.d.ts.map +0 -1
  145. package/dist/tools/beads-memory-sync.d.ts +0 -17
  146. package/dist/tools/beads-memory-sync.d.ts.map +0 -1
  147. package/dist/tools/quick-research.d.ts +0 -16
  148. package/dist/tools/quick-research.d.ts.map +0 -1
  149. package/dist/tools/swarm.d.ts +0 -57
  150. package/dist/tools/swarm.d.ts.map +0 -1
  151. package/skill/accessibility-audit/SKILL.md +0 -115
  152. package/skill/beads-bridge/SKILL.md +0 -45
  153. package/skill/brainstorming/SKILL.md +0 -41
  154. package/skill/cass-village/SKILL.md +0 -217
  155. package/skill/cloudflare/SKILL.md +0 -96
  156. package/skill/design-system-audit/SKILL.md +0 -136
  157. package/skill/development-lifecycle/SKILL.md +0 -58
  158. package/skill/dispatching-parallel-agents/SKILL.md +0 -94
  159. package/skill/figma/SKILL.md +0 -34
  160. package/skill/frontend-aesthetics/SKILL.md +0 -63
  161. package/skill/gemini-large-context/SKILL.md +0 -80
  162. package/skill/mockup-to-code/SKILL.md +0 -98
  163. package/skill/mqdh/SKILL.md +0 -54
  164. package/skill/notebooklm/SKILL.md +0 -71
  165. package/skill/playwriter/SKILL.md +0 -56
  166. package/skill/polar/SKILL.md +0 -39
  167. package/skill/resend/SKILL.md +0 -85
  168. package/skill/sharing-skills/SKILL.md +0 -50
  169. package/skill/subagent-driven-development/SKILL.md +0 -69
  170. package/skill/supabase/SKILL.md +0 -80
  171. package/skill/supabase-postgres-best-practices/SKILL.md +0 -168
  172. package/skill/swarm-coordination/SKILL.md +0 -54
  173. package/skill/testing-skills-with-subagents/SKILL.md +0 -102
  174. package/skill/ui-ux-research/SKILL.md +0 -93
  175. package/skill/v0/SKILL.md +0 -67
  176. package/skill/v1-run/SKILL.md +0 -85
  177. package/skill/visual-analysis/SKILL.md +0 -113
package/dist/index.js CHANGED
@@ -16196,12 +16196,21 @@ var DEFAULT_CONFIG = {
16196
16196
  commands: {},
16197
16197
  skills: {},
16198
16198
  lsp: {},
16199
+ workflow: {
16200
+ mode: "compressed",
16201
+ active_roles: ["build", "plan", "review", "coordinator"],
16202
+ use_packets: true,
16203
+ embed_verify_in_start: true,
16204
+ verify_is_audit: true,
16205
+ subagent_call_budget: 2
16206
+ },
16199
16207
  hooks: {
16200
16208
  session_logging: false,
16201
16209
  tool_logging: false,
16202
16210
  todo_enforcer: {
16203
16211
  enabled: true,
16204
- warn_on_incomplete: true
16212
+ warn_on_incomplete: false,
16213
+ beads_authoritative: true
16205
16214
  },
16206
16215
  empty_message_sanitizer: {
16207
16216
  enabled: true,
@@ -16225,25 +16234,22 @@ var DEFAULT_CONFIG = {
16225
16234
  max_output_lines: 500,
16226
16235
  preserve_head_lines: 50,
16227
16236
  preserve_tail_lines: 50,
16228
- log: false
16229
- },
16230
- swarm_enforcer: {
16231
- enabled: true,
16232
- strict_file_locking: true,
16233
- block_unreserved_edits: false,
16237
+ packet_friendly: true,
16234
16238
  log: false
16235
16239
  },
16236
16240
  memory_digest: {
16237
16241
  enabled: true,
16238
- max_per_type: 10,
16242
+ max_per_type: 5,
16239
16243
  include_types: ["decision", "learning", "blocker", "progress", "handoff"],
16240
- index_highlights_per_type: 2,
16244
+ index_highlights_per_type: 1,
16241
16245
  write_topic_files: true,
16246
+ compact_mode: true,
16242
16247
  log: false
16243
16248
  },
16244
16249
  todo_beads_sync: {
16245
- enabled: true,
16250
+ enabled: false,
16246
16251
  close_missing: true,
16252
+ mode: "disabled",
16247
16253
  log: false
16248
16254
  },
16249
16255
  cass_memory: {
@@ -16256,8 +16262,10 @@ var DEFAULT_CONFIG = {
16256
16262
  },
16257
16263
  beads_context: {
16258
16264
  enabled: true,
16259
- max_issues: 20,
16265
+ max_issues: 8,
16260
16266
  include_closed: false,
16267
+ active_only: true,
16268
+ ready_limit: 3,
16261
16269
  log: false
16262
16270
  }
16263
16271
  }
@@ -16550,7 +16558,7 @@ function checkTodoCompletion(todos) {
16550
16558
  inProgress
16551
16559
  };
16552
16560
  }
16553
- function formatIncompleteWarning(result, sessionId) {
16561
+ function formatIncompleteWarning(result, sessionId, beadsAuthoritative) {
16554
16562
  const safeResult = normalizeTodoResult(result);
16555
16563
  const lines = [];
16556
16564
  if (sessionId) {
@@ -16567,7 +16575,7 @@ function formatIncompleteWarning(result, sessionId) {
16567
16575
  safeResult.incomplete.forEach((t) => lines.push(` - [${t.id}] ${t.content}`));
16568
16576
  }
16569
16577
  lines.push("");
16570
- lines.push(" Complete all todos before finishing.");
16578
+ lines.push(beadsAuthoritative ? " Todos are informational only here \u2014 update/close the active Beads issue instead." : " Complete all todos before finishing.");
16571
16579
  return lines.join(`
16572
16580
  `);
16573
16581
  }
@@ -16890,90 +16898,9 @@ function formatTruncationLog(result) {
16890
16898
  const saved = result.originalLength - result.truncatedLength;
16891
16899
  return `[CliKit:truncator] Truncated output: ${result.originalLines} \u2192 ${result.truncatedLines} lines, saved ${(saved / 1024).toFixed(1)}KB`;
16892
16900
  }
16893
- // src/hooks/swarm-enforcer.ts
16894
- import * as path6 from "path";
16895
- function isFileInScope(filePath, scope) {
16896
- if (typeof filePath !== "string")
16897
- return false;
16898
- const normalizedPath = path6.resolve(filePath);
16899
- for (const reserved of scope.reservedFiles) {
16900
- const normalizedReserved = path6.resolve(reserved);
16901
- if (normalizedPath === normalizedReserved) {
16902
- return true;
16903
- }
16904
- }
16905
- if (scope.allowedPatterns) {
16906
- for (const pattern of scope.allowedPatterns) {
16907
- if (normalizedPath.includes(pattern) || normalizedPath.startsWith(path6.resolve(pattern))) {
16908
- return true;
16909
- }
16910
- }
16911
- }
16912
- return false;
16913
- }
16914
- function checkEditPermission(filePath, scope, config2) {
16915
- if (!scope) {
16916
- return { allowed: true };
16917
- }
16918
- if (config2?.strict_file_locking === false) {
16919
- return { allowed: true };
16920
- }
16921
- if (typeof filePath !== "string") {
16922
- return { allowed: false, reason: "Invalid file path" };
16923
- }
16924
- if (isFileInScope(filePath, scope)) {
16925
- return { allowed: true, file: filePath };
16926
- }
16927
- return {
16928
- allowed: false,
16929
- file: filePath,
16930
- reason: `File is not in task scope for task ${scope.taskId}`,
16931
- suggestion: `Reserve the file first using beads-village reserve, or ask the lead agent to reassign.`
16932
- };
16933
- }
16934
- function extractFileFromToolInput(toolName, input) {
16935
- if (typeof toolName !== "string")
16936
- return;
16937
- switch (toolName.toLowerCase()) {
16938
- case "edit":
16939
- case "write":
16940
- case "read":
16941
- return input.filePath;
16942
- case "bash": {
16943
- const cmd = input.command;
16944
- if (!cmd)
16945
- return;
16946
- const writePatterns = [
16947
- />\s*["']?([^\s"'|&;]+)/,
16948
- /tee\s+["']?([^\s"'|&;]+)/,
16949
- /mv\s+\S+\s+["']?([^\s"'|&;]+)/,
16950
- /cp\s+\S+\s+["']?([^\s"'|&;]+)/
16951
- ];
16952
- for (const pattern of writePatterns) {
16953
- const match = cmd.match(pattern);
16954
- if (match)
16955
- return match[1];
16956
- }
16957
- return;
16958
- }
16959
- default:
16960
- return;
16961
- }
16962
- }
16963
- function formatEnforcementWarning(result) {
16964
- if (result.allowed)
16965
- return "";
16966
- const lines = [`[CliKit:swarm-enforcer] BLOCKED edit to ${result.file}`];
16967
- if (result.reason)
16968
- lines.push(` Reason: ${result.reason}`);
16969
- if (result.suggestion)
16970
- lines.push(` Suggestion: ${result.suggestion}`);
16971
- return lines.join(`
16972
- `);
16973
- }
16974
16901
  // src/hooks/memory-digest.ts
16975
16902
  import * as fs6 from "fs";
16976
- import * as path7 from "path";
16903
+ import * as path6 from "path";
16977
16904
  import { Database } from "bun:sqlite";
16978
16905
  function parseJsonArray(value) {
16979
16906
  if (typeof value !== "string" || !value.trim())
@@ -16993,7 +16920,7 @@ function formatDate(iso) {
16993
16920
  }
16994
16921
  }
16995
16922
  function writeTopicFile(memoryDir, type, heading, rows) {
16996
- const topicPath = path7.join(memoryDir, `${type}.md`);
16923
+ const topicPath = path6.join(memoryDir, `${type}.md`);
16997
16924
  const lines = [];
16998
16925
  lines.push(`# ${heading}`);
16999
16926
  lines.push("");
@@ -17041,13 +16968,14 @@ function generateMemoryDigest(projectDir, config2) {
17041
16968
  const result = { written: false, path: "", counts: {} };
17042
16969
  if (typeof projectDir !== "string" || !projectDir)
17043
16970
  return result;
17044
- const memoryDir = path7.join(projectDir, ".opencode", "memory");
17045
- const dbPath = path7.join(memoryDir, "memory.db");
16971
+ const memoryDir = path6.join(projectDir, ".opencode", "memory");
16972
+ const dbPath = path6.join(memoryDir, "memory.db");
17046
16973
  if (!fs6.existsSync(dbPath)) {
17047
16974
  return result;
17048
16975
  }
17049
- const maxPerType = config2?.max_per_type ?? 10;
17050
- const indexHighlightsPerType = config2?.index_highlights_per_type ?? 2;
16976
+ const compactMode = config2?.compact_mode !== false;
16977
+ const maxPerType = config2?.max_per_type ?? (compactMode ? 5 : 10);
16978
+ const indexHighlightsPerType = config2?.index_highlights_per_type ?? (compactMode ? 1 : 2);
17051
16979
  const writeTopicFiles = config2?.write_topic_files !== false;
17052
16980
  const includeTypes = config2?.include_types ?? [
17053
16981
  "decision",
@@ -17091,7 +17019,8 @@ function generateMemoryDigest(projectDir, config2) {
17091
17019
  const date5 = formatDate(row.created_at);
17092
17020
  const headline = row.narrative.split(`
17093
17021
  `)[0];
17094
- sections.push(`- ${date5}: ${headline}`);
17022
+ const beadNote = row.bead_id ? ` [${row.bead_id}]` : "";
17023
+ sections.push(`- ${date5}${beadNote}: ${headline}`);
17095
17024
  }
17096
17025
  sections.push("");
17097
17026
  if (writeTopicFiles) {
@@ -17106,7 +17035,7 @@ function generateMemoryDigest(projectDir, config2) {
17106
17035
  sections.push("*No observations found in memory database.*");
17107
17036
  sections.push("");
17108
17037
  }
17109
- const digestPath = path7.join(memoryDir, "_digest.md");
17038
+ const digestPath = path6.join(memoryDir, "_digest.md");
17110
17039
  const content = sections.join(`
17111
17040
  `);
17112
17041
  try {
@@ -17128,7 +17057,7 @@ function formatDigestLog(result) {
17128
17057
  }
17129
17058
  // src/hooks/todo-beads-sync.ts
17130
17059
  import * as fs7 from "fs";
17131
- import * as path8 from "path";
17060
+ import * as path7 from "path";
17132
17061
  import { Database as Database2 } from "bun:sqlite";
17133
17062
  import { execFile } from "child_process";
17134
17063
  import { promisify } from "util";
@@ -17272,7 +17201,18 @@ function syncTodosToBeadsAttempt(beadsDbPath, sessionID, todos, config2) {
17272
17201
  }
17273
17202
  }
17274
17203
  function syncTodosToBeads(projectDirectory, sessionID, todos, config2) {
17275
- const beadsDbPath = path8.join(projectDirectory, ".beads", "beads.db");
17204
+ if (config2?.mode === "disabled" || config2?.enabled === false) {
17205
+ return {
17206
+ synced: false,
17207
+ sessionID,
17208
+ totalTodos: todos.length,
17209
+ created: 0,
17210
+ updated: 0,
17211
+ closed: 0,
17212
+ skippedReason: "Todo sync disabled; Beads is authoritative"
17213
+ };
17214
+ }
17215
+ const beadsDbPath = path7.join(projectDirectory, ".beads", "beads.db");
17276
17216
  if (!fs7.existsSync(beadsDbPath)) {
17277
17217
  return {
17278
17218
  synced: false,
@@ -17303,7 +17243,7 @@ function syncTodosToBeads(projectDirectory, sessionID, todos, config2) {
17303
17243
  throw lastError instanceof Error ? lastError : new Error("Todo-Beads sync failed after retries");
17304
17244
  }
17305
17245
  function flushBeadsJsonl(projectDirectory, result) {
17306
- const jsonlPath = path8.join(projectDirectory, ".beads", "issues.jsonl");
17246
+ const jsonlPath = path7.join(projectDirectory, ".beads", "issues.jsonl");
17307
17247
  execFileAsync("bd", ["export", "--force", "-o", jsonlPath], {
17308
17248
  cwd: projectDirectory,
17309
17249
  timeout: 5000
@@ -17321,7 +17261,7 @@ function formatTodoBeadsSyncLog(result) {
17321
17261
  }
17322
17262
  // src/hooks/beads-context.ts
17323
17263
  import * as fs8 from "fs";
17324
- import * as path9 from "path";
17264
+ import * as path8 from "path";
17325
17265
  import { Database as Database3 } from "bun:sqlite";
17326
17266
  var BEADS_CONTEXT_BUSY_TIMEOUT_MS = 2000;
17327
17267
  var PRIORITY_LABELS = {
@@ -17337,7 +17277,7 @@ var STATUS_ICONS = {
17337
17277
  closed: "\u2713"
17338
17278
  };
17339
17279
  function openBeadsDbReadonly(projectDirectory) {
17340
- const beadsDbPath = path9.join(projectDirectory, ".beads", "beads.db");
17280
+ const beadsDbPath = path8.join(projectDirectory, ".beads", "beads.db");
17341
17281
  if (!fs8.existsSync(beadsDbPath)) {
17342
17282
  return null;
17343
17283
  }
@@ -17349,6 +17289,67 @@ function openBeadsDbReadonly(projectDirectory) {
17349
17289
  return null;
17350
17290
  }
17351
17291
  }
17292
+ function formatIssueLine(issue2) {
17293
+ const icon = STATUS_ICONS[issue2.status] ?? "?";
17294
+ const priority = PRIORITY_LABELS[issue2.priority] ?? `p${issue2.priority}`;
17295
+ const assignee = issue2.assignee ? ` @${issue2.assignee}` : "";
17296
+ return `- ${icon} \`${issue2.id}\` **${issue2.title}** (${priority}${assignee})`;
17297
+ }
17298
+ function formatCompressedBeadsSnapshot(issues, config2) {
17299
+ if (issues.length === 0) {
17300
+ return null;
17301
+ }
17302
+ const inProgress = issues.filter((issue2) => issue2.status === "in_progress");
17303
+ const ready = issues.filter((issue2) => issue2.status === "open");
17304
+ const includeClosed = config2?.include_closed === true;
17305
+ const closed = includeClosed ? issues.filter((issue2) => issue2.status === "closed") : [];
17306
+ const readyLimit = config2?.ready_limit ?? 3;
17307
+ const activeOnly = config2?.active_only !== false;
17308
+ const lines = [
17309
+ "## Beads Task State",
17310
+ "",
17311
+ "Beads is the live execution source of truth. Prefer the active issue and its direct dependencies.",
17312
+ ""
17313
+ ];
17314
+ if (inProgress.length > 0) {
17315
+ lines.push("### Active Issue");
17316
+ lines.push(formatIssueLine(inProgress[0]));
17317
+ if (inProgress.length > 1) {
17318
+ lines.push(`- +${inProgress.length - 1} additional in-progress issue(s)`);
17319
+ }
17320
+ lines.push("");
17321
+ }
17322
+ if (!activeOnly && ready.length > 0) {
17323
+ lines.push("### Ready Queue");
17324
+ for (const issue2 of ready.slice(0, readyLimit)) {
17325
+ lines.push(formatIssueLine(issue2));
17326
+ }
17327
+ if (ready.length > readyLimit) {
17328
+ lines.push(`- +${ready.length - readyLimit} more ready issue(s)`);
17329
+ }
17330
+ lines.push("");
17331
+ } else if (activeOnly && ready.length > 0 && inProgress.length === 0) {
17332
+ lines.push("### Ready Queue (fallback)");
17333
+ for (const issue2 of ready.slice(0, readyLimit)) {
17334
+ lines.push(formatIssueLine(issue2));
17335
+ }
17336
+ if (ready.length > readyLimit) {
17337
+ lines.push(`- +${ready.length - readyLimit} more ready issue(s)`);
17338
+ }
17339
+ lines.push("");
17340
+ } else if (activeOnly && ready.length > 0) {
17341
+ lines.push(`Ready queue hidden (active_only=true, ${ready.length} ready issue(s) available).`);
17342
+ lines.push("");
17343
+ }
17344
+ if (closed.length > 0) {
17345
+ lines.push(`Recently closed available on demand: ${closed.length}`);
17346
+ lines.push("");
17347
+ }
17348
+ lines.push("Use `mcp__beads_village__show({id})` for full details.");
17349
+ lines.push("Use `mcp__beads_village__claim()` only when starting the next packet.");
17350
+ return lines.join(`
17351
+ `);
17352
+ }
17352
17353
  function getBeadsSnapshot(projectDirectory, config2) {
17353
17354
  const db = openBeadsDbReadonly(projectDirectory);
17354
17355
  if (!db) {
@@ -17371,55 +17372,16 @@ function getBeadsSnapshot(projectDirectory, config2) {
17371
17372
  if (issues.length === 0) {
17372
17373
  return null;
17373
17374
  }
17374
- const countByStatus = {};
17375
- for (const issue2 of issues) {
17376
- countByStatus[issue2.status] = (countByStatus[issue2.status] ?? 0) + 1;
17377
- }
17378
- const statusSummary = Object.entries(countByStatus).map(([status, count]) => `${status}: ${count}`).join(", ");
17379
- const lines = [
17380
- `## Active Beads Issues (${statusSummary})`,
17381
- ""
17382
- ];
17383
- const inProgress = issues.filter((i) => i.status === "in_progress");
17384
- const open = issues.filter((i) => i.status === "open");
17385
- const closed = issues.filter((i) => i.status === "closed");
17386
- if (inProgress.length > 0) {
17387
- lines.push("### In Progress");
17388
- for (const issue2 of inProgress) {
17389
- lines.push(formatIssueLine(issue2));
17390
- }
17391
- lines.push("");
17392
- }
17393
- if (open.length > 0) {
17394
- lines.push("### Ready");
17395
- for (const issue2 of open) {
17396
- lines.push(formatIssueLine(issue2));
17397
- }
17398
- lines.push("");
17399
- }
17400
- if (closed.length > 0 && includeClosed) {
17401
- lines.push("### Recently Closed");
17402
- for (const issue2 of closed) {
17403
- lines.push(formatIssueLine(issue2));
17404
- }
17405
- lines.push("");
17406
- }
17407
- lines.push("Use `mcp__beads_village__show({id})` to see full issue details.");
17408
- lines.push("Use `mcp__beads_village__claim()` to pick up the next ready task.");
17409
- return lines.join(`
17410
- `);
17375
+ return formatCompressedBeadsSnapshot(issues, {
17376
+ ...config2,
17377
+ include_closed: includeClosed
17378
+ });
17411
17379
  } catch {
17412
17380
  return null;
17413
17381
  } finally {
17414
17382
  db.close();
17415
17383
  }
17416
17384
  }
17417
- function formatIssueLine(issue2) {
17418
- const icon = STATUS_ICONS[issue2.status] ?? "?";
17419
- const priority = PRIORITY_LABELS[issue2.priority] ?? `p${issue2.priority}`;
17420
- const assignee = issue2.assignee ? ` @${issue2.assignee}` : "";
17421
- return `- ${icon} \`${issue2.id}\` **${issue2.title}** (${priority}${assignee})`;
17422
- }
17423
17385
  function getBeadsCompactionContext(projectDirectory, config2) {
17424
17386
  const snapshot = getBeadsSnapshot(projectDirectory, {
17425
17387
  ...config2,
@@ -17432,8 +17394,8 @@ function getBeadsCompactionContext(projectDirectory, config2) {
17432
17394
  return [
17433
17395
  "## Beads Task State (Source of Truth)",
17434
17396
  "",
17435
- "The following Beads issues represent the canonical task state.",
17436
- "Preserve this context across compaction \u2014 it takes priority over OpenCode todos.",
17397
+ "Preserve active Beads task state across compaction. Prefer the active issue and direct packet scope.",
17398
+ "OpenCode todos are informational only when Beads state is available.",
17437
17399
  "",
17438
17400
  snapshot
17439
17401
  ].join(`
@@ -17445,11 +17407,11 @@ import { promisify as promisify2 } from "util";
17445
17407
 
17446
17408
  // src/tools/memory-db.ts
17447
17409
  import * as fs9 from "fs";
17448
- import * as path10 from "path";
17410
+ import * as path9 from "path";
17449
17411
  import { Database as Database4 } from "bun:sqlite";
17450
17412
  function getMemoryPaths(projectDir = process.cwd()) {
17451
- const memoryDir = path10.join(projectDir, ".opencode", "memory");
17452
- const memoryDbPath = path10.join(memoryDir, "memory.db");
17413
+ const memoryDir = path9.join(projectDir, ".opencode", "memory");
17414
+ const memoryDbPath = path9.join(memoryDir, "memory.db");
17453
17415
  return { memoryDir, memoryDbPath };
17454
17416
  }
17455
17417
  function ensureObservationSchema(db) {
@@ -17774,185 +17736,6 @@ async function cassMemoryReflect(params = {}) {
17774
17736
  return embeddedReflect(p);
17775
17737
  }
17776
17738
 
17777
- // src/tools/swarm.ts
17778
- var swarmState = {
17779
- planId: null,
17780
- tasks: new Map,
17781
- parallelism: 3
17782
- };
17783
- function swarm(params) {
17784
- if (!params || typeof params !== "object") {
17785
- return { planId: "none", tasks: [], parallelism: 3, estimatedTime: "0m" };
17786
- }
17787
- const p = params;
17788
- switch (p.operation) {
17789
- case "plan":
17790
- return swarmPlan(p);
17791
- case "monitor":
17792
- return swarmMonitor(p);
17793
- case "delegate":
17794
- return swarmDelegate(p);
17795
- case "abort":
17796
- return swarmAbort(p);
17797
- default:
17798
- return { planId: "none", tasks: [], parallelism: 3, estimatedTime: "0m" };
17799
- }
17800
- }
17801
- function swarmPlan(params) {
17802
- const planId = `swarm-${Date.now()}`;
17803
- swarmState.planId = planId;
17804
- swarmState.tasks.clear();
17805
- swarmState.parallelism = params.parallelism || 3;
17806
- for (const task of params.tasks) {
17807
- swarmState.tasks.set(task.id, { ...task, status: task.status || "pending" });
17808
- }
17809
- const completedDeps = findReadyTasks();
17810
- for (const taskId of completedDeps) {
17811
- const task = swarmState.tasks.get(taskId);
17812
- if (task && task.status === "pending") {
17813
- task.status = "in_progress";
17814
- }
17815
- }
17816
- return {
17817
- planId,
17818
- tasks: Array.from(swarmState.tasks.values()),
17819
- parallelism: swarmState.parallelism,
17820
- estimatedTime: estimateTime(params.tasks)
17821
- };
17822
- }
17823
- function swarmMonitor(params) {
17824
- const tasks = Array.from(swarmState.tasks.values());
17825
- if (params.taskId) {
17826
- const task = swarmState.tasks.get(params.taskId);
17827
- if (!task) {
17828
- throw new Error(`Task not found: ${params.taskId}`);
17829
- }
17830
- }
17831
- return {
17832
- planId: swarmState.planId || "none",
17833
- totalTasks: tasks.length,
17834
- completed: tasks.filter((t) => t.status === "completed").length,
17835
- inProgress: tasks.filter((t) => t.status === "in_progress").length,
17836
- pending: tasks.filter((t) => t.status === "pending").length,
17837
- failed: tasks.filter((t) => t.status === "failed").length,
17838
- tasks
17839
- };
17840
- }
17841
- function swarmDelegate(params) {
17842
- const task = swarmState.tasks.get(params.taskId);
17843
- if (!task) {
17844
- throw new Error(`Task not found: ${params.taskId}`);
17845
- }
17846
- task.agentRole = params.agentRole;
17847
- task.status = "in_progress";
17848
- return {
17849
- taskId: params.taskId,
17850
- delegatedTo: `@${params.agentRole}`,
17851
- status: "delegated"
17852
- };
17853
- }
17854
- function swarmAbort(params) {
17855
- const task = swarmState.tasks.get(params.taskId);
17856
- if (!task) {
17857
- throw new Error(`Task not found: ${params.taskId}`);
17858
- }
17859
- task.status = "failed";
17860
- return {
17861
- taskId: params.taskId,
17862
- aborted: true,
17863
- reason: params.reason
17864
- };
17865
- }
17866
- function findReadyTasks() {
17867
- const ready = [];
17868
- for (const [id, task] of swarmState.tasks) {
17869
- if (task.status !== "pending")
17870
- continue;
17871
- const deps = task.dependencies || [];
17872
- const allDepsComplete = deps.every((depId) => {
17873
- const dep = swarmState.tasks.get(depId);
17874
- return dep && dep.status === "completed";
17875
- });
17876
- if (allDepsComplete) {
17877
- ready.push(id);
17878
- }
17879
- }
17880
- return ready;
17881
- }
17882
- function estimateTime(tasks) {
17883
- const totalTasks = tasks.length;
17884
- const parallelism = swarmState.parallelism;
17885
- const avgTaskTime = 5;
17886
- const batches = Math.ceil(totalTasks / parallelism);
17887
- const totalMinutes = batches * avgTaskTime;
17888
- if (totalMinutes < 60) {
17889
- return `${totalMinutes} minutes`;
17890
- } else {
17891
- const hours = Math.floor(totalMinutes / 60);
17892
- const mins = totalMinutes % 60;
17893
- return `${hours}h ${mins}m`;
17894
- }
17895
- }
17896
-
17897
- // src/tools/quick-research.ts
17898
- function quickResearch(params) {
17899
- if (!params || typeof params !== "object") {
17900
- return {
17901
- query: "",
17902
- suggestion: "Invalid params provided"
17903
- };
17904
- }
17905
- const p = params;
17906
- if (!p.query || typeof p.query !== "string") {
17907
- return {
17908
- query: "",
17909
- suggestion: "Missing query parameter"
17910
- };
17911
- }
17912
- const sources = p.sources || ["memory", "context7", "github"];
17913
- const limit = p.limit || 5;
17914
- let memoryResults;
17915
- let context7Hint;
17916
- let githubHint;
17917
- if (sources.includes("memory")) {
17918
- try {
17919
- memoryResults = memorySearch({ query: p.query, limit });
17920
- } catch {}
17921
- }
17922
- if (sources.includes("context7")) {
17923
- context7Hint = `Use context7 MCP tool: context7_resolve-library-id({ libraryName: "${p.query}" }) then context7_query-docs()`;
17924
- }
17925
- if (sources.includes("github")) {
17926
- const langHint = p.language ? ` language:${p.language}` : "";
17927
- githubHint = `Use gh-grep MCP tool: gh-grep_searchGitHub({ query: "${p.query}${langHint}" })`;
17928
- }
17929
- const suggestion = buildSuggestion(p.query, memoryResults, sources);
17930
- return {
17931
- query: p.query,
17932
- memory: memoryResults,
17933
- context7Hint,
17934
- githubHint,
17935
- suggestion
17936
- };
17937
- }
17938
- function buildSuggestion(query, memoryResults, sources) {
17939
- const parts = [];
17940
- if (memoryResults && memoryResults.length > 0) {
17941
- parts.push(`Found ${memoryResults.length} relevant observations in memory.`);
17942
- parts.push(`Check memory-get({ ids: "${memoryResults.map((r) => r.id).join(",")}" }) for details.`);
17943
- }
17944
- if (sources?.includes("context7")) {
17945
- parts.push(`For library docs, run context7_resolve-library-id \u2192 context7_query-docs.`);
17946
- }
17947
- if (sources?.includes("github")) {
17948
- parts.push(`For code examples, run gh-grep_searchGitHub with your query.`);
17949
- }
17950
- if (parts.length === 0) {
17951
- parts.push(`No results found. Try broadening your query or checking different sources.`);
17952
- }
17953
- return parts.join(" ");
17954
- }
17955
-
17956
17739
  // src/tools/context-summary.ts
17957
17740
  function parseStringArray(value) {
17958
17741
  if (typeof value !== "string" || !value.trim()) {
@@ -18047,170 +17830,6 @@ function buildSummary(sections, maxTokens) {
18047
17830
  return summary;
18048
17831
  }
18049
17832
 
18050
- // src/tools/beads-memory-sync.ts
18051
- import * as path11 from "path";
18052
- import * as fs10 from "fs";
18053
- import { Database as Database5 } from "bun:sqlite";
18054
- var BEADS_DIR = path11.join(process.cwd(), ".beads");
18055
- function getMemoryDb2() {
18056
- return openMemoryDb();
18057
- }
18058
- function getBeadsDb() {
18059
- const beadsDbPath = path11.join(BEADS_DIR, "beads.db");
18060
- if (!fs10.existsSync(beadsDbPath)) {
18061
- return null;
18062
- }
18063
- return new Database5(beadsDbPath);
18064
- }
18065
- function beadsMemorySync(params) {
18066
- if (!params || typeof params !== "object") {
18067
- return { success: false, operation: "unknown", details: {} };
18068
- }
18069
- const p = params;
18070
- if (!p.operation) {
18071
- return { success: false, operation: "unknown", details: {} };
18072
- }
18073
- switch (p.operation) {
18074
- case "sync_to_memory":
18075
- return syncTasksToMemory();
18076
- case "sync_from_memory":
18077
- return syncMemoryToTasks();
18078
- case "link":
18079
- if (!p.beadId || !p.observationId) {
18080
- return { success: false, operation: "link", details: {} };
18081
- }
18082
- return linkObservationToTask(p.observationId, p.beadId);
18083
- case "status":
18084
- return getSyncStatus();
18085
- default:
18086
- return { success: false, operation: p.operation, details: {} };
18087
- }
18088
- }
18089
- function syncTasksToMemory() {
18090
- const beadsDb = getBeadsDb();
18091
- if (!beadsDb) {
18092
- return { success: false, operation: "sync_to_memory", details: { tasksSynced: 0 } };
18093
- }
18094
- const memoryDb = getMemoryDb2();
18095
- try {
18096
- const tasks = beadsDb.query(`
18097
- SELECT id, title, description, t, desc
18098
- FROM issues
18099
- WHERE status IN ('done', 'closed')
18100
- `).all();
18101
- let synced = 0;
18102
- const existsStmt = memoryDb.prepare(`
18103
- SELECT id FROM observations WHERE type = 'progress' AND bead_id = ? AND narrative = ? LIMIT 1
18104
- `);
18105
- const insertStmt = memoryDb.prepare(`
18106
- INSERT INTO observations (type, narrative, facts, bead_id)
18107
- VALUES ('progress', ?, '[]', ?)
18108
- `);
18109
- for (const task of tasks) {
18110
- const narrative = task.title || task.t || task.description || task.desc || task.id;
18111
- const existing = existsStmt.get(task.id, narrative);
18112
- if (existing) {
18113
- continue;
18114
- }
18115
- insertStmt.run(narrative, task.id);
18116
- synced += 1;
18117
- }
18118
- return {
18119
- success: true,
18120
- operation: "sync_to_memory",
18121
- details: { tasksSynced: synced }
18122
- };
18123
- } finally {
18124
- memoryDb.close();
18125
- beadsDb.close();
18126
- }
18127
- }
18128
- function syncMemoryToTasks() {
18129
- const beadsDb = getBeadsDb();
18130
- if (!beadsDb) {
18131
- return { success: false, operation: "sync_from_memory", details: {} };
18132
- }
18133
- const memoryDb = getMemoryDb2();
18134
- try {
18135
- beadsDb.exec(`
18136
- CREATE TABLE IF NOT EXISTS issue_observations (
18137
- issue_id TEXT NOT NULL,
18138
- observation_id INTEGER NOT NULL,
18139
- observation_type TEXT NOT NULL,
18140
- narrative TEXT NOT NULL,
18141
- synced_at TEXT DEFAULT CURRENT_TIMESTAMP,
18142
- PRIMARY KEY (issue_id, observation_id)
18143
- )
18144
- `);
18145
- const observations = memoryDb.query(`
18146
- SELECT id, type, narrative, bead_id
18147
- FROM observations
18148
- WHERE bead_id IS NOT NULL
18149
- AND type IN ('blocker', 'decision')
18150
- `).all();
18151
- let linked = 0;
18152
- const issueExistsStmt = beadsDb.prepare("SELECT id FROM issues WHERE id = ? LIMIT 1");
18153
- const linkStmt = beadsDb.prepare(`
18154
- INSERT OR IGNORE INTO issue_observations (issue_id, observation_id, observation_type, narrative)
18155
- VALUES (?, ?, ?, ?)
18156
- `);
18157
- for (const obs of observations) {
18158
- const existingIssue = issueExistsStmt.get(obs.bead_id);
18159
- if (!existingIssue) {
18160
- continue;
18161
- }
18162
- const result = linkStmt.run(obs.bead_id, obs.id, obs.type, obs.narrative);
18163
- if (result.changes > 0) {
18164
- linked += 1;
18165
- }
18166
- }
18167
- return {
18168
- success: true,
18169
- operation: "sync_from_memory",
18170
- details: { observationsLinked: linked }
18171
- };
18172
- } finally {
18173
- memoryDb.close();
18174
- beadsDb.close();
18175
- }
18176
- }
18177
- function linkObservationToTask(observationId, beadId) {
18178
- const memoryDb = getMemoryDb2();
18179
- try {
18180
- memoryDb.run("UPDATE observations SET bead_id = ? WHERE id = ?", [beadId, observationId]);
18181
- return {
18182
- success: true,
18183
- operation: "link",
18184
- details: { observationsLinked: 1 }
18185
- };
18186
- } finally {
18187
- memoryDb.close();
18188
- }
18189
- }
18190
- function getSyncStatus() {
18191
- const memoryDb = getMemoryDb2();
18192
- const beadsDb = getBeadsDb();
18193
- try {
18194
- const memoryCount = memoryDb.query("SELECT COUNT(*) as count FROM observations").get();
18195
- let activeTasks = 0;
18196
- if (beadsDb) {
18197
- const taskCount = beadsDb.query("SELECT COUNT(*) as count FROM issues WHERE status != 'closed'").get();
18198
- activeTasks = taskCount.count;
18199
- }
18200
- return {
18201
- success: true,
18202
- operation: "status",
18203
- details: {
18204
- memoryCount: memoryCount.count,
18205
- activeTasks
18206
- }
18207
- };
18208
- } finally {
18209
- memoryDb.close();
18210
- beadsDb?.close();
18211
- }
18212
- }
18213
-
18214
17833
  // src/index.ts
18215
17834
  var execFileAsync3 = promisify3(execFile3);
18216
17835
  var CliKitPlugin = async (ctx) => {
@@ -18348,6 +17967,127 @@ var CliKitPlugin = async (ctx) => {
18348
17967
  writeErrorLog(hookName, error45, ctx.directory, context);
18349
17968
  await cliLog("error", formatHookErrorLog(hookName, error45, context));
18350
17969
  }
17970
+ function getEffectiveWorkflow() {
17971
+ const raw = pluginConfig.workflow ?? {};
17972
+ const classicMode = raw.mode === "classic";
17973
+ return {
17974
+ mode: classicMode ? "classic" : "compressed",
17975
+ activeRoles: raw.active_roles || ["build", "plan", "review", "coordinator"],
17976
+ usePackets: classicMode ? raw.use_packets === true : raw.use_packets !== false,
17977
+ embedVerifyInStart: classicMode ? false : raw.embed_verify_in_start !== false,
17978
+ verifyIsAudit: classicMode ? false : raw.verify_is_audit !== false,
17979
+ subagentCallBudget: raw.subagent_call_budget ?? 2
17980
+ };
17981
+ }
17982
+ function prependBlock(content, block) {
17983
+ return `${block.trim()}
17984
+
17985
+ ${(content || "").trim()}`.trim();
17986
+ }
17987
+ function applyWorkflowOverridesToAgents(agents) {
17988
+ const workflow = getEffectiveWorkflow();
17989
+ const result = { ...agents };
17990
+ const runtimeBlock = workflow.mode === "classic" ? [
17991
+ "## Runtime Workflow Override",
17992
+ "- Mode: classic",
17993
+ `- Use packets: ${workflow.usePackets ? "yes" : "no"}`,
17994
+ `- Subagent budget per unit of work: ${workflow.subagentCallBudget}`,
17995
+ "- Do not assume `/start` embeds verification; `/verify` is the pre-ship gate \u2014 required before `/ship`."
17996
+ ].join(`
17997
+ `) : [
17998
+ "## Runtime Workflow Override",
17999
+ "- Mode: compressed",
18000
+ `- Use packets: ${workflow.usePackets ? "yes" : "no"}`,
18001
+ `- Subagent budget per packet: ${workflow.subagentCallBudget}`,
18002
+ workflow.embedVerifyInStart ? "- `/start` performs execute + verify loop." : "- `/start` performs execute only.",
18003
+ workflow.verifyIsAudit ? "- `/verify` is optional deep audit." : "- `/verify` is the pre-ship gate \u2014 required before `/ship`."
18004
+ ].join(`
18005
+ `);
18006
+ for (const agentName of ["build", "plan", "review"]) {
18007
+ const agent = result[agentName];
18008
+ if (!agent)
18009
+ continue;
18010
+ result[agentName] = {
18011
+ ...agent,
18012
+ prompt: prependBlock(typeof agent.prompt === "string" ? agent.prompt : "", runtimeBlock)
18013
+ };
18014
+ }
18015
+ return result;
18016
+ }
18017
+ function applyWorkflowOverridesToCommands(commands) {
18018
+ const workflow = getEffectiveWorkflow();
18019
+ const result = { ...commands };
18020
+ if (workflow.mode === "classic") {
18021
+ if (result.start?.template) {
18022
+ result.start = {
18023
+ ...result.start,
18024
+ template: prependBlock(result.start.template, [
18025
+ "## Runtime Workflow Override",
18026
+ "- Classic mode is active.",
18027
+ "- Implement using the approved plan/task boundaries.",
18028
+ "- Verification remains a standalone `/verify` gate before `/ship`."
18029
+ ].join(`
18030
+ `))
18031
+ };
18032
+ }
18033
+ if (result.verify?.template) {
18034
+ result.verify = {
18035
+ ...result.verify,
18036
+ template: prependBlock(result.verify.template, [
18037
+ "## Runtime Workflow Override",
18038
+ "- Classic mode is active.",
18039
+ "- This verification pass is mandatory before ship."
18040
+ ].join(`
18041
+ `))
18042
+ };
18043
+ }
18044
+ if (result.ship?.template) {
18045
+ result.ship = {
18046
+ ...result.ship,
18047
+ template: prependBlock(result.ship.template, [
18048
+ "## Runtime Workflow Override",
18049
+ "- Classic mode is active.",
18050
+ "- Require `/verify` PASS before `/ship`."
18051
+ ].join(`
18052
+ `))
18053
+ };
18054
+ }
18055
+ }
18056
+ if (!workflow.usePackets) {
18057
+ for (const commandName of ["start"]) {
18058
+ const command = result[commandName];
18059
+ if (!command?.template)
18060
+ continue;
18061
+ result[commandName] = {
18062
+ ...command,
18063
+ template: prependBlock(command.template, [
18064
+ "## Runtime Workflow Override",
18065
+ "- Packetized execution is disabled.",
18066
+ "- Fall back to approved task/file-impact boundaries from the plan."
18067
+ ].join(`
18068
+ `))
18069
+ };
18070
+ }
18071
+ }
18072
+ return result;
18073
+ }
18074
+ function getWorkflowSystemCapsule() {
18075
+ const workflow = getEffectiveWorkflow();
18076
+ const roles = workflow.activeRoles.join(", ");
18077
+ const budget = workflow.subagentCallBudget;
18078
+ return [
18079
+ "## CliKit Workflow Capsule",
18080
+ "",
18081
+ `Mode: ${workflow.mode}`,
18082
+ `Active roles: ${roles}`,
18083
+ workflow.usePackets ? "Execution unit: Task Packet (1 concern, 1-3 files, one verify bundle)" : "Execution unit: plan tasks with explicit file-impact boundaries",
18084
+ "Source of truth: Beads live task state; OpenCode todos are informational only",
18085
+ workflow.usePackets ? `Subagent budget per packet: ${budget}` : `Subagent budget per unit of work: ${budget}`,
18086
+ workflow.embedVerifyInStart ? "`/start` performs execute + verify loop" : "`/start` performs execute only",
18087
+ workflow.verifyIsAudit ? "`/verify` is an optional deep audit / pre-ship confidence pass" : "`/verify` is the mandatory pre-ship gate \u2014 ship only after SHIP_READY verdict"
18088
+ ].join(`
18089
+ `);
18090
+ }
18351
18091
  const pluginConfig = loadCliKitConfig(ctx.directory) ?? {};
18352
18092
  const debugLogsEnabled = pluginConfig.hooks?.session_logging === true && process.env.CLIKIT_DEBUG === "1";
18353
18093
  const toolLogsEnabled = pluginConfig.hooks?.tool_logging === true && process.env.CLIKIT_DEBUG === "1";
@@ -18359,8 +18099,8 @@ var CliKitPlugin = async (ctx) => {
18359
18099
  const builtinAgents = getBuiltinAgents();
18360
18100
  const builtinCommands = getBuiltinCommands();
18361
18101
  const builtinSkills = getBuiltinSkills();
18362
- const filteredAgents = filterAgents(builtinAgents, pluginConfig);
18363
- const filteredCommands = filterCommands(builtinCommands, pluginConfig);
18102
+ const filteredAgents = applyWorkflowOverridesToAgents(filterAgents(builtinAgents, pluginConfig));
18103
+ const filteredCommands = applyWorkflowOverridesToCommands(filterCommands(builtinCommands, pluginConfig));
18364
18104
  const filteredSkills = filterSkills(builtinSkills, pluginConfig);
18365
18105
  if (debugLogsEnabled) {
18366
18106
  cliLog("info", "[CliKit] Plugin initializing...");
@@ -18377,42 +18117,6 @@ var CliKitPlugin = async (ctx) => {
18377
18117
  }
18378
18118
  return {
18379
18119
  tool: {
18380
- swarm: tool({
18381
- description: "Plan, monitor, delegate, and abort tasks in a multi-agent swarm. Use operation=plan to decompose work into parallel tasks, operation=monitor to check progress, operation=delegate to assign a task to an agent role, operation=abort to cancel a task.",
18382
- args: {
18383
- operation: tool.schema.enum(["plan", "monitor", "delegate", "abort"]).describe("The swarm operation to perform"),
18384
- tasks: tool.schema.array(tool.schema.object({
18385
- id: tool.schema.string(),
18386
- title: tool.schema.string(),
18387
- description: tool.schema.string(),
18388
- dependencies: tool.schema.array(tool.schema.string()).optional(),
18389
- agentRole: tool.schema.enum(["fe", "be", "mobile", "devops", "qa"]).optional(),
18390
- files: tool.schema.array(tool.schema.string()).optional(),
18391
- status: tool.schema.enum(["pending", "in_progress", "completed", "failed", "blocked"])
18392
- })).optional().describe("Tasks for operation=plan"),
18393
- parallelism: tool.schema.number().optional().describe("Max parallel tasks (default 3)"),
18394
- taskId: tool.schema.string().optional().describe("Task ID for operation=monitor|delegate|abort"),
18395
- agentRole: tool.schema.enum(["fe", "be", "mobile", "devops", "qa"]).optional().describe("Role to delegate to for operation=delegate"),
18396
- reason: tool.schema.string().optional().describe("Abort reason for operation=abort")
18397
- },
18398
- async execute(args) {
18399
- const result = swarm(args);
18400
- return JSON.stringify(result, null, 2);
18401
- }
18402
- }),
18403
- quick_research: tool({
18404
- description: "Search local memory observations and get hints for context7 and GitHub code search. Use this before starting research to check what's already known.",
18405
- args: {
18406
- query: tool.schema.string().describe("Search query"),
18407
- sources: tool.schema.array(tool.schema.enum(["memory", "context7", "github"])).optional().describe("Sources to search (default: all)"),
18408
- language: tool.schema.string().optional().describe("Language filter for GitHub search"),
18409
- limit: tool.schema.number().optional().describe("Max memory results (default 5)")
18410
- },
18411
- async execute(args) {
18412
- const result = quickResearch(args);
18413
- return JSON.stringify(result, null, 2);
18414
- }
18415
- }),
18416
18120
  context_summary: tool({
18417
18121
  description: "Summarize memory observations (decisions, learnings, blockers, progress) into a structured context digest. Useful for compaction or session handoff.",
18418
18122
  args: {
@@ -18424,18 +18128,6 @@ var CliKitPlugin = async (ctx) => {
18424
18128
  const result = contextSummary(args);
18425
18129
  return JSON.stringify(result, null, 2);
18426
18130
  }
18427
- }),
18428
- beads_memory_sync: tool({
18429
- description: "Sync between Beads task database and memory observations. Use sync_to_memory to import completed tasks as progress observations, sync_from_memory to link observations back to tasks, link to associate an observation with a task, or status to check sync state.",
18430
- args: {
18431
- operation: tool.schema.enum(["sync_to_memory", "sync_from_memory", "link", "status"]).describe("Sync operation to perform"),
18432
- beadId: tool.schema.string().optional().describe("Bead/task ID for operation=link"),
18433
- observationId: tool.schema.number().optional().describe("Observation ID for operation=link")
18434
- },
18435
- async execute(args) {
18436
- const result = beadsMemorySync(args);
18437
- return JSON.stringify(result, null, 2);
18438
- }
18439
18131
  })
18440
18132
  },
18441
18133
  config: async (config2) => {
@@ -18561,7 +18253,7 @@ var CliKitPlugin = async (ctx) => {
18561
18253
  const todoHash = JSON.stringify([...todos].sort((a, b) => a.id.localeCompare(b.id)).map((t) => `${t.id}:${t.status}`));
18562
18254
  if (todoHash !== lastTodoHash) {
18563
18255
  lastTodoHash = todoHash;
18564
- if (pluginConfig.hooks?.todo_beads_sync?.enabled !== false) {
18256
+ if (pluginConfig.hooks?.todo_beads_sync?.enabled !== false && pluginConfig.hooks?.todo_beads_sync?.mode !== "disabled") {
18565
18257
  try {
18566
18258
  const result = syncTodosToBeads(ctx.directory, sessionID, todos, pluginConfig.hooks?.todo_beads_sync);
18567
18259
  if (pluginConfig.hooks?.todo_beads_sync?.log === true) {
@@ -18589,7 +18281,7 @@ var CliKitPlugin = async (ctx) => {
18589
18281
  if (effectiveTodos.length > 0) {
18590
18282
  const result = checkTodoCompletion(effectiveTodos);
18591
18283
  if (!result.complete && todoConfig?.warn_on_incomplete !== false) {
18592
- await cliLog("warn", formatIncompleteWarning(result, sessionID));
18284
+ await cliLog("warn", formatIncompleteWarning(result, sessionID, todoConfig?.beads_authoritative === true));
18593
18285
  }
18594
18286
  }
18595
18287
  } catch (error45) {
@@ -18717,32 +18409,6 @@ var CliKitPlugin = async (ctx) => {
18717
18409
  }
18718
18410
  }
18719
18411
  }
18720
- if (pluginConfig.hooks?.swarm_enforcer?.enabled !== false) {
18721
- const editTools = ["edit", "write", "bash"];
18722
- if (editTools.some((name) => isToolNamed(toolName, name))) {
18723
- const targetFile = extractFileFromToolInput(toolName, toolInput);
18724
- try {
18725
- if (targetFile) {
18726
- const taskScope = toolInput.taskScope || input.__taskScope;
18727
- const enforcement = checkEditPermission(targetFile, taskScope, pluginConfig.hooks?.swarm_enforcer);
18728
- if (!enforcement.allowed) {
18729
- await cliLog("warn", formatEnforcementWarning(enforcement));
18730
- if (pluginConfig.hooks?.swarm_enforcer?.block_unreserved_edits) {
18731
- await showToast(enforcement.reason || "Edit blocked outside task scope", "warning", "CliKit Swarm");
18732
- blockToolExecution(enforcement.reason || "Edit outside reserved task scope");
18733
- }
18734
- } else if (pluginConfig.hooks?.swarm_enforcer?.log === true) {
18735
- await cliLog("debug", `[CliKit:swarm-enforcer] Allowed edit: ${targetFile}`);
18736
- }
18737
- }
18738
- } catch (error45) {
18739
- if (isBlockedToolExecutionError(error45)) {
18740
- throw error45;
18741
- }
18742
- await hookErr("swarm-enforcer", error45, { tool: toolName, targetFile });
18743
- }
18744
- }
18745
- }
18746
18412
  if (pluginConfig.hooks?.subagent_question_blocker?.enabled !== false) {
18747
18413
  if (isSubagentTool(toolName)) {
18748
18414
  const prompt = toolInput.prompt;
@@ -18805,6 +18471,10 @@ var CliKitPlugin = async (ctx) => {
18805
18471
  },
18806
18472
  "experimental.chat.system.transform": async (_input, output) => {
18807
18473
  const beadsConfig = pluginConfig.hooks?.beads_context;
18474
+ const workflowCapsule = getWorkflowSystemCapsule();
18475
+ if (workflowCapsule) {
18476
+ output.system.push(workflowCapsule);
18477
+ }
18808
18478
  if (beadsConfig?.enabled === false) {
18809
18479
  return;
18810
18480
  }
@@ -18822,6 +18492,10 @@ var CliKitPlugin = async (ctx) => {
18822
18492
  },
18823
18493
  "experimental.session.compacting": async (_input, output) => {
18824
18494
  const beadsConfig = pluginConfig.hooks?.beads_context;
18495
+ const workflowCapsule = getWorkflowSystemCapsule();
18496
+ if (workflowCapsule) {
18497
+ output.context.push(workflowCapsule);
18498
+ }
18825
18499
  if (beadsConfig?.enabled === false) {
18826
18500
  return;
18827
18501
  }