@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.
- package/AGENTS.md +17 -2
- package/CHANGELOG.md +8 -0
- package/CODE_OF_CONDUCT.md +16 -0
- package/CONFIGURATION.md +1968 -0
- package/CONTRIBUTING.md +83 -0
- package/DESIGN.md +296 -0
- package/README.md +35 -7
- package/SECURITY.md +54 -0
- package/THIRD_PARTY_NOTICES.md +20 -0
- package/dist/server/db/migrations.js +23 -0
- package/dist/server/db/schema.js +2 -0
- package/dist/server/index.js +6 -0
- package/dist/server/routes/environment.js +18 -0
- package/dist/server/routes/health.js +17 -2
- package/dist/server/routes/integrations.js +29 -0
- package/dist/server/routes/settings.js +5 -0
- package/dist/server/routes/sounds.js +60 -0
- package/dist/server/routes/workspaces.js +46 -12
- package/dist/server/services/agent/engines/codex/options-builder.js +1 -0
- package/dist/server/services/agent/engines/codex/spawn.js +2 -2
- package/dist/server/services/agent/integration-mcp.js +49 -0
- package/dist/server/services/agent/orchestrator.js +6 -2
- package/dist/server/services/auto-loop-service.js +45 -25
- package/dist/server/services/custom-sound-service.js +0 -0
- package/dist/server/services/environment-check-service.js +125 -0
- package/dist/server/services/initial-prompt-template-service.js +8 -21
- package/dist/server/services/integration-config-service.js +65 -0
- package/dist/server/services/legacy-public-prompts.js +112 -0
- package/dist/server/services/notion-service.js +25 -61
- package/dist/server/services/sentry-service.js +17 -12
- package/dist/server/services/settings-defaults.js +5 -0
- package/dist/server/services/settings-service.js +112 -23
- package/dist/server/services/skill-suite-prompts.js +29 -22
- package/dist/server/services/templates-service.js +31 -8
- package/dist/server/services/terminal-service.js +16 -0
- package/dist/server/services/wakeup-service.js +7 -5
- package/dist/server/services/workspace-service.js +25 -4
- package/dist/server/services/worktree-service.js +3 -1
- package/dist/server/utils/git-repo-lock.js +7 -3
- package/dist/server/utils/mcp-client.js +26 -12
- package/dist/server/utils/mcp-process.js +25 -0
- package/dist/server/utils/node-pty-spawn-helper.js +31 -0
- package/dist/server/utils/paths.js +7 -0
- package/dist/shared/auto-loop-prompts.js +6 -2
- package/dist/shared/automatic-admission.js +1 -0
- package/dist/shared/environment.js +1 -0
- package/dist/shared/notification-assets.js +73 -0
- package/dist/shared/skill-suite-prompts.js +6 -3
- package/dist/shared/workflow-policy.js +25 -0
- package/docs/getting-started.md +47 -0
- package/docs/troubleshooting.md +49 -0
- package/package.json +19 -7
- package/src/client/dist/pwa/assets/ActivityFeed-DRgetl1M.js +8 -0
- package/src/client/dist/pwa/assets/{ChangelogPage-CnXTnFhe.js → ChangelogPage-BJdICFvz.js} +1 -1
- package/src/client/dist/pwa/assets/{ComparisonPanel-CKylN45q.js → ComparisonPanel-2GLd8KIy.js} +2 -2
- package/src/client/dist/pwa/assets/CreatePage-B9AdNJZj.js +2 -0
- package/src/client/dist/pwa/assets/CreatePage-B9C9J9Pw.css +1 -0
- package/src/client/dist/pwa/assets/DashboardPage-CzVOvjSP.js +1 -0
- package/src/client/dist/pwa/assets/DiffViewer-X25vuf83.js +8 -0
- package/src/client/dist/pwa/assets/{DocumentsPanel-BeCttB-x.js → DocumentsPanel-BastjrEm.js} +1 -1
- package/src/client/dist/pwa/assets/{DrawerToggleButton-BJBBYeOc.js → DrawerToggleButton-DbipGmBL.js} +1 -1
- package/src/client/dist/pwa/assets/{GitPanel-BFCnyhE2.css → GitPanel-C4wOcZV2.css} +1 -1
- package/src/client/dist/pwa/assets/GitPanel-CnW4iVao.js +3 -0
- package/src/client/dist/pwa/assets/{HealthPage-l88TEk-k.js → HealthPage-aieNQly-.js} +1 -1
- package/src/client/dist/pwa/assets/MainLayout-Cc4XzCAy.css +1 -0
- package/src/client/dist/pwa/assets/MainLayout-DqBbE8o4.js +2 -0
- package/src/client/dist/pwa/assets/{QBtnDropdown-44Mj-y_1.js → QBtnDropdown-BWy-rh45.js} +1 -1
- package/src/client/dist/pwa/assets/{QExpansionItem-Bok1m8Wi.js → QExpansionItem-DfmdBGuW.js} +1 -1
- package/src/client/dist/pwa/assets/QSelect-BfqaWakg.js +1 -0
- package/src/client/dist/pwa/assets/{QTooltip-BDihn2aY.js → QTooltip-Cy0T0vk2.js} +1 -1
- package/src/client/dist/pwa/assets/SchedulePanel-BYKSFoFj.css +1 -0
- package/src/client/dist/pwa/assets/SchedulePanel-YQPObRR3.js +1 -0
- package/src/client/dist/pwa/assets/{SearchPage-BwZ2TX1G.js → SearchPage-BoBjmItc.js} +1 -1
- package/src/client/dist/pwa/assets/SettingsPage-0GtDcXRC.js +9 -0
- package/src/client/dist/pwa/assets/{SettingsPage-W6N01tGz.css → SettingsPage-BYdLXJEJ.css} +1 -1
- package/src/client/dist/pwa/assets/SplitWorkspacePage-4wFh65Lh.js +1 -0
- package/src/client/dist/pwa/assets/{TerminalPanel-Cq-FR7A7.js → TerminalPanel-b70x_jqH.js} +4 -4
- package/src/client/dist/pwa/assets/{TouchPan-BQ1cvzRC.js → TouchPan-CcTVcxwd.js} +1 -1
- package/src/client/dist/pwa/assets/{TourReplayButton-Dz1yEz_z.js → TourReplayButton-CpEMnQS8.js} +1 -1
- package/src/client/dist/pwa/assets/WorkspaceAttentionLabels-C5lTHTp2.js +1 -0
- package/src/client/dist/pwa/assets/{WorkspacePage-BbUvR1Vf.css → WorkspacePage--5HsnMQ1.css} +1 -1
- package/src/client/dist/pwa/assets/WorkspacePage-D_V9gNON.js +4 -0
- package/src/client/dist/pwa/assets/{browser-BmWgBx9M.js → browser-LBbxVwWf.js} +1 -1
- package/src/client/dist/pwa/assets/{build-path-tree-6EjBmYYY.js → build-path-tree-DyvtWxb0.js} +1 -1
- package/src/client/dist/pwa/assets/custom-sounds-BpeLZUDW.js +1 -0
- package/src/client/dist/pwa/assets/de-v6i2HlE2.js +17 -0
- package/src/client/dist/pwa/assets/{documents-BZ8bwcjr.js → documents-Bjx8lz-h.js} +1 -1
- package/src/client/dist/pwa/assets/{editor.api-CK7--ckY.js → editor.api-BC3PbJkx.js} +1 -1
- package/src/client/dist/pwa/assets/efforts-BDHAnNUs.js +9 -0
- package/src/client/dist/pwa/assets/engineFeatures-hlEiwqt-.js +1 -0
- package/src/client/dist/pwa/assets/es-Bc1KgkAT.js +17 -0
- package/src/client/dist/pwa/assets/{expand-template-C8VyjASo.js → expand-template-DLDl1qPx.js} +1 -1
- package/src/client/dist/pwa/assets/{format-LtTLLitJ.js → format-Q94deO3I.js} +7 -7
- package/src/client/dist/pwa/assets/{formatters-Bl9zA7Ai.js → formatters-CWxRHuUu.js} +1 -1
- package/src/client/dist/pwa/assets/fr-ByYPK5vr.js +17 -0
- package/src/client/dist/pwa/assets/{freemarker2-DxezMaje.js → freemarker2-MPhk0eTh.js} +1 -1
- package/src/client/dist/pwa/assets/{handlebars-DK_Bj6Rx.js → handlebars-C60ru5gR.js} +1 -1
- package/src/client/dist/pwa/assets/{html-DFfsfStD.js → html-ClzchR9j.js} +1 -1
- package/src/client/dist/pwa/assets/i18n-Sy42tm-V.js +1 -0
- package/src/client/dist/pwa/assets/index-CqZ7sDcM.js +20 -0
- package/src/client/dist/pwa/assets/it-BYF_88z6.js +17 -0
- package/src/client/dist/pwa/assets/{javascript-DuNbcaL7.js → javascript-C43UJmMx.js} +1 -1
- package/src/client/dist/pwa/assets/{liquid-CM3JKyhv.js → liquid-CYTrvTKF.js} +1 -1
- package/src/client/dist/pwa/assets/{mdx-BG3zYwNF.js → mdx-CxsXOvkQ.js} +1 -1
- package/src/client/dist/pwa/assets/{monaco-contributions-DLscZGH-.js → monaco-contributions-Cl4-iVpK.js} +1 -1
- package/src/client/dist/pwa/assets/{monaco.contribution-DnhZHwXT.js → monaco.contribution-DkjLUmyA.js} +2 -2
- package/src/client/dist/pwa/assets/network-auth-CXQn2wO7.js +1 -0
- package/src/client/dist/pwa/assets/notify-theme-BrueBr2j.js +1 -0
- package/src/client/dist/pwa/assets/{pending-diff-open-dYIFdS4r.js → pending-diff-open-B4POItbR.js} +1 -1
- package/src/client/dist/pwa/assets/permissionModes-B-ciuUbz.js +36 -0
- package/src/client/dist/pwa/assets/{project-color-R_1je4vW.js → project-color-CM3hflLH.js} +1 -1
- package/src/client/dist/pwa/assets/{python-COs6pHk2.js → python-s2IMpsoV.js} +1 -1
- package/src/client/dist/pwa/assets/{razor-Jl1VqMsk.js → razor-DVNXiVBh.js} +1 -1
- package/src/client/dist/pwa/assets/render-chat-markdown-TU6CDfD8.js +69 -0
- package/src/client/dist/pwa/assets/{typescript-BU_TUuAM.js → typescript-BYT_8ABE.js} +1 -1
- package/src/client/dist/pwa/assets/use-tours-CNe8qb1q.js +2 -0
- package/src/client/dist/pwa/assets/workspace-templates-tBxXE52A.js +1 -0
- package/src/client/dist/pwa/assets/{xml-gFFsobxE.js → xml-BIG-fmxk.js} +1 -1
- package/src/client/dist/pwa/assets/{yaml-DaXaqaGD.js → yaml-D7gu2CQh.js} +1 -1
- package/src/client/dist/pwa/index.html +1 -1
- package/src/client/dist/pwa/sounds/neutral.wav +0 -0
- package/src/client/dist/pwa/sounds/ready.wav +0 -0
- package/src/client/dist/pwa/sw.js +1 -1
- package/src/client/dist/pwa/assets/ActivityFeed-CLXjdqS8.js +0 -8
- package/src/client/dist/pwa/assets/CreatePage-SoCcvxuD.js +0 -2
- package/src/client/dist/pwa/assets/CreatePage-TY9g3hZb.css +0 -1
- package/src/client/dist/pwa/assets/DashboardPage-CZQLfoV1.js +0 -1
- package/src/client/dist/pwa/assets/DiffViewer-Csf3WmLc.js +0 -8
- package/src/client/dist/pwa/assets/GitPanel-B-ZHgghQ.js +0 -3
- package/src/client/dist/pwa/assets/MainLayout-BAAQLq95.css +0 -1
- package/src/client/dist/pwa/assets/MainLayout-Cf4Q9x1u.js +0 -2
- package/src/client/dist/pwa/assets/QDrawer-B4qHw8wt.js +0 -1
- package/src/client/dist/pwa/assets/QSelect-BbtD5Iks.js +0 -1
- package/src/client/dist/pwa/assets/SchedulePanel-BAA4Aajn.css +0 -1
- package/src/client/dist/pwa/assets/SchedulePanel-DiWCDNZ8.js +0 -1
- package/src/client/dist/pwa/assets/SettingsPage-BUh0WfNf.js +0 -9
- package/src/client/dist/pwa/assets/SplitWorkspacePage-Bg6nKBcA.js +0 -1
- package/src/client/dist/pwa/assets/WorkspaceAttentionLabels-BCVOP8vp.js +0 -1
- package/src/client/dist/pwa/assets/WorkspacePage-Cl8gap4b.js +0 -4
- package/src/client/dist/pwa/assets/de-COObokpu.js +0 -17
- package/src/client/dist/pwa/assets/efforts-Bw0o2Bud.js +0 -9
- package/src/client/dist/pwa/assets/engineFeatures-DQO9HHXI.js +0 -1
- package/src/client/dist/pwa/assets/es-By2Q9Tca.js +0 -17
- package/src/client/dist/pwa/assets/fouet-ahh-DdxrUXRj.mp3 +0 -0
- package/src/client/dist/pwa/assets/fr-D-sd0ddn.js +0 -17
- package/src/client/dist/pwa/assets/i18n-aDWy4KHt.js +0 -1
- package/src/client/dist/pwa/assets/index-BLd8DAzg.js +0 -20
- package/src/client/dist/pwa/assets/it-CeK5lyIA.js +0 -17
- package/src/client/dist/pwa/assets/network-auth-BJiPbO5l.js +0 -1
- package/src/client/dist/pwa/assets/notify-theme-D4p3qPkp.js +0 -1
- package/src/client/dist/pwa/assets/permissionModes-B7fuUegU.js +0 -36
- package/src/client/dist/pwa/assets/render-chat-markdown-AaOo0Tgq.js +0 -67
- package/src/client/dist/pwa/assets/use-tours-CVn874kD.js +0 -2
- package/src/client/dist/pwa/assets/workspace-templates-BCKR8TXr.js +0 -1
- package/src/client/dist/pwa/sounds/7eme-compagnie-03.mp3 +0 -0
- package/src/client/dist/pwa/sounds/aller-ftg.mp3 +0 -0
- package/src/client/dist/pwa/sounds/arrete-de-mentir.mp3 +0 -0
- package/src/client/dist/pwa/sounds/arretez-les-messages.mp3 +0 -0
- package/src/client/dist/pwa/sounds/bah-alors-on-est-nul.mp3 +0 -0
- package/src/client/dist/pwa/sounds/basic-notification.mp3 +0 -0
- package/src/client/dist/pwa/sounds/ca_va_peter.mp3 +0 -0
- package/src/client/dist/pwa/sounds/dry-fart.mp3 +0 -0
- package/src/client/dist/pwa/sounds/faaah.mp3 +0 -0
- package/src/client/dist/pwa/sounds/for-shure.mp3 +0 -0
- package/src/client/dist/pwa/sounds/gta-v-death.mp3 +0 -0
- package/src/client/dist/pwa/sounds/hey.mp3 +0 -0
- package/src/client/dist/pwa/sounds/mais-laisse-moi-dormir-zebi.mp3 +0 -0
- package/src/client/dist/pwa/sounds/nan-tu-degages.mp3 +0 -0
- package/src/client/dist/pwa/sounds/nan-wallah-pardon.mp3 +0 -0
- package/src/client/dist/pwa/sounds/ouais-cest-greg.mp3 +0 -0
- package/src/client/dist/pwa/sounds/pas-ca-zinedine.mp3 +0 -0
- package/src/client/dist/pwa/sounds/ta-gueule.mp3 +0 -0
- package/src/client/dist/pwa/sounds/travail_termine.mp3 +0 -0
- package/src/client/dist/pwa/sounds/tu-vas-la-fermer.mp3 +0 -0
- package/src/client/dist/pwa/sounds/warcraft-3-humain-travail.mp3 +0 -0
- 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.
|
|
59
|
-
5.
|
|
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.
|
|
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.
|
|
85
|
-
4.
|
|
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
|
|
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:
|
|
265
|
+
p.finalization = { prompt: LEGACY_FINALIZATION_PROMPT };
|
|
258
266
|
}
|
|
259
267
|
else if (typeof p.finalization.prompt !== 'string') {
|
|
260
268
|
;
|
|
261
|
-
p.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 =
|
|
328
|
+
global.notionInitialPromptTemplate = LEGACY_NOTION_INITIAL_PROMPT;
|
|
321
329
|
}
|
|
322
330
|
if (typeof global.sentryInitialPromptTemplate !== 'string') {
|
|
323
|
-
global.sentryInitialPromptTemplate =
|
|
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 =
|
|
458
|
+
global.customReviewTemplate = LEGACY_AGNOSTIC_REVIEW_TEMPLATE;
|
|
451
459
|
}
|
|
452
460
|
if (typeof global.customAutoLoopReviewGate !== 'string') {
|
|
453
|
-
global.customAutoLoopReviewGate =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
1038
|
+
audioNotifications: false,
|
|
976
1039
|
audioQuestionNotifications: false,
|
|
977
1040
|
audioWorkspaceCreatedNotifications: false,
|
|
978
1041
|
audioAgentErrorNotifications: false,
|
|
979
|
-
audioNotificationSound: '
|
|
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:
|
|
1016
|
-
sentryEnabled:
|
|
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: '
|
|
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\` —
|
|
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
|
|
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: '
|
|
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
|
-
|
|
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
|
|
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).
|
|
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,
|
|
70
|
-
brainstormingInstruction: '
|
|
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
|
|
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: '
|
|
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
|
-
|
|
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
|
-
'
|
|
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
|
|
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
|
|
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).
|
|
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,
|
|
136
|
-
brainstormingInstruction: '
|
|
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
|
|
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).
|
|
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,
|
|
189
|
-
brainstormingInstruction: '
|
|
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
|
-
|
|
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
|
|
202
|
-
`3. **Auto-loop (opt-in)** — Kōbō
|
|
203
|
-
`4. **Completed / Archived** —
|
|
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;
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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);
|