@loicngr/kobo 1.11.45 → 2.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 (176) hide show
  1. package/AGENTS.md +17 -2
  2. package/CHANGELOG.md +8 -0
  3. package/CODE_OF_CONDUCT.md +16 -0
  4. package/CONFIGURATION.md +1968 -0
  5. package/CONTRIBUTING.md +83 -0
  6. package/DESIGN.md +296 -0
  7. package/README.md +35 -7
  8. package/SECURITY.md +54 -0
  9. package/THIRD_PARTY_NOTICES.md +20 -0
  10. package/dist/server/db/migrations.js +23 -0
  11. package/dist/server/db/schema.js +2 -0
  12. package/dist/server/index.js +6 -0
  13. package/dist/server/routes/environment.js +18 -0
  14. package/dist/server/routes/health.js +17 -2
  15. package/dist/server/routes/integrations.js +29 -0
  16. package/dist/server/routes/settings.js +5 -0
  17. package/dist/server/routes/sounds.js +60 -0
  18. package/dist/server/routes/workspaces.js +46 -12
  19. package/dist/server/services/agent/engines/codex/options-builder.js +1 -0
  20. package/dist/server/services/agent/engines/codex/spawn.js +2 -2
  21. package/dist/server/services/agent/integration-mcp.js +49 -0
  22. package/dist/server/services/agent/orchestrator.js +6 -2
  23. package/dist/server/services/auto-loop-service.js +45 -25
  24. package/dist/server/services/custom-sound-service.js +0 -0
  25. package/dist/server/services/environment-check-service.js +125 -0
  26. package/dist/server/services/initial-prompt-template-service.js +8 -21
  27. package/dist/server/services/integration-config-service.js +65 -0
  28. package/dist/server/services/legacy-public-prompts.js +112 -0
  29. package/dist/server/services/notion-service.js +25 -61
  30. package/dist/server/services/sentry-service.js +17 -12
  31. package/dist/server/services/settings-defaults.js +5 -0
  32. package/dist/server/services/settings-service.js +112 -23
  33. package/dist/server/services/skill-suite-prompts.js +29 -22
  34. package/dist/server/services/templates-service.js +31 -8
  35. package/dist/server/services/terminal-service.js +16 -0
  36. package/dist/server/services/wakeup-service.js +7 -5
  37. package/dist/server/services/workspace-service.js +25 -4
  38. package/dist/server/services/worktree-service.js +3 -1
  39. package/dist/server/utils/git-repo-lock.js +7 -3
  40. package/dist/server/utils/mcp-client.js +26 -12
  41. package/dist/server/utils/mcp-process.js +25 -0
  42. package/dist/server/utils/node-pty-spawn-helper.js +31 -0
  43. package/dist/server/utils/paths.js +7 -0
  44. package/dist/shared/auto-loop-prompts.js +6 -2
  45. package/dist/shared/automatic-admission.js +1 -0
  46. package/dist/shared/environment.js +1 -0
  47. package/dist/shared/notification-assets.js +73 -0
  48. package/dist/shared/skill-suite-prompts.js +6 -3
  49. package/dist/shared/workflow-policy.js +25 -0
  50. package/docs/getting-started.md +47 -0
  51. package/docs/troubleshooting.md +49 -0
  52. package/package.json +19 -7
  53. package/src/client/dist/pwa/assets/ActivityFeed-DRgetl1M.js +8 -0
  54. package/src/client/dist/pwa/assets/{ChangelogPage-CnXTnFhe.js → ChangelogPage-BJdICFvz.js} +1 -1
  55. package/src/client/dist/pwa/assets/{ComparisonPanel-CKylN45q.js → ComparisonPanel-2GLd8KIy.js} +2 -2
  56. package/src/client/dist/pwa/assets/CreatePage-B9AdNJZj.js +2 -0
  57. package/src/client/dist/pwa/assets/CreatePage-B9C9J9Pw.css +1 -0
  58. package/src/client/dist/pwa/assets/DashboardPage-CzVOvjSP.js +1 -0
  59. package/src/client/dist/pwa/assets/DiffViewer-X25vuf83.js +8 -0
  60. package/src/client/dist/pwa/assets/{DocumentsPanel-BeCttB-x.js → DocumentsPanel-BastjrEm.js} +1 -1
  61. package/src/client/dist/pwa/assets/{DrawerToggleButton-BJBBYeOc.js → DrawerToggleButton-DbipGmBL.js} +1 -1
  62. package/src/client/dist/pwa/assets/{GitPanel-BFCnyhE2.css → GitPanel-C4wOcZV2.css} +1 -1
  63. package/src/client/dist/pwa/assets/GitPanel-CnW4iVao.js +3 -0
  64. package/src/client/dist/pwa/assets/{HealthPage-l88TEk-k.js → HealthPage-aieNQly-.js} +1 -1
  65. package/src/client/dist/pwa/assets/MainLayout-Cc4XzCAy.css +1 -0
  66. package/src/client/dist/pwa/assets/MainLayout-DqBbE8o4.js +2 -0
  67. package/src/client/dist/pwa/assets/{QBtnDropdown-44Mj-y_1.js → QBtnDropdown-BWy-rh45.js} +1 -1
  68. package/src/client/dist/pwa/assets/{QExpansionItem-Bok1m8Wi.js → QExpansionItem-DfmdBGuW.js} +1 -1
  69. package/src/client/dist/pwa/assets/QSelect-BfqaWakg.js +1 -0
  70. package/src/client/dist/pwa/assets/{QTooltip-BDihn2aY.js → QTooltip-Cy0T0vk2.js} +1 -1
  71. package/src/client/dist/pwa/assets/SchedulePanel-BYKSFoFj.css +1 -0
  72. package/src/client/dist/pwa/assets/SchedulePanel-YQPObRR3.js +1 -0
  73. package/src/client/dist/pwa/assets/{SearchPage-BwZ2TX1G.js → SearchPage-BoBjmItc.js} +1 -1
  74. package/src/client/dist/pwa/assets/SettingsPage-0GtDcXRC.js +9 -0
  75. package/src/client/dist/pwa/assets/{SettingsPage-W6N01tGz.css → SettingsPage-BYdLXJEJ.css} +1 -1
  76. package/src/client/dist/pwa/assets/SplitWorkspacePage-4wFh65Lh.js +1 -0
  77. package/src/client/dist/pwa/assets/{TerminalPanel-Cq-FR7A7.js → TerminalPanel-b70x_jqH.js} +4 -4
  78. package/src/client/dist/pwa/assets/{TouchPan-BQ1cvzRC.js → TouchPan-CcTVcxwd.js} +1 -1
  79. package/src/client/dist/pwa/assets/{TourReplayButton-Dz1yEz_z.js → TourReplayButton-CpEMnQS8.js} +1 -1
  80. package/src/client/dist/pwa/assets/WorkspaceAttentionLabels-C5lTHTp2.js +1 -0
  81. package/src/client/dist/pwa/assets/{WorkspacePage-BbUvR1Vf.css → WorkspacePage--5HsnMQ1.css} +1 -1
  82. package/src/client/dist/pwa/assets/WorkspacePage-D_V9gNON.js +4 -0
  83. package/src/client/dist/pwa/assets/{browser-BmWgBx9M.js → browser-LBbxVwWf.js} +1 -1
  84. package/src/client/dist/pwa/assets/{build-path-tree-6EjBmYYY.js → build-path-tree-DyvtWxb0.js} +1 -1
  85. package/src/client/dist/pwa/assets/custom-sounds-BpeLZUDW.js +1 -0
  86. package/src/client/dist/pwa/assets/de-v6i2HlE2.js +17 -0
  87. package/src/client/dist/pwa/assets/{documents-BZ8bwcjr.js → documents-Bjx8lz-h.js} +1 -1
  88. package/src/client/dist/pwa/assets/{editor.api-CK7--ckY.js → editor.api-BC3PbJkx.js} +1 -1
  89. package/src/client/dist/pwa/assets/efforts-BDHAnNUs.js +9 -0
  90. package/src/client/dist/pwa/assets/engineFeatures-hlEiwqt-.js +1 -0
  91. package/src/client/dist/pwa/assets/es-Bc1KgkAT.js +17 -0
  92. package/src/client/dist/pwa/assets/{expand-template-C8VyjASo.js → expand-template-DLDl1qPx.js} +1 -1
  93. package/src/client/dist/pwa/assets/{format-LtTLLitJ.js → format-Q94deO3I.js} +7 -7
  94. package/src/client/dist/pwa/assets/{formatters-Bl9zA7Ai.js → formatters-CWxRHuUu.js} +1 -1
  95. package/src/client/dist/pwa/assets/fr-ByYPK5vr.js +17 -0
  96. package/src/client/dist/pwa/assets/{freemarker2-DxezMaje.js → freemarker2-MPhk0eTh.js} +1 -1
  97. package/src/client/dist/pwa/assets/{handlebars-DK_Bj6Rx.js → handlebars-C60ru5gR.js} +1 -1
  98. package/src/client/dist/pwa/assets/{html-DFfsfStD.js → html-ClzchR9j.js} +1 -1
  99. package/src/client/dist/pwa/assets/i18n-Sy42tm-V.js +1 -0
  100. package/src/client/dist/pwa/assets/index-CqZ7sDcM.js +20 -0
  101. package/src/client/dist/pwa/assets/it-BYF_88z6.js +17 -0
  102. package/src/client/dist/pwa/assets/{javascript-DuNbcaL7.js → javascript-C43UJmMx.js} +1 -1
  103. package/src/client/dist/pwa/assets/{liquid-CM3JKyhv.js → liquid-CYTrvTKF.js} +1 -1
  104. package/src/client/dist/pwa/assets/{mdx-BG3zYwNF.js → mdx-CxsXOvkQ.js} +1 -1
  105. package/src/client/dist/pwa/assets/{monaco-contributions-DLscZGH-.js → monaco-contributions-Cl4-iVpK.js} +1 -1
  106. package/src/client/dist/pwa/assets/{monaco.contribution-DnhZHwXT.js → monaco.contribution-DkjLUmyA.js} +2 -2
  107. package/src/client/dist/pwa/assets/network-auth-CXQn2wO7.js +1 -0
  108. package/src/client/dist/pwa/assets/notify-theme-BrueBr2j.js +1 -0
  109. package/src/client/dist/pwa/assets/{pending-diff-open-dYIFdS4r.js → pending-diff-open-B4POItbR.js} +1 -1
  110. package/src/client/dist/pwa/assets/permissionModes-B-ciuUbz.js +36 -0
  111. package/src/client/dist/pwa/assets/{project-color-R_1je4vW.js → project-color-CM3hflLH.js} +1 -1
  112. package/src/client/dist/pwa/assets/{python-COs6pHk2.js → python-s2IMpsoV.js} +1 -1
  113. package/src/client/dist/pwa/assets/{razor-Jl1VqMsk.js → razor-DVNXiVBh.js} +1 -1
  114. package/src/client/dist/pwa/assets/render-chat-markdown-TU6CDfD8.js +69 -0
  115. package/src/client/dist/pwa/assets/{typescript-BU_TUuAM.js → typescript-BYT_8ABE.js} +1 -1
  116. package/src/client/dist/pwa/assets/use-tours-CNe8qb1q.js +2 -0
  117. package/src/client/dist/pwa/assets/workspace-templates-tBxXE52A.js +1 -0
  118. package/src/client/dist/pwa/assets/{xml-gFFsobxE.js → xml-BIG-fmxk.js} +1 -1
  119. package/src/client/dist/pwa/assets/{yaml-DaXaqaGD.js → yaml-D7gu2CQh.js} +1 -1
  120. package/src/client/dist/pwa/index.html +1 -1
  121. package/src/client/dist/pwa/sounds/neutral.wav +0 -0
  122. package/src/client/dist/pwa/sounds/ready.wav +0 -0
  123. package/src/client/dist/pwa/sw.js +1 -1
  124. package/src/client/dist/pwa/assets/ActivityFeed-CLXjdqS8.js +0 -8
  125. package/src/client/dist/pwa/assets/CreatePage-SoCcvxuD.js +0 -2
  126. package/src/client/dist/pwa/assets/CreatePage-TY9g3hZb.css +0 -1
  127. package/src/client/dist/pwa/assets/DashboardPage-CZQLfoV1.js +0 -1
  128. package/src/client/dist/pwa/assets/DiffViewer-Csf3WmLc.js +0 -8
  129. package/src/client/dist/pwa/assets/GitPanel-B-ZHgghQ.js +0 -3
  130. package/src/client/dist/pwa/assets/MainLayout-BAAQLq95.css +0 -1
  131. package/src/client/dist/pwa/assets/MainLayout-Cf4Q9x1u.js +0 -2
  132. package/src/client/dist/pwa/assets/QDrawer-B4qHw8wt.js +0 -1
  133. package/src/client/dist/pwa/assets/QSelect-BbtD5Iks.js +0 -1
  134. package/src/client/dist/pwa/assets/SchedulePanel-BAA4Aajn.css +0 -1
  135. package/src/client/dist/pwa/assets/SchedulePanel-DiWCDNZ8.js +0 -1
  136. package/src/client/dist/pwa/assets/SettingsPage-BUh0WfNf.js +0 -9
  137. package/src/client/dist/pwa/assets/SplitWorkspacePage-Bg6nKBcA.js +0 -1
  138. package/src/client/dist/pwa/assets/WorkspaceAttentionLabels-BCVOP8vp.js +0 -1
  139. package/src/client/dist/pwa/assets/WorkspacePage-Cl8gap4b.js +0 -4
  140. package/src/client/dist/pwa/assets/de-COObokpu.js +0 -17
  141. package/src/client/dist/pwa/assets/efforts-Bw0o2Bud.js +0 -9
  142. package/src/client/dist/pwa/assets/engineFeatures-DQO9HHXI.js +0 -1
  143. package/src/client/dist/pwa/assets/es-By2Q9Tca.js +0 -17
  144. package/src/client/dist/pwa/assets/fouet-ahh-DdxrUXRj.mp3 +0 -0
  145. package/src/client/dist/pwa/assets/fr-D-sd0ddn.js +0 -17
  146. package/src/client/dist/pwa/assets/i18n-aDWy4KHt.js +0 -1
  147. package/src/client/dist/pwa/assets/index-BLd8DAzg.js +0 -20
  148. package/src/client/dist/pwa/assets/it-CeK5lyIA.js +0 -17
  149. package/src/client/dist/pwa/assets/network-auth-BJiPbO5l.js +0 -1
  150. package/src/client/dist/pwa/assets/notify-theme-D4p3qPkp.js +0 -1
  151. package/src/client/dist/pwa/assets/permissionModes-B7fuUegU.js +0 -36
  152. package/src/client/dist/pwa/assets/render-chat-markdown-AaOo0Tgq.js +0 -67
  153. package/src/client/dist/pwa/assets/use-tours-CVn874kD.js +0 -2
  154. package/src/client/dist/pwa/assets/workspace-templates-BCKR8TXr.js +0 -1
  155. package/src/client/dist/pwa/sounds/7eme-compagnie-03.mp3 +0 -0
  156. package/src/client/dist/pwa/sounds/aller-ftg.mp3 +0 -0
  157. package/src/client/dist/pwa/sounds/arrete-de-mentir.mp3 +0 -0
  158. package/src/client/dist/pwa/sounds/arretez-les-messages.mp3 +0 -0
  159. package/src/client/dist/pwa/sounds/bah-alors-on-est-nul.mp3 +0 -0
  160. package/src/client/dist/pwa/sounds/basic-notification.mp3 +0 -0
  161. package/src/client/dist/pwa/sounds/ca_va_peter.mp3 +0 -0
  162. package/src/client/dist/pwa/sounds/dry-fart.mp3 +0 -0
  163. package/src/client/dist/pwa/sounds/faaah.mp3 +0 -0
  164. package/src/client/dist/pwa/sounds/for-shure.mp3 +0 -0
  165. package/src/client/dist/pwa/sounds/gta-v-death.mp3 +0 -0
  166. package/src/client/dist/pwa/sounds/hey.mp3 +0 -0
  167. package/src/client/dist/pwa/sounds/mais-laisse-moi-dormir-zebi.mp3 +0 -0
  168. package/src/client/dist/pwa/sounds/nan-tu-degages.mp3 +0 -0
  169. package/src/client/dist/pwa/sounds/nan-wallah-pardon.mp3 +0 -0
  170. package/src/client/dist/pwa/sounds/ouais-cest-greg.mp3 +0 -0
  171. package/src/client/dist/pwa/sounds/pas-ca-zinedine.mp3 +0 -0
  172. package/src/client/dist/pwa/sounds/ta-gueule.mp3 +0 -0
  173. package/src/client/dist/pwa/sounds/travail_termine.mp3 +0 -0
  174. package/src/client/dist/pwa/sounds/tu-vas-la-fermer.mp3 +0 -0
  175. package/src/client/dist/pwa/sounds/warcraft-3-humain-travail.mp3 +0 -0
  176. package/src/client/dist/pwa/sounds/yaaa.mp3 +0 -0
@@ -1,16 +1,24 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { MASK_CHARACTER, MASKED_SECRET, SECRET_GLOBAL_KEYS, WORKTREES_PATH } from '../../shared/consts.js';
4
+ import { normalizePublicSounds } from '../../shared/notification-assets.js';
4
5
  import { isValidProjectColor } from '../../shared/project-colors.js';
5
6
  import { isValidSkillSuite } from '../../shared/skill-suite-prompts.js';
6
7
  import { DEFAULT_WHIP_SHORTCUT, isValidWhipShortcut } from '../../shared/whip-shortcut.js';
8
+ import { isWorkflowPolicy, LEGACY_WORKFLOW_POLICY, MANUAL_WORKFLOW_POLICY, resolveWorkflowPolicy, } from '../../shared/workflow-policy.js';
7
9
  import { listClaudeMcpEntries } from '../utils/mcp-client.js';
8
10
  import { getSettingsPath } from '../utils/paths.js';
9
11
  import { InvalidWorktreesPathError, resolveGlobalWorktreesRoot, sanitizeWorktreesPath, validateWorktreesPath, } from '../utils/worktree-paths.js';
10
12
  import { DEFAULT_NOTION_INITIAL_PROMPT, DEFAULT_SENTRY_INITIAL_PROMPT } from './initial-prompt-template-service.js';
13
+ import { LEGACY_AGNOSTIC_AUTO_LOOP_REVIEW_GATE, LEGACY_AGNOSTIC_REVIEW_TEMPLATE, LEGACY_CI_FIX_PROMPT_TEMPLATE, LEGACY_FINALIZATION_PROMPT, LEGACY_NOTION_INITIAL_PROMPT, LEGACY_PR_PROMPT_TEMPLATE, LEGACY_SENTRY_INITIAL_PROMPT, } from './legacy-public-prompts.js';
11
14
  import { DEFAULT_REVIEW_PROMPT_TEMPLATE } from './review-template-service.js';
12
- import { DEFAULT_CHANGE_SOURCE_BRANCH_SCRIPT, DEFAULT_MODEL_BY_ENGINE } from './settings-defaults.js';
15
+ import { DEFAULT_CHANGE_SOURCE_BRANCH_SCRIPT, DEFAULT_MODEL_BY_ENGINE, FRESH_MODEL_BY_ENGINE, } from './settings-defaults.js';
13
16
  import { AGNOSTIC_PROMPTS } from './skill-suite-prompts.js';
17
+ export const STANDARD_GIT_CONVENTIONS = `Follow the repository's existing Git conventions and the user's instructions.
18
+ Work locally by default. Commit, push, publish comments or open pull requests only when explicitly authorized.
19
+ Inspect git status and all staged, unstaged and untracked changes before staging. Preserve unrelated work.
20
+ Never rewrite shared history or run destructive Git commands without explicit authorization.
21
+ `;
14
22
  export const DEFAULT_GIT_CONVENTIONS = `# Git conventions
15
23
 
16
24
  ## Commits
@@ -55,8 +63,8 @@ Steps:
55
63
  1. For each failing job, fetch its logs from the forge and pinpoint the root cause.
56
64
  2. Fix the underlying issue locally — never disable a check or skip a test to "fix" CI.
57
65
  3. Run the relevant lint / type-check / test commands locally to verify the fix.
58
- 4. Commit with a clear, conventional message and push to the same branch.
59
- 5. Wait for CI to re-run and confirm every job now passes.
66
+ 4. Report the local changes and checks. Commit or push only when explicitly authorized; otherwise leave the fix local.
67
+ 5. If a push was authorized, wait for CI to re-run and report its result.
60
68
  `;
61
69
  export const DEFAULT_PR_PROMPT_TEMPLATE = `A pull request has been opened: {{pr_url}} (#{{pr_number}})
62
70
 
@@ -79,15 +87,15 @@ Acceptance criteria:
79
87
  {{acceptance_criteria}}
80
88
 
81
89
  Please:
82
- 1. Review the PR description on GitHub and improve it if needed (add a proper summary, screenshots if relevant, a test plan)
90
+ 1. Read the PR/MR description using the configured forge and propose improvements locally (summary, screenshots if relevant, test plan)
83
91
  2. Verify that all acceptance criteria are checked
84
- 3. Post a comment on the PR summarizing what was done and any follow-up items
85
- 4. Do NOT add a "Generated with Claude Code" footer or any AI attribution to the PR description
92
+ 3. Draft a summary of the work and follow-up items locally. Publish comments or edit the PR/MR only when explicitly authorized.
93
+ 4. Follow the repository policy for attribution and PR/MR formatting.
86
94
  `;
87
95
  export const DEFAULT_FINALIZATION_PROMPT = `Run final quality checks before closing the workspace:
88
96
 
89
97
  1. Verify all work tasks and acceptance criteria are marked \`done\`. If any remain pending/in_progress, keep finalization open and report them.
90
- 2. Run the project's linters, type-checkers, and tests (see CLAUDE.md or package.json scripts).
98
+ 2. Run the project's linters, type-checkers, and tests (see the repository instructions and existing build/test configuration).
91
99
  3. If any check fails or cannot be run, create a regular repair task with a title like \`Fix lint failure in X\` (role \`work\`, no \`[FINAL]\` prefix), record the failed/not_run checks and leave this finalization task pending. Kōbō will process the repairs first, then run final verification again against the repaired state.
92
100
  4. Only after all required checks actually pass, mark this task as \`done\` with structured verification: method, summary, and the named checks with status \`passed\`.
93
101
 
@@ -254,11 +262,11 @@ const settingsMigrations = [
254
262
  migrate({ projects }) {
255
263
  for (const p of projects) {
256
264
  if (!p.finalization || typeof p.finalization !== 'object') {
257
- p.finalization = { prompt: DEFAULT_FINALIZATION_PROMPT };
265
+ p.finalization = { prompt: LEGACY_FINALIZATION_PROMPT };
258
266
  }
259
267
  else if (typeof p.finalization.prompt !== 'string') {
260
268
  ;
261
- p.finalization.prompt = DEFAULT_FINALIZATION_PROMPT;
269
+ p.finalization.prompt = LEGACY_FINALIZATION_PROMPT;
262
270
  }
263
271
  }
264
272
  },
@@ -317,10 +325,10 @@ const settingsMigrations = [
317
325
  name: 'add-notion-sentry-initial-prompts',
318
326
  migrate({ global, projects }) {
319
327
  if (typeof global.notionInitialPromptTemplate !== 'string') {
320
- global.notionInitialPromptTemplate = DEFAULT_NOTION_INITIAL_PROMPT;
328
+ global.notionInitialPromptTemplate = LEGACY_NOTION_INITIAL_PROMPT;
321
329
  }
322
330
  if (typeof global.sentryInitialPromptTemplate !== 'string') {
323
- global.sentryInitialPromptTemplate = DEFAULT_SENTRY_INITIAL_PROMPT;
331
+ global.sentryInitialPromptTemplate = LEGACY_SENTRY_INITIAL_PROMPT;
324
332
  }
325
333
  for (const p of projects) {
326
334
  if (typeof p.notionInitialPromptTemplate !== 'string') {
@@ -447,10 +455,10 @@ const settingsMigrations = [
447
455
  global.skillSuite = 'superpowers';
448
456
  }
449
457
  if (typeof global.customReviewTemplate !== 'string') {
450
- global.customReviewTemplate = AGNOSTIC_PROMPTS.reviewTemplate;
458
+ global.customReviewTemplate = LEGACY_AGNOSTIC_REVIEW_TEMPLATE;
451
459
  }
452
460
  if (typeof global.customAutoLoopReviewGate !== 'string') {
453
- global.customAutoLoopReviewGate = AGNOSTIC_PROMPTS.autoLoopReviewGate;
461
+ global.customAutoLoopReviewGate = LEGACY_AGNOSTIC_AUTO_LOOP_REVIEW_GATE;
454
462
  }
455
463
  if (typeof global.customAutoLoopGroomingIntro !== 'string') {
456
464
  global.customAutoLoopGroomingIntro = AGNOSTIC_PROMPTS.autoLoopGroomingIntro;
@@ -586,7 +594,7 @@ const settingsMigrations = [
586
594
  name: 'add-ci-fix-prompt-template',
587
595
  migrate: ({ global, projects }) => {
588
596
  if (typeof global.ciFixPromptTemplate !== 'string') {
589
- global.ciFixPromptTemplate = DEFAULT_CI_FIX_PROMPT_TEMPLATE;
597
+ global.ciFixPromptTemplate = LEGACY_CI_FIX_PROMPT_TEMPLATE;
590
598
  }
591
599
  for (const p of projects) {
592
600
  if (typeof p.ciFixPromptTemplate !== 'string')
@@ -632,7 +640,7 @@ const settingsMigrations = [
632
640
  // Seed the global default; projects keep their own override (or empty to
633
641
  // inherit this global value — cascade handled by getEffectiveFinalization).
634
642
  if (typeof global.finalizationPrompt !== 'string') {
635
- global.finalizationPrompt = DEFAULT_FINALIZATION_PROMPT;
643
+ global.finalizationPrompt = LEGACY_FINALIZATION_PROMPT;
636
644
  }
637
645
  },
638
646
  },
@@ -909,6 +917,59 @@ const settingsMigrations = [
909
917
  global.activityDigestEnabled = true;
910
918
  },
911
919
  },
920
+ {
921
+ version: 59,
922
+ name: 'neutral-built-in-prompts',
923
+ migrate: ({ global, projects }) => {
924
+ const defaults = [
925
+ ['customReviewTemplate', LEGACY_AGNOSTIC_REVIEW_TEMPLATE, AGNOSTIC_PROMPTS.reviewTemplate],
926
+ ['customAutoLoopReviewGate', LEGACY_AGNOSTIC_AUTO_LOOP_REVIEW_GATE, AGNOSTIC_PROMPTS.autoLoopReviewGate],
927
+ ['notionInitialPromptTemplate', LEGACY_NOTION_INITIAL_PROMPT, DEFAULT_NOTION_INITIAL_PROMPT],
928
+ ['sentryInitialPromptTemplate', LEGACY_SENTRY_INITIAL_PROMPT, DEFAULT_SENTRY_INITIAL_PROMPT],
929
+ ['ciFixPromptTemplate', LEGACY_CI_FIX_PROMPT_TEMPLATE, DEFAULT_CI_FIX_PROMPT_TEMPLATE],
930
+ ['prPromptTemplate', LEGACY_PR_PROMPT_TEMPLATE, DEFAULT_PR_PROMPT_TEMPLATE],
931
+ ['finalizationPrompt', LEGACY_FINALIZATION_PROMPT, DEFAULT_FINALIZATION_PROMPT],
932
+ ];
933
+ for (const [key, previous, next] of defaults) {
934
+ if (global[key] === previous)
935
+ global[key] = next;
936
+ for (const project of projects) {
937
+ if (project[key] === previous)
938
+ project[key] = next;
939
+ }
940
+ }
941
+ for (const project of projects) {
942
+ const finalization = project.finalization;
943
+ if (finalization?.prompt === LEGACY_FINALIZATION_PROMPT)
944
+ finalization.prompt = DEFAULT_FINALIZATION_PROMPT;
945
+ }
946
+ },
947
+ },
948
+ {
949
+ version: 60,
950
+ name: 'add-onboarding-completion',
951
+ migrate: ({ global }) => {
952
+ if (typeof global.onboardingComplete !== 'boolean')
953
+ global.onboardingComplete = true;
954
+ },
955
+ },
956
+ {
957
+ version: 61,
958
+ name: 'original-public-notification-sounds',
959
+ migrate: ({ global }) => normalizePublicSounds(global),
960
+ },
961
+ {
962
+ version: 62,
963
+ name: 'explicit-workflow-preferences',
964
+ migrate: ({ global, projects }) => {
965
+ if (!isWorkflowPolicy(global.workflowPolicy))
966
+ global.workflowPolicy = { ...LEGACY_WORKFLOW_POLICY };
967
+ for (const project of projects) {
968
+ if (!isWorkflowPolicy(project.workflowPolicy))
969
+ project.workflowPolicy = {};
970
+ }
971
+ },
972
+ },
912
973
  ];
913
974
  /** Current settings schema version — always equals the highest migration version. */
914
975
  export const SETTINGS_SCHEMA_VERSION = settingsMigrations.length > 0 ? settingsMigrations[settingsMigrations.length - 1].version : 0;
@@ -938,7 +999,9 @@ function defaultSettings() {
938
999
  return {
939
1000
  schemaVersion: SETTINGS_SCHEMA_VERSION,
940
1001
  global: {
941
- defaultModelByEngine: { ...DEFAULT_MODEL_BY_ENGINE },
1002
+ workflowPolicy: { ...MANUAL_WORKFLOW_POLICY },
1003
+ onboardingComplete: false,
1004
+ defaultModelByEngine: { ...FRESH_MODEL_BY_ENGINE },
942
1005
  dangerouslySkipPermissions: true,
943
1006
  prPromptTemplate: DEFAULT_PR_PROMPT_TEMPLATE,
944
1007
  reviewPromptTemplate: DEFAULT_REVIEW_PROMPT_TEMPLATE,
@@ -946,7 +1009,7 @@ function defaultSettings() {
946
1009
  finalizationPrompt: DEFAULT_FINALIZATION_PROMPT,
947
1010
  notionInitialPromptTemplate: DEFAULT_NOTION_INITIAL_PROMPT,
948
1011
  sentryInitialPromptTemplate: DEFAULT_SENTRY_INITIAL_PROMPT,
949
- gitConventions: DEFAULT_GIT_CONVENTIONS,
1012
+ gitConventions: STANDARD_GIT_CONVENTIONS,
950
1013
  setupScript: '',
951
1014
  cleanupScript: '',
952
1015
  cleanupScriptMode: 'no-tasks',
@@ -963,7 +1026,7 @@ function defaultSettings() {
963
1026
  autoLoopMaxRetries: 5,
964
1027
  awaitingUserReminderMinutes: 0,
965
1028
  activityDigestEnabled: true,
966
- maxConcurrentAgents: 0,
1029
+ maxConcurrentAgents: 2,
967
1030
  wsEventsRetentionDays: 0,
968
1031
  wsEventsKeepPerWorkspace: 0,
969
1032
  networkAccessEnabled: false,
@@ -972,11 +1035,11 @@ function defaultSettings() {
972
1035
  bitbucketToken: '',
973
1036
  bitbucketUsername: '',
974
1037
  browserNotifications: true,
975
- audioNotifications: true,
1038
+ audioNotifications: false,
976
1039
  audioQuestionNotifications: false,
977
1040
  audioWorkspaceCreatedNotifications: false,
978
1041
  audioAgentErrorNotifications: false,
979
- audioNotificationSound: 'hey.mp3',
1042
+ audioNotificationSound: 'neutral.wav',
980
1043
  audioQuestionSound: 'inherit',
981
1044
  audioWorkspaceCreatedSound: 'inherit',
982
1045
  audioAgentErrorSound: 'inherit',
@@ -1012,8 +1075,8 @@ function defaultSettings() {
1012
1075
  defaultPermissionModeByEngine: { 'claude-code': 'plan', codex: 'plan' },
1013
1076
  notionMcpKey: '',
1014
1077
  sentryMcpKey: '',
1015
- notionEnabled: true,
1016
- sentryEnabled: true,
1078
+ notionEnabled: false,
1079
+ sentryEnabled: false,
1017
1080
  showThinkingBlocks: true,
1018
1081
  whipEnabled: false,
1019
1082
  whipShortcut: DEFAULT_WHIP_SHORTCUT,
@@ -1033,7 +1096,7 @@ function defaultSettings() {
1033
1096
  voiceTranslateToEnglish: false,
1034
1097
  voiceSuppressNonSpeechTokens: true,
1035
1098
  flattenWorkspaceList: false,
1036
- skillSuite: 'superpowers',
1099
+ skillSuite: 'standard',
1037
1100
  customReviewTemplate: AGNOSTIC_PROMPTS.reviewTemplate,
1038
1101
  customAutoLoopReviewGate: AGNOSTIC_PROMPTS.autoLoopReviewGate,
1039
1102
  customAutoLoopGroomingIntro: AGNOSTIC_PROMPTS.autoLoopGroomingIntro,
@@ -1045,6 +1108,7 @@ function defaultSettings() {
1045
1108
  }
1046
1109
  function defaultProjectSettings(projectPath) {
1047
1110
  return {
1111
+ workflowPolicy: {},
1048
1112
  path: projectPath,
1049
1113
  displayName: '',
1050
1114
  defaultSourceBranch: '',
@@ -1103,10 +1167,18 @@ export function runSettingsMigrations(raw) {
1103
1167
  version = m.version;
1104
1168
  }
1105
1169
  }
1170
+ if (typeof current.global.onboardingComplete !== 'boolean')
1171
+ current.global.onboardingComplete = true;
1172
+ current.global.workflowPolicy = resolveWorkflowPolicy(current.global.workflowPolicy);
1173
+ for (const project of current.projects) {
1174
+ if (!isWorkflowPolicy(project.workflowPolicy))
1175
+ project.workflowPolicy = {};
1176
+ }
1106
1177
  current.global.worktreesPath = sanitizeWorktreesPath(current.global.worktreesPath);
1107
1178
  current.global.whipEnabled = current.global.whipEnabled === true;
1108
1179
  current.global.whipShortcut = normalizeWhipShortcut(current.global.whipShortcut);
1109
1180
  current.global.whipVolume = normalizeWhipVolume(current.global.whipVolume);
1181
+ normalizePublicSounds(current.global);
1110
1182
  current.schemaVersion = version;
1111
1183
  return current;
1112
1184
  }
@@ -1472,7 +1544,16 @@ export function updateGlobalSettings(input) {
1472
1544
  if ('activityDigestEnabled' in data && typeof data.activityDigestEnabled !== 'boolean') {
1473
1545
  delete data.activityDigestEnabled;
1474
1546
  }
1547
+ if ('onboardingComplete' in data && typeof data.onboardingComplete !== 'boolean')
1548
+ delete data.onboardingComplete;
1549
+ if ('workflowPolicy' in data) {
1550
+ if (!isWorkflowPolicy(data.workflowPolicy))
1551
+ throw new Error('Invalid workflowPolicy');
1552
+ data.workflowPolicy = resolveWorkflowPolicy(settings.global.workflowPolicy, data.workflowPolicy);
1553
+ }
1475
1554
  const allowedGlobalKeys = [
1555
+ 'workflowPolicy',
1556
+ 'onboardingComplete',
1476
1557
  'defaultModelByEngine',
1477
1558
  'dangerouslySkipPermissions',
1478
1559
  'prPromptTemplate',
@@ -1573,6 +1654,7 @@ export function updateGlobalSettings(input) {
1573
1654
  'customBrainstormingInstruction',
1574
1655
  ];
1575
1656
  const filtered = pickKnownKeys(data, allowedGlobalKeys);
1657
+ normalizePublicSounds(filtered);
1576
1658
  if (filtered.tags !== undefined) {
1577
1659
  filtered.tags = Array.isArray(filtered.tags)
1578
1660
  ? Array.from(new Set(filtered.tags
@@ -1686,7 +1768,10 @@ export function upsertProject(projectPath, data) {
1686
1768
  delete data.cleanupScriptMode;
1687
1769
  }
1688
1770
  }
1771
+ if ('workflowPolicy' in data && !isWorkflowPolicy(data.workflowPolicy))
1772
+ throw new Error('Invalid workflowPolicy');
1689
1773
  const allowedProjectKeys = [
1774
+ 'workflowPolicy',
1690
1775
  'displayName',
1691
1776
  'defaultSourceBranch',
1692
1777
  'defaultModel',
@@ -1785,3 +1870,7 @@ export function listActiveClaudeMcpServers() {
1785
1870
  args: entry.args ?? [],
1786
1871
  }));
1787
1872
  }
1873
+ /** Resolve inheritance before taking a new workspace snapshot. */
1874
+ export function getEffectiveWorkflowPolicy(projectPath, override) {
1875
+ return resolveWorkflowPolicy(getGlobalSettings().workflowPolicy, getProjectSettings(projectPath)?.workflowPolicy, override);
1876
+ }
@@ -12,7 +12,7 @@ const REVIEW_BODY = `## Scope
12
12
 
13
13
  Review ALL changes — both committed and uncommitted in the working tree:
14
14
  - \`git diff {{base_commit}}..HEAD\` — committed changes on this branch
15
- - \`git status\` and \`git diff\` — uncommitted changes (staged + unstaged)
15
+ - \`git status\` and \`git diff\` / \`git diff --cached\` — unstaged / staged changes; inspect untracked files too
16
16
 
17
17
  ## Diff summary
18
18
  {{diff_stats}}
@@ -36,20 +36,21 @@ export const SUPERPOWERS_PROMPTS = {
36
36
  reviewTemplate: REVIEW_HEADER +
37
37
  'If a code-review skill is available (e.g. superpowers:requesting-code-review), invoke it to drive this review. Otherwise follow the steps below directly.\n\n' +
38
38
  REVIEW_BODY,
39
- autoLoopReviewGate: 'Code review gate — BEFORE marking the task done, dispatch an independent code-reviewer subagent via the Task tool with `subagent_type: "code-reviewer"` (or `"superpowers:code-reviewer"` / `"pr-review-toolkit:code-reviewer"` — use whichever exists in this environment; fall back to `superpowers:requesting-code-review` skill if none is available). Brief the reviewer with: what you just implemented, the task title, and the commit SHA (via `git rev-parse HEAD`). Ask specifically whether the change matches the task scope, whether edge cases are handled, and whether the commit is clean.',
39
+ autoLoopReviewGate: 'If the named skills or subagents are unavailable, review the full diff manually with the same checks. Code review gate — BEFORE marking the task done, dispatch an independent code-reviewer subagent via the Task tool with `subagent_type: "code-reviewer"` (or `"superpowers:code-reviewer"` / `"pr-review-toolkit:code-reviewer"` — use whichever exists in this environment; fall back to `superpowers:requesting-code-review` skill if none is available). Brief the reviewer with: what you just implemented, the task title, and the commit SHA (via `git rev-parse HEAD`). Ask specifically whether the change matches the task scope, whether edge cases are handled, and whether committed and uncommitted changes (including staged and untracked files) are correct.',
40
40
  autoLoopGroomingIntro: GROOMING_INTRO_SUPERPOWERS,
41
41
  qaPromptTemplate: 'QA pass for workspace "{{workspace_name}}" in project {{project_name}}.\n\nBranch: {{branch_name}}\nStaging URL: {{staging_url}}\n\nIf a QA-style skill that drives a real browser is available in this environment (e.g. via the superpowers-chrome browsing skill), use it to navigate the staging URL and exercise the changes. Otherwise, fall back to manually scripting the smoke checks and recording your findings as a bug report.',
42
- brainstormingInstruction: 'Brainstorm the implementation approach with discipline:\n' +
42
+ brainstormingInstruction: 'Use only skills and tools actually available in this session. If a named skill is unavailable, perform its described planning or review steps directly. Do not install tools or expand permissions automatically.\n' +
43
+ 'Brainstorm the implementation approach with discipline:\n' +
43
44
  '1. Use the `superpowers:brainstorming` skill — it walks you through purpose, requirements, and design BEFORE any code. Ask clarifying questions and wait for explicit user approval on the design before moving on.\n' +
44
45
  '2. Use `superpowers:writing-plans` to turn the approved design into a multi-step implementation plan, saved under `docs/superpowers/plans/`.\n' +
45
46
  '3. If you encounter a bug or unexpected behaviour during exploration, use `superpowers:systematic-debugging` rather than guessing.\n' +
46
- "Do NOT skip the skills or rationalise around them — that's how the rigour gets lost.",
47
+ 'Apply the planning and review steps rigorously; when a named skill is unavailable, perform those steps directly.',
47
48
  };
48
49
  export const GSTACK_PROMPTS = {
49
50
  reviewTemplate: REVIEW_HEADER +
50
51
  'Run /review to drive this audit (the gstack Staff Engineer skill — finds bugs that pass CI but blow up in production, auto-fixes the obvious ones, flags completeness gaps). If /review is unavailable in this environment, fall back to the manual checklist below.\n\n' +
51
52
  REVIEW_BODY,
52
- autoLoopReviewGate: 'Code review gate — BEFORE marking the task done, run /review (the gstack Staff Engineer skill). Brief it with: what you just implemented, the task title, and the commit SHA (via `git rev-parse HEAD`). Ask specifically whether the change matches the task scope, whether edge cases are handled, and whether the commit is clean. If /review auto-fixes minor issues, accept the fixes via an amend or fix-up commit, then re-run step 3 checks.',
53
+ autoLoopReviewGate: 'If the named skills or subagents are unavailable, review the full diff manually with the same checks. Code review gate — BEFORE marking the task done, run /review (the gstack Staff Engineer skill). Brief it with: what you just implemented, the task title, and the commit SHA (via `git rev-parse HEAD`). Ask specifically whether the change matches the task scope, whether edge cases are handled, and whether committed and uncommitted changes (including staged and untracked files) are correct. If /review auto-fixes minor issues, apply fixes locally and re-run checks; commit only when explicitly authorized.',
53
54
  autoLoopGroomingIntro: GROOMING_INTRO_GSTACK,
54
55
  qaPromptTemplate: `QA pass for workspace "{{workspace_name}}" in project {{project_name}}.
55
56
 
@@ -64,10 +65,11 @@ Pick the right gstack tool for the situation:
64
65
  - **Standard** — adds medium-severity bugs.
65
66
  - **Exhaustive** — adds cosmetic issues.
66
67
  - \`/qa-only {{staging_url}}\` — Same methodology as \`/qa\` but report only, no code changes. Use when you only want a bug report.
67
- - \`/design-review\` — Visual audit (consistency, spacing, hierarchy, AI slop). Commits atomic fixes with before/after screenshots.
68
+ - \`/design-review\` — Visual audit (consistency, spacing, hierarchy, AI slop). Prepare local fixes with before/after screenshots. Commit only when explicitly authorized; if the skill cannot avoid automatic commits, perform the visual audit manually.
68
69
 
69
- For reproducible regression coverage that runs on every PR, prefer **Cypress** specs in \`test/cypress/\` instead of \`/qa\`. Reserve the gstack tools above for exploration, dogfooding, and one-shot visual debugging.`,
70
- brainstormingInstruction: 'Brainstorm the implementation approach using the gstack sprint pipeline:\n' +
70
+ For reproducible regression coverage that runs on every PR, use the project's configured test framework and existing test directory instead of \`/qa\`. Reserve the gstack tools above for exploration, dogfooding, and one-shot visual debugging.`,
71
+ brainstormingInstruction: 'Use only skills and tools actually available in this session. If a named skill is unavailable, perform its described planning or review steps directly. Do not install tools or expand permissions automatically.\n' +
72
+ 'Brainstorm the implementation approach using the gstack sprint pipeline:\n' +
71
73
  '1. Run `/office-hours` — six forcing questions that reframe the problem and write a design doc. This is where you challenge premises and surface alternatives before any code.\n' +
72
74
  '2. Run `/autoplan` — it chains CEO → design → eng → DX reviews automatically (auto-detects which apply) and surfaces only the taste decisions you need to approve. Prefer this over manual orchestration.\n' +
73
75
  '3. If you need fine control (e.g. skip a step, run one in isolation), invoke the individual skills instead: `/plan-ceo-review`, `/plan-eng-review`, `/plan-design-review`, `/plan-devex-review`.\n' +
@@ -77,14 +79,15 @@ export const ECC_PROMPTS = {
77
79
  reviewTemplate: REVIEW_HEADER +
78
80
  'If a code-review skill is available (e.g. `ecc:code-review`, or dispatch a subagent via the Task tool with `subagent_type: "ecc:code-reviewer"`), invoke it to drive this review. Otherwise follow the steps below directly.\n\n' +
79
81
  REVIEW_BODY,
80
- autoLoopReviewGate: 'Code review gate — BEFORE marking the task done, dispatch an independent code-reviewer subagent via the Task tool with `subagent_type: "ecc:code-reviewer"` (or run the `ecc:code-review` / `ecc:quality-gate` skill if you prefer a driven workflow over a bare subagent). Brief the reviewer with: what you just implemented, the task title, and the commit SHA (via `git rev-parse HEAD`). Ask specifically whether the change matches the task scope, whether edge cases are handled, and whether the commit is clean.',
82
+ autoLoopReviewGate: 'If the named skills or subagents are unavailable, review the full diff manually with the same checks. Code review gate — BEFORE marking the task done, dispatch an independent code-reviewer subagent via the Task tool with `subagent_type: "ecc:code-reviewer"` (or run the `ecc:code-review` / `ecc:quality-gate` skill if you prefer a driven workflow over a bare subagent). Brief the reviewer with: what you just implemented, the task title, and the commit SHA (via `git rev-parse HEAD`). Ask specifically whether the change matches the task scope, whether edge cases are handled, and whether committed and uncommitted changes (including staged and untracked files) are correct.',
81
83
  autoLoopGroomingIntro: GROOMING_INTRO_ECC,
82
84
  qaPromptTemplate: 'QA pass for workspace "{{workspace_name}}" in project {{project_name}}.\n\nBranch: {{branch_name}}\nStaging URL: {{staging_url}}\n\nIf a QA-style skill is available in this environment (e.g. `ecc:browser-qa`, or dispatch a subagent via the Task tool with `subagent_type: "ecc:e2e-runner"`), use it to exercise the staging URL. Otherwise, fall back to manually scripting the smoke checks and recording your findings as a bug report.',
83
- brainstormingInstruction: 'Brainstorm the implementation approach using the ECC pipeline:\n' +
85
+ brainstormingInstruction: 'Use only skills and tools actually available in this session. If a named skill is unavailable, perform its described planning or review steps directly. Do not install tools or expand permissions automatically.\n' +
86
+ 'Brainstorm the implementation approach using the ECC pipeline:\n' +
84
87
  '1. Run the `ecc:plan` skill (or dispatch a subagent via the Task tool with `subagent_type: "ecc:planner"`) — it expands the request into a full spec with features, sprints, and evaluation criteria before any code. Ask clarifying questions and wait for explicit user approval on the design before moving on.\n' +
85
88
  '2. Use `ecc:tdd-workflow` to shape the approved design into a test-first implementation plan.\n' +
86
89
  '3. If you encounter a bug or unexpected behaviour during exploration, dispatch a subagent via the Task tool with `subagent_type: "ecc:architect"` (or the relevant language-specific `ecc:*-reviewer` agent) rather than guessing.\n' +
87
- "Do NOT skip the skills or rationalise around them — that's how the rigour gets lost.",
90
+ 'Apply the planning and review steps rigorously; when a named skill is unavailable, perform those steps directly.',
88
91
  };
89
92
  export const AGNOSTIC_PROMPTS = {
90
93
  reviewTemplate: AGNOSTIC_REVIEW_TEMPLATE,
@@ -103,15 +106,15 @@ export const AGNOSTIC_PROMPTS = {
103
106
  // - superpowers-chrome:browsing → low-level browser control fallback
104
107
  export const COMBINED_PROMPTS = {
105
108
  reviewTemplate: REVIEW_HEADER +
106
- 'Two complementary review skills are available — pick by intent:\n' +
109
+ 'If installed, these complementary review skills can be used — pick by intent:\n' +
107
110
  '- `/review` (gstack Staff Engineer) for tactical bug-hunting that finds issues passing CI but blowing up in production. Auto-fixes the obvious ones.\n' +
108
111
  '- `superpowers:requesting-code-review` for principles-level critique — silent failures, test-design soundness, surface-area discipline.\n' +
109
112
  'You can run both on the same diff if the change is large. If neither is available, fall back to the manual checklist below.\n\n' +
110
113
  REVIEW_BODY,
111
- autoLoopReviewGate: 'Code review gate — BEFORE marking the task done, pick the appropriate review skill (two are installed):\n' +
114
+ autoLoopReviewGate: 'If the named skills or subagents are unavailable, review the full diff manually with the same checks. Code review gate — BEFORE marking the task done, pick the appropriate review skill from those actually available:\n' +
112
115
  '- Default to `/review` (gstack Staff Engineer) for tactical code-level bugs and auto-fixes.\n' +
113
116
  '- Use `superpowers:requesting-code-review` instead when the task introduces tests, refactors, or design decisions worth a principles-level critique.\n\n' +
114
- 'Brief the chosen reviewer with: what you just implemented, the task title, and the commit SHA (via `git rev-parse HEAD`). Ask specifically whether the change matches the task scope, whether edge cases are handled, and whether the commit is clean. If the reviewer auto-fixes minor issues, accept the fixes via an amend or fix-up commit, then re-run step 3 checks.',
117
+ 'Brief the chosen reviewer with: what you just implemented, the task title, and the commit SHA (via `git rev-parse HEAD`). Ask specifically whether the change matches the task scope, whether edge cases are handled, and whether committed and uncommitted changes (including staged and untracked files) are correct. If the reviewer auto-fixes minor issues, apply fixes locally and re-run checks; commit only when explicitly authorized.',
115
118
  autoLoopGroomingIntro: GROOMING_INTRO_COMBINED,
116
119
  qaPromptTemplate: `QA pass for workspace "{{workspace_name}}" in project {{project_name}}.
117
120
 
@@ -127,13 +130,14 @@ gstack QA toolkit (preferred for interactive QA):
127
130
  - **Standard** — adds medium-severity bugs.
128
131
  - **Exhaustive** — adds cosmetic issues.
129
132
  - \`/qa-only {{staging_url}}\` — Same methodology as \`/qa\` but report only, no code changes.
130
- - \`/design-review\` — Visual audit (consistency, spacing, hierarchy, AI slop). Commits atomic fixes with before/after screenshots.
133
+ - \`/design-review\` — Visual audit (consistency, spacing, hierarchy, AI slop). Prepare local fixes with before/after screenshots. Commit only when explicitly authorized; if the skill cannot avoid automatic commits, perform the visual audit manually.
131
134
 
132
135
  Superpowers alternative (low-level browser control):
133
136
  - \`superpowers-chrome:browsing\` — Direct Chrome DevTools Protocol control over an existing Chrome session: multi-tab management, form automation, content extraction. Use when you need fine-grained control beyond what \`/browse\` exposes.
134
137
 
135
- For reproducible regression coverage that runs on every PR, prefer **Cypress** specs in \`test/cypress/\` instead of any interactive QA skill. Reserve the tools above for exploration, dogfooding, and one-shot visual debugging.`,
136
- brainstormingInstruction: 'Brainstorm using both suites — each plays to its strength:\n' +
138
+ For reproducible regression coverage that runs on every PR, use the project's configured test framework and existing test directory instead of any interactive QA skill. Reserve the tools above for exploration, dogfooding, and one-shot visual debugging.`,
139
+ brainstormingInstruction: 'Use only skills and tools actually available in this session. If a named skill is unavailable, perform its described planning or review steps directly. Do not install tools or expand permissions automatically.\n' +
140
+ 'Brainstorm using both suites — each plays to its strength:\n' +
137
141
  '1. Early product framing: prefer gstack `/office-hours` for product-shaped work (six forcing questions + design doc). Fall back to `superpowers:brainstorming` for purely infra/refactor work where the product lens does not apply.\n' +
138
142
  '2. Plan construction — pick whichever fits the work better:\n' +
139
143
  ' - gstack `/autoplan` for the chained CEO/design/eng/DX pipeline (auto-detects which apply).\n' +
@@ -156,11 +160,11 @@ export const ALL_THREE_PROMPTS = {
156
160
  "- `ecc:code-review` (or a Task-dispatched `ecc:code-reviewer` subagent) for ECC's structured multi-agent review pass.\n" +
157
161
  'You can run more than one on the same diff if the change is large. If none is available, fall back to the manual checklist below.\n\n' +
158
162
  REVIEW_BODY,
159
- autoLoopReviewGate: 'Code review gate — BEFORE marking the task done, pick the appropriate review path (three are installed):\n' +
163
+ autoLoopReviewGate: 'If the named skills or subagents are unavailable, review the full diff manually with the same checks. Code review gate — BEFORE marking the task done, pick the appropriate review path (three are installed):\n' +
160
164
  '- Default to `/review` (gstack Staff Engineer) for tactical code-level bugs and auto-fixes.\n' +
161
165
  '- Use `superpowers:requesting-code-review` instead when the task introduces tests, refactors, or design decisions worth a principles-level critique.\n' +
162
166
  "- Use a Task-dispatched `ecc:code-reviewer` subagent (or the `ecc:quality-gate` skill) when you want ECC's structured multi-agent pass.\n\n" +
163
- 'Brief the chosen reviewer with: what you just implemented, the task title, and the commit SHA (via `git rev-parse HEAD`). Ask specifically whether the change matches the task scope, whether edge cases are handled, and whether the commit is clean. If the reviewer auto-fixes minor issues, accept the fixes via an amend or fix-up commit, then re-run step 3 checks.',
167
+ 'Brief the chosen reviewer with: what you just implemented, the task title, and the commit SHA (via `git rev-parse HEAD`). Ask specifically whether the change matches the task scope, whether edge cases are handled, and whether committed and uncommitted changes (including staged and untracked files) are correct. If the reviewer auto-fixes minor issues, apply fixes locally and re-run checks; commit only when explicitly authorized.',
164
168
  autoLoopGroomingIntro: GROOMING_INTRO_ALL,
165
169
  qaPromptTemplate: `QA pass for workspace "{{workspace_name}}" in project {{project_name}}.
166
170
 
@@ -176,7 +180,7 @@ gstack QA toolkit (preferred for interactive QA):
176
180
  - **Standard** — adds medium-severity bugs.
177
181
  - **Exhaustive** — adds cosmetic issues.
178
182
  - \`/qa-only {{staging_url}}\` — Same methodology as \`/qa\` but report only, no code changes.
179
- - \`/design-review\` — Visual audit (consistency, spacing, hierarchy, AI slop). Commits atomic fixes with before/after screenshots.
183
+ - \`/design-review\` — Visual audit (consistency, spacing, hierarchy, AI slop). Prepare local fixes with before/after screenshots. Commit only when explicitly authorized; if the skill cannot avoid automatic commits, perform the visual audit manually.
180
184
 
181
185
  ECC toolkit:
182
186
  - \`ecc:browser-qa\` skill — structured browser-driven QA pass.
@@ -185,8 +189,9 @@ ECC toolkit:
185
189
  Superpowers alternative (low-level browser control):
186
190
  - \`superpowers-chrome:browsing\` — Direct Chrome DevTools Protocol control over an existing Chrome session: multi-tab management, form automation, content extraction. Use when you need fine-grained control beyond what \`/browse\` exposes.
187
191
 
188
- For reproducible regression coverage that runs on every PR, prefer **Cypress** specs in \`test/cypress/\` instead of any interactive QA skill. Reserve the tools above for exploration, dogfooding, and one-shot visual debugging.`,
189
- brainstormingInstruction: 'Brainstorm using all three suites — each plays to its strength:\n' +
192
+ For reproducible regression coverage that runs on every PR, use the project's configured test framework and existing test directory instead of any interactive QA skill. Reserve the tools above for exploration, dogfooding, and one-shot visual debugging.`,
193
+ brainstormingInstruction: 'Use only skills and tools actually available in this session. If a named skill is unavailable, perform its described planning or review steps directly. Do not install tools or expand permissions automatically.\n' +
194
+ 'Brainstorm using all three suites — each plays to its strength:\n' +
190
195
  '1. Early product framing: prefer gstack `/office-hours` for product-shaped work (six forcing questions + design doc), or `ecc:plan` (or `subagent_type: "ecc:planner"`) for ECC-style spec expansion (features, sprints, evaluation criteria). Fall back to `superpowers:brainstorming` for purely infra/refactor work where neither product lens applies.\n' +
191
196
  '2. Plan construction — pick whichever fits the work better:\n' +
192
197
  ' - gstack `/autoplan` for the chained CEO/design/eng/DX pipeline (auto-detects which apply).\n' +
@@ -205,6 +210,8 @@ For reproducible regression coverage that runs on every PR, prefer **Cypress** s
205
210
  * Empty-string or whitespace-only overrides fall back to AGNOSTIC defaults.
206
211
  */
207
212
  export function getSuitePrompts(suite, overrides) {
213
+ if (suite === 'standard')
214
+ return AGNOSTIC_PROMPTS;
208
215
  if (suite === 'superpowers')
209
216
  return SUPERPOWERS_PROMPTS;
210
217
  if (suite === 'gstack')
@@ -1,6 +1,12 @@
1
+ import { createHash } from 'node:crypto';
1
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
3
  import path from 'node:path';
3
4
  import { getTemplatesPath } from '../utils/paths.js';
5
+ const LEGACY_DEFAULT_CONTENT_HASHES = {
6
+ 'kobo-context': 'ee29ebb56186ce9537e682c25d9d7737ff8d824ab6f29c095c925b27eed70552',
7
+ 'pr-review-comments': '67dfc29fb0c566349a72d9375e314269f061fd184d3a73c9a6bf00451a0f4d9e',
8
+ 'ci-status': 'a96fc75efa7c1f11b58163d8a0d2912f9b22d980087ed224341979c08c250bc8',
9
+ };
4
10
  const CURRENT_FILE_VERSION = 2;
5
11
  const SLUG_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
6
12
  const MAX_CONTENT_LENGTH = 4096;
@@ -20,7 +26,24 @@ export function listTemplates() {
20
26
  if (parsed.version !== CURRENT_FILE_VERSION) {
21
27
  console.warn(`[templates-service] templates.json has version ${parsed.version}, expected ${CURRENT_FILE_VERSION}. Reading best-effort.`);
22
28
  }
23
- return Array.isArray(parsed.templates) ? parsed.templates : [];
29
+ const templates = Array.isArray(parsed.templates) ? parsed.templates : [];
30
+ let changed = false;
31
+ for (const template of templates) {
32
+ const previousHash = LEGACY_DEFAULT_CONTENT_HASHES[template.slug];
33
+ if (!previousHash || typeof template.content !== 'string')
34
+ continue;
35
+ if (createHash('sha256').update(template.content).digest('hex') !== previousHash)
36
+ continue;
37
+ const next = DEFAULT_TEMPLATES.find((value) => value.slug === template.slug);
38
+ if (!next || next.content === template.content)
39
+ continue;
40
+ template.content = next.content;
41
+ template.updatedAt = new Date().toISOString();
42
+ changed = true;
43
+ }
44
+ if (changed)
45
+ writeTemplates(templates, parsed.seededDefaultSlugs);
46
+ return templates;
24
47
  }
25
48
  catch (err) {
26
49
  console.error('[templates-service] Failed to read templates.json:', err);
@@ -198,9 +221,9 @@ export const DEFAULT_TEMPLATES = [
198
221
  `- A dedicated MCP server (\`kobo-tasks\`) exposing tools to read/write workspace state\n\n` +
199
222
  `# Lifecycle\n` +
200
223
  `1. **Brainstorming** — you scope the work, output a plan, end with the literal marker \`[BRAINSTORM_COMPLETE]\`\n` +
201
- `2. **Executing** — you implement the plan, commit, push\n` +
202
- `3. **Auto-loop (opt-in)** — Kōbō re-spawns a fresh session per task; each iteration sees a clean context\n` +
203
- `4. **Completed / Archived** — the workspace freezes; the worktree stays available read-only\n\n` +
224
+ `2. **Executing** — you implement and verify the plan locally; commit, push and publication require explicit authorization\n` +
225
+ `3. **Auto-loop (opt-in)** — Kōbō runs iterations using the configured session mode, with durable tasks and instructions\n` +
226
+ `4. **Completed / Archived** — completion records lifecycle state; archiving hides the workspace without making its worktree read-only\n\n` +
204
227
  `# Kōbō MCP tools (always namespaced \`kobo__…\`)\n` +
205
228
  `These are the main tools — the full \`kobo__\` set is larger and is listed in your available tools; consult that list for the rest (dev-server, search_codebase, documents, settings, session usage…).\n` +
206
229
  `- \`kobo__list_tasks\` / \`create_task\` / \`update_task\` / \`mark_task_done\` / \`delete_task\` — manage the visible task list\n` +
@@ -213,7 +236,7 @@ export const DEFAULT_TEMPLATES = [
213
236
  `- \`kobo__mark_auto_loop_ready\` — flip the loop into auto-execution after grooming\n\n` +
214
237
  `# Foreground & waking yourself\n` +
215
238
  `- You run in the FOREGROUND of an interactive session — do your work within the current turn\n` +
216
- `- When a turn ends the workspace goes idle; nothing re-invokes you automatically. A background task or detached process finishing does NOT wake you\n` +
239
+ `- When a turn ends the workspace goes idle; automatic continuation depends on enabled auto-loop, schedules and lifecycle settings. A background task or detached process finishing does NOT wake you\n` +
217
240
  `- To wait and continue later (CI, long build, scheduled check), schedule your own wake-up: \`kobo__schedule_wakeup\` (one-off delay) or \`kobo__cron_create\` (recurring), then end the turn\n\n` +
218
241
  `# Conventions\n` +
219
242
  `- \`CLAUDE.md\` / \`AGENTS.md\` at the project root override default behavior — read them first\n` +
@@ -271,12 +294,12 @@ export const DEFAULT_TEMPLATES = [
271
294
  {
272
295
  slug: 'pr-review-comments',
273
296
  description: 'List PR review comments requesting changes',
274
- content: 'Check if a pull request exists for branch {working_branch}.\n\nIf a PR exists (PR {pr_url}):\n1. Use the GitHub MCP tools to fetch the PR reviews and comments\n2. Filter for reviews with status "CHANGES_REQUESTED"\n3. List each review comment with:\n - The reviewer name\n - The file and line referenced\n - The comment body\n - Whether it has been resolved\n4. Summarize the outstanding requested changes that still need to be addressed\n\nIf no PR exists, say so and suggest pushing the branch first.',
297
+ content: 'Check if a pull request exists for branch {working_branch}.\n\nIf a PR exists (PR {pr_url}):\n1. Use the configured forge tools or CLI to fetch the PR reviews and comments\n2. Filter for reviews with status "CHANGES_REQUESTED"\n3. List each review comment with:\n - The reviewer name\n - The file and line referenced\n - The comment body\n - Whether it has been resolved\n4. Summarize the outstanding requested changes that still need to be addressed\n\nIf no PR exists, report that no PR/MR exists; do not push or publish without authorization.',
275
298
  },
276
299
  {
277
300
  slug: 'ci-status',
278
- description: 'Check GitHub Actions status on PR',
279
- content: 'Check the CI/CD status for the pull request on branch {working_branch}.\n\nIf a PR exists (PR {pr_url}):\n1. Use the GitHub MCP tools to list the check runs / status checks on the latest commit of the PR\n2. For each check, report:\n - Check name\n - Status (queued, in_progress, completed)\n - Conclusion (success, failure, neutral, skipped, etc.)\n - Duration if available\n3. If any checks failed, fetch the logs or annotations and summarize what went wrong\n4. Give an overall summary: all green, some failing, or still running\n\nIf no PR exists, say so and suggest creating one first.',
301
+ description: 'Check CI status on the configured forge',
302
+ content: 'Check the CI/CD status for the pull request on branch {working_branch}.\n\nIf a PR exists (PR {pr_url}):\n1. Use the configured forge tools or CLI to list the check runs / status checks on the latest commit of the PR\n2. For each check, report:\n - Check name\n - Status (queued, in_progress, completed)\n - Conclusion (success, failure, neutral, skipped, etc.)\n - Duration if available\n3. If any checks failed, fetch the logs or annotations and summarize what went wrong\n4. Give an overall summary: all green, some failing, or still running\n\nIf no PR exists, report that no PR/MR exists; do not create one without authorization.',
280
303
  },
281
304
  {
282
305
  slug: 'council',
@@ -1,6 +1,21 @@
1
1
  import fs from 'node:fs';
2
2
  import * as pty from 'node-pty';
3
+ import { ensureSpawnHelperExecutable } from '../utils/node-pty-spawn-helper.js';
3
4
  const terminals = new Map();
5
+ let spawnHelperChecked = false;
6
+ function prepareSpawnHelper() {
7
+ if (spawnHelperChecked)
8
+ return;
9
+ spawnHelperChecked = true;
10
+ try {
11
+ const fixed = ensureSpawnHelperExecutable();
12
+ if (fixed)
13
+ console.log(`[terminal] Made node-pty spawn-helper executable: ${fixed}`);
14
+ }
15
+ catch (err) {
16
+ console.warn('[terminal] node-pty spawn-helper is not executable and could not be fixed (run chmod +x on it):', err);
17
+ }
18
+ }
4
19
  export function createTerminal(workspaceId, cwd) {
5
20
  if (terminals.has(workspaceId)) {
6
21
  return terminals.get(workspaceId).pty;
@@ -8,6 +23,7 @@ export function createTerminal(workspaceId, cwd) {
8
23
  if (!fs.existsSync(cwd)) {
9
24
  throw new Error(`Worktree directory does not exist: ${cwd}`);
10
25
  }
26
+ prepareSpawnHelper();
11
27
  const shell = process.env.SHELL || '/bin/sh';
12
28
  const term = pty.spawn(shell, [], {
13
29
  name: 'xterm-256color',
@@ -45,11 +45,11 @@ const failedRetries = new Map();
45
45
  /** Keep a claimed wakeup durable while the session is still unavailable. */
46
46
  function defer(workspaceId, row) {
47
47
  const targetAt = new Date(Date.now() + ACTIVE_SESSION_RETRY_MS).toISOString();
48
- getDb().prepare('UPDATE pending_wakeups SET target_at = ? WHERE workspace_id = ?').run(targetAt, workspaceId);
48
+ getDb().prepare('UPDATE pending_wakeups SET retry_at = ? WHERE workspace_id = ?').run(targetAt, workspaceId);
49
49
  const timeout = setTimeout(() => fire(workspaceId), ACTIVE_SESSION_RETRY_MS);
50
50
  timeout.unref?.();
51
51
  timers.set(workspaceId, timeout);
52
- emitEphemeral(workspaceId, 'wakeup:scheduled', { targetAt, reason: row.reason ?? undefined });
52
+ emitEphemeral(workspaceId, 'wakeup:scheduled', { targetAt: row.target_at, reason: row.reason ?? undefined });
53
53
  }
54
54
  /** Schedule a wakeup for the given workspace. Replaces any existing pending wakeup. */
55
55
  export function schedule(workspaceId, delaySeconds, prompt, reason, agentSessionId) {
@@ -124,7 +124,7 @@ export function getPending(workspaceId) {
124
124
  export function isWakeupScheduled(workspaceId) {
125
125
  return getPending(workspaceId) !== null;
126
126
  }
127
- /** Re-register timers for rows persisted across restart. Skips stale entries. */
127
+ /** Re-register persisted timers. Previously deferred work survives downtime; only never-attempted stale wakeups expire. */
128
128
  export function rehydrate() {
129
129
  suspendForShutdown();
130
130
  suspended = false;
@@ -134,14 +134,16 @@ export function rehydrate() {
134
134
  const now = Date.now();
135
135
  for (const row of rows) {
136
136
  try {
137
- const target = new Date(row.target_at).getTime();
137
+ const target = new Date(row.retry_at ?? row.target_at).getTime();
138
138
  const delay = target - now;
139
139
  if (delay > 0) {
140
140
  const timeout = setTimeout(() => fire(row.workspace_id), delay);
141
141
  timeout.unref?.();
142
142
  timers.set(row.workspace_id, timeout);
143
143
  }
144
- else if (-delay <= STALE_WAKEUP_GRACE_MS) {
144
+ else if (row.retry_at != null || -delay <= STALE_WAKEUP_GRACE_MS) {
145
+ // Admission deferred this wakeup after its deadline. Downtime does not
146
+ // revoke the pending instruction; retry through the same admission gate.
145
147
  const timeout = setTimeout(() => fire(row.workspace_id), 0);
146
148
  timeout.unref?.();
147
149
  timers.set(row.workspace_id, timeout);