supipowers 1.2.6 → 1.5.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 (137) hide show
  1. package/README.md +118 -56
  2. package/bin/install.ts +48 -128
  3. package/package.json +11 -3
  4. package/skills/code-review/SKILL.md +137 -40
  5. package/skills/context-mode/SKILL.md +67 -56
  6. package/skills/creating-supi-agents/SKILL.md +204 -0
  7. package/skills/debugging/SKILL.md +86 -40
  8. package/skills/fix-pr/SKILL.md +96 -65
  9. package/skills/planning/SKILL.md +103 -46
  10. package/skills/qa-strategy/SKILL.md +68 -46
  11. package/skills/receiving-code-review/SKILL.md +60 -53
  12. package/skills/release/SKILL.md +111 -39
  13. package/skills/tdd/SKILL.md +118 -67
  14. package/skills/verification/SKILL.md +71 -37
  15. package/src/bootstrap.ts +27 -5
  16. package/src/commands/agents.ts +249 -0
  17. package/src/commands/ai-review.ts +1113 -0
  18. package/src/commands/config.ts +224 -95
  19. package/src/commands/doctor.ts +19 -13
  20. package/src/commands/fix-pr.ts +8 -11
  21. package/src/commands/generate.ts +200 -0
  22. package/src/commands/model-picker.ts +5 -15
  23. package/src/commands/model.ts +4 -5
  24. package/src/commands/optimize-context.ts +202 -0
  25. package/src/commands/plan.ts +148 -92
  26. package/src/commands/qa.ts +14 -23
  27. package/src/commands/release.ts +504 -275
  28. package/src/commands/review.ts +643 -86
  29. package/src/commands/status.ts +44 -17
  30. package/src/commands/supi.ts +69 -41
  31. package/src/commands/update.ts +57 -2
  32. package/src/config/defaults.ts +6 -39
  33. package/src/config/loader.ts +388 -40
  34. package/src/config/model-resolver.ts +26 -22
  35. package/src/config/schema.ts +113 -48
  36. package/src/context/analyzer.ts +61 -2
  37. package/src/context/optimizer.ts +199 -0
  38. package/src/context-mode/compressor.ts +14 -11
  39. package/src/context-mode/detector.ts +16 -54
  40. package/src/context-mode/event-extractor.ts +45 -16
  41. package/src/context-mode/event-store.ts +225 -16
  42. package/src/context-mode/hooks.ts +195 -22
  43. package/src/context-mode/knowledge/chunker.ts +235 -0
  44. package/src/context-mode/knowledge/store.ts +187 -0
  45. package/src/context-mode/routing.ts +12 -23
  46. package/src/context-mode/sandbox/executor.ts +183 -0
  47. package/src/context-mode/sandbox/runners.ts +40 -0
  48. package/src/context-mode/snapshot-builder.ts +243 -7
  49. package/src/context-mode/tools.ts +440 -0
  50. package/src/context-mode/web/fetcher.ts +117 -0
  51. package/src/context-mode/web/html-to-md.ts +293 -0
  52. package/src/debug/logger.ts +107 -0
  53. package/src/deps/registry.ts +0 -20
  54. package/src/docs/drift.ts +454 -0
  55. package/src/fix-pr/fetch-comments.ts +66 -0
  56. package/src/git/commit-msg.ts +2 -1
  57. package/src/git/commit.ts +123 -141
  58. package/src/git/conventions.ts +2 -2
  59. package/src/git/status.ts +4 -1
  60. package/src/lsp/bridge.ts +138 -12
  61. package/src/planning/approval-flow.ts +125 -19
  62. package/src/planning/plan-writer-prompt.ts +4 -11
  63. package/src/planning/planning-ask-tool.ts +81 -0
  64. package/src/planning/prompt-builder.ts +9 -169
  65. package/src/planning/system-prompt.ts +290 -0
  66. package/src/platform/omp.ts +50 -4
  67. package/src/platform/progress.ts +182 -0
  68. package/src/platform/test-utils.ts +4 -1
  69. package/src/platform/tui-colors.ts +30 -0
  70. package/src/platform/types.ts +1 -0
  71. package/src/qa/detect-app-type.ts +102 -0
  72. package/src/qa/discover-routes.ts +353 -0
  73. package/src/quality/ai-session.ts +96 -0
  74. package/src/quality/ai-setup.ts +86 -0
  75. package/src/quality/gates/ai-review.ts +129 -0
  76. package/src/quality/gates/build.ts +8 -0
  77. package/src/quality/gates/command.ts +150 -0
  78. package/src/quality/gates/format.ts +28 -0
  79. package/src/quality/gates/lint.ts +22 -0
  80. package/src/quality/gates/lsp-diagnostics.ts +84 -0
  81. package/src/quality/gates/test-suite.ts +8 -0
  82. package/src/quality/gates/typecheck.ts +22 -0
  83. package/src/quality/registry.ts +25 -0
  84. package/src/quality/review-gates.ts +33 -0
  85. package/src/quality/runner.ts +268 -0
  86. package/src/quality/schemas.ts +48 -0
  87. package/src/quality/setup.ts +227 -0
  88. package/src/release/changelog.ts +7 -3
  89. package/src/release/channels/custom.ts +43 -0
  90. package/src/release/channels/gitea.ts +35 -0
  91. package/src/release/channels/github.ts +35 -0
  92. package/src/release/channels/gitlab.ts +35 -0
  93. package/src/release/channels/registry.ts +52 -0
  94. package/src/release/channels/types.ts +27 -0
  95. package/src/release/detector.ts +10 -63
  96. package/src/release/executor.ts +61 -51
  97. package/src/release/prompt.ts +38 -38
  98. package/src/release/version.ts +129 -10
  99. package/src/review/agent-loader.ts +331 -0
  100. package/src/review/consolidator.ts +180 -0
  101. package/src/review/default-agents/correctness.md +72 -0
  102. package/src/review/default-agents/maintainability.md +64 -0
  103. package/src/review/default-agents/security.md +67 -0
  104. package/src/review/fixer.ts +219 -0
  105. package/src/review/multi-agent-runner.ts +135 -0
  106. package/src/review/output.ts +147 -0
  107. package/src/review/prompts/agent-review-wrapper.md +36 -0
  108. package/src/review/prompts/fix-findings.md +32 -0
  109. package/src/review/prompts/fix-output-schema.md +18 -0
  110. package/src/review/prompts/invalid-output-retry.md +22 -0
  111. package/src/review/prompts/output-instructions.md +14 -0
  112. package/src/review/prompts/review-output-schema.md +38 -0
  113. package/src/review/prompts/single-review.md +53 -0
  114. package/src/review/prompts/validation-review.md +30 -0
  115. package/src/review/runner.ts +128 -0
  116. package/src/review/scope.ts +353 -0
  117. package/src/review/template.ts +15 -0
  118. package/src/review/types.ts +296 -0
  119. package/src/review/validator.ts +160 -0
  120. package/src/storage/plans.ts +5 -3
  121. package/src/storage/reports.ts +50 -7
  122. package/src/storage/review-sessions.ts +117 -0
  123. package/src/text.ts +19 -0
  124. package/src/types.ts +336 -26
  125. package/src/utils/paths.ts +39 -0
  126. package/src/visual/companion.ts +5 -3
  127. package/src/visual/start-server.ts +101 -0
  128. package/src/visual/stop-server.ts +39 -0
  129. package/bin/ctx-mode-wrapper.mjs +0 -66
  130. package/src/config/profiles.ts +0 -64
  131. package/src/context-mode/installer.ts +0 -38
  132. package/src/quality/ai-review-gate.ts +0 -43
  133. package/src/quality/gate-runner.ts +0 -67
  134. package/src/quality/lsp-gate.ts +0 -24
  135. package/src/quality/test-gate.ts +0 -39
  136. package/src/visual/scripts/start-server.sh +0 -98
  137. package/src/visual/scripts/stop-server.sh +0 -21
@@ -1,24 +1,51 @@
1
1
  import type { Platform, PlatformContext } from "../platform/types.js";
2
+ import { DEFAULT_CONFIG } from "../config/defaults.js";
3
+ import { formatConfigErrors, inspectConfig } from "../config/loader.js";
2
4
  import { listPlans } from "../storage/plans.js";
3
- import { loadConfig } from "../config/loader.js";
5
+ import { summarizeEnabledGates } from "../quality/setup.js";
6
+
7
+ export interface StatusCommandDependencies {
8
+ inspectConfig: typeof inspectConfig;
9
+ listPlans: typeof listPlans;
10
+ }
11
+
12
+ const STATUS_COMMAND_DEPENDENCIES: StatusCommandDependencies = {
13
+ inspectConfig,
14
+ listPlans,
15
+ };
16
+
17
+ function formatStatusSummary(platform: Platform, ctx: PlatformContext, deps: StatusCommandDependencies): string {
18
+ const inspection = deps.inspectConfig(platform.paths, ctx.cwd);
19
+ const config = inspection.effectiveConfig ?? DEFAULT_CONFIG;
20
+
21
+ if (inspection.parseErrors.length > 0 || inspection.validationErrors.length > 0) {
22
+ return `Config error: ${formatConfigErrors(inspection).split("\n")[0]}`;
23
+ }
24
+
25
+ return `Gates: ${summarizeEnabledGates(config.quality.gates)}`;
26
+ }
27
+
28
+ export async function showStatusDialog(
29
+ platform: Platform,
30
+ ctx: PlatformContext,
31
+ deps: StatusCommandDependencies = STATUS_COMMAND_DEPENDENCIES,
32
+ ): Promise<void> {
33
+ const plans = deps.listPlans(platform.paths, ctx.cwd);
34
+ const options = [
35
+ formatStatusSummary(platform, ctx, deps),
36
+ `Plans: ${plans.length === 0 ? "none" : ""}`,
37
+ ...plans.map((plan) => ` · ${plan}`),
38
+ "",
39
+ "Close",
40
+ ];
41
+
42
+ await ctx.ui.select("Supipowers Status", options, {
43
+ helpText: "Esc to close",
44
+ });
45
+ }
4
46
 
5
47
  export function handleStatus(platform: Platform, ctx: PlatformContext): void {
6
- void (async () => {
7
- const plans = listPlans(platform.paths, ctx.cwd);
8
- const config = loadConfig(platform.paths, ctx.cwd);
9
-
10
- const options = [
11
- `Profile: ${config.defaultProfile}`,
12
- `Plans: ${plans.length === 0 ? "none" : ""}`,
13
- ...plans.map((p) => ` · ${p}`),
14
- "",
15
- "Close",
16
- ];
17
-
18
- await ctx.ui.select("Supipowers Status", options, {
19
- helpText: "Esc to close",
20
- });
21
- })();
48
+ void showStatusDialog(platform, ctx, STATUS_COMMAND_DEPENDENCIES);
22
49
  }
23
50
 
24
51
  export function registerStatusCommand(platform: Platform): void {
@@ -1,48 +1,77 @@
1
1
  import type { Platform, PlatformContext } from "../platform/types.js";
2
- import { loadConfig } from "../config/loader.js";
2
+ import { DEFAULT_CONFIG } from "../config/defaults.js";
3
+ import { formatConfigErrors, inspectConfig } from "../config/loader.js";
3
4
  import { loadLatestReport } from "../storage/reports.js";
4
5
  import { listPlans } from "../storage/plans.js";
6
+ import { summarizeEnabledGates } from "../quality/setup.js";
5
7
 
6
- export function handleSupi(platform: Platform, ctx: PlatformContext): void {
7
- void (async () => {
8
- const config = loadConfig(platform.paths, ctx.cwd);
9
- const latestReport = loadLatestReport(platform.paths, ctx.cwd);
10
- const plans = listPlans(platform.paths, ctx.cwd);
11
-
12
- const commands = [
13
- "/supi:plan — Start collaborative planning",
14
- "/supi:review — Run quality gates",
15
- "/supi:qa — E2E product testing with Playwright",
16
- "/supi:fix-pr — Fix PR review comments",
17
- "/supi:release — Release automation",
18
- "/supi:config — Manage configuration",
19
- "/supi:status — Show project status",
20
- "/supi:doctor — Run health checks",
21
- "/supi:update — Update to latest version",
22
- "/supi:context Show context breakdown",
23
- ];
24
-
25
- const status = [
26
- `Profile: ${config.defaultProfile}`,
27
- `Plans: ${plans.length}`,
28
- `Last review: ${latestReport ? `${latestReport.timestamp.slice(0, 10)} (${latestReport.passed ? "passed" : "failed"})` : "none"}`,
29
- ];
30
-
31
- const choice = await ctx.ui.select(
32
- "Supipowers",
33
- [...commands, "", ...status, "", "Close"],
34
- { helpText: "Select a command to run · Esc to close" },
35
- );
36
-
37
- if (choice && choice.startsWith("/supi:")) {
38
- const cmdName = choice.split(" ")[0].slice(1); // remove leading /
39
- const cmd = platform.getCommands().find((c) => c.name === cmdName);
40
- if (cmd?.handler) {
41
- await cmd.handler("", ctx as any);
42
- }
8
+ export interface SupiCommandDependencies {
9
+ inspectConfig: typeof inspectConfig;
10
+ loadLatestReport: typeof loadLatestReport;
11
+ listPlans: typeof listPlans;
12
+ }
13
+
14
+ const SUPI_COMMAND_DEPENDENCIES: SupiCommandDependencies = {
15
+ inspectConfig,
16
+ loadLatestReport,
17
+ listPlans,
18
+ };
19
+
20
+ function formatOverviewStatus(platform: Platform, ctx: PlatformContext, deps: SupiCommandDependencies): string[] {
21
+ const inspection = deps.inspectConfig(platform.paths, ctx.cwd);
22
+ const config = inspection.effectiveConfig ?? DEFAULT_CONFIG;
23
+ const latestReport = deps.loadLatestReport(platform.paths, ctx.cwd);
24
+ const plans = deps.listPlans(platform.paths, ctx.cwd);
25
+
26
+ return [
27
+ inspection.parseErrors.length > 0 || inspection.validationErrors.length > 0
28
+ ? `Config error: ${formatConfigErrors(inspection).split("\n")[0]}`
29
+ : `Gates: ${summarizeEnabledGates(config.quality.gates)}`,
30
+ `Plans: ${plans.length}`,
31
+ `Last checks: ${latestReport ? `${latestReport.timestamp.slice(0, 10)} (${latestReport.overallStatus})` : "none"}`,
32
+ ];
33
+ }
34
+
35
+ export async function showSupiDialog(
36
+ platform: Platform,
37
+ ctx: PlatformContext,
38
+ deps: SupiCommandDependencies = SUPI_COMMAND_DEPENDENCIES,
39
+ ): Promise<void> {
40
+ const commands = [
41
+ "/supi:plan — Start collaborative planning",
42
+ "/supi:review — Run AI code review pipeline",
43
+ "/supi:agents — List and manage review agents",
44
+ "/supi:checks — Run quality gates",
45
+ "/supi:qa — E2E product testing with Playwright",
46
+ "/supi:fix-pr — Fix PR review comments",
47
+ "/supi:release — Release automation",
48
+ "/supi:config — Manage configuration",
49
+ "/supi:status — Show project status",
50
+ "/supi:doctor — Run health checks",
51
+ "/supi:update — Update to latest version",
52
+ "/supi:context — Show context breakdown",
53
+ "/supi:optimize-context — Optimize context to save tokens",
54
+ ];
55
+ const status = formatOverviewStatus(platform, ctx, deps);
56
+
57
+ const choice = await ctx.ui.select(
58
+ "Supipowers",
59
+ [...commands, "", ...status, "", "Close"],
60
+ { helpText: "Select a command to run · Esc to close" },
61
+ );
62
+
63
+ if (choice && choice.startsWith("/supi:")) {
64
+ const commandName = choice.split(" ")[0].slice(1);
65
+ const command = platform.getCommands().find((candidate) => candidate.name === commandName);
66
+ if (command?.handler) {
67
+ await command.handler("", ctx as any);
43
68
  }
44
- })().catch((err) => {
45
- ctx.ui.notify(`Supipowers error: ${(err as Error).message}`, "error");
69
+ }
70
+ }
71
+
72
+ export function handleSupi(platform: Platform, ctx: PlatformContext): void {
73
+ void showSupiDialog(platform, ctx, SUPI_COMMAND_DEPENDENCIES).catch((error) => {
74
+ ctx.ui.notify(`Supipowers error: ${(error as Error).message}`, "error");
46
75
  });
47
76
  }
48
77
 
@@ -50,7 +79,6 @@ export function registerSupiCommand(platform: Platform): void {
50
79
  platform.registerCommand("supi", {
51
80
  description: "Supipowers overview — show available commands and project status",
52
81
  async handler(_args: string | undefined, ctx: any) {
53
- // Handled via input event interception — this is a fallback for non-interactive contexts
54
82
  handleSupi(platform, ctx);
55
83
  },
56
84
  });
@@ -1,8 +1,8 @@
1
1
  import type { Platform, PlatformContext } from "../platform/types.js";
2
2
  import type { DependencyStatus, InstallResult } from "../deps/registry.js";
3
3
  import { scanAll, installAll, formatReport } from "../deps/registry.js";
4
- import { readFileSync, existsSync, mkdirSync, cpSync, rmSync, readdirSync } from "node:fs";
5
- import { join } from "node:path";
4
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, cpSync, rmSync, readdirSync } from "node:fs";
5
+ import { join, dirname } from "node:path";
6
6
  import { tmpdir } from "node:os";
7
7
 
8
8
  // ── Options builder ──────────────────────────────────────
@@ -94,6 +94,10 @@ async function updateSupipowers(
94
94
  // Copy extension files
95
95
  mkdirSync(extDir, { recursive: true });
96
96
  cpSync(join(downloadedRoot, "src"), join(extDir, "src"), { recursive: true });
97
+ const binSource = join(downloadedRoot, "bin");
98
+ if (existsSync(binSource)) {
99
+ cpSync(binSource, join(extDir, "bin"), { recursive: true });
100
+ }
97
101
  cpSync(join(downloadedRoot, "package.json"), join(extDir, "package.json"));
98
102
 
99
103
  // Copy skills
@@ -110,6 +114,9 @@ async function updateSupipowers(
110
114
  }
111
115
  }
112
116
 
117
+ // Clean up legacy MCP entries and re-register with current name
118
+ cleanupLegacyMcp(agentDir);
119
+
113
120
  ctx.ui.notify(`supipowers updated to v${latestVersion}`, "info");
114
121
  return { updated: true, fromVersion: currentVersion, toVersion: latestVersion };
115
122
  } finally {
@@ -174,6 +181,54 @@ export function handleUpdate(platform: Platform, ctx: PlatformContext): void {
174
181
  })();
175
182
  }
176
183
 
184
+ // ── Legacy cleanup ───────────────────────────────────────
185
+
186
+ /**
187
+ * Remove stale MCP artifacts from pre-v0.5.x installs.
188
+ * Context-mode tools are now native — remove any MCP server entries.
189
+ *
190
+ * Handles:
191
+ * 1. Old "context-mode" key in agent/mcp.json
192
+ * 2. "supi-context-mode" key in agent/mcp.json (no longer needed)
193
+ * 3. Old settings/mcp.json file (wrong path — should be agent/mcp.json)
194
+ */
195
+ function cleanupLegacyMcp(agentDir: string): void {
196
+ const mcpConfigPath = join(agentDir, "mcp.json");
197
+
198
+ // Remove context-mode MCP entries (no longer needed — tools are native)
199
+ if (existsSync(mcpConfigPath)) {
200
+ try {
201
+ const config = JSON.parse(readFileSync(mcpConfigPath, "utf8"));
202
+ if (config.mcpServers) {
203
+ delete config.mcpServers["context-mode"];
204
+ delete config.mcpServers["supi-context-mode"];
205
+ writeFileSync(mcpConfigPath, JSON.stringify(config, null, 2));
206
+ }
207
+ } catch {
208
+ // Corrupted mcp.json — leave it for the user
209
+ }
210
+ }
211
+
212
+ // Remove old settings/mcp.json from pre-v0.5.x installs (wrong path)
213
+ const platformRoot = dirname(agentDir);
214
+ const oldMcpPath = join(platformRoot, "settings", "mcp.json");
215
+ if (!existsSync(oldMcpPath)) return;
216
+
217
+ try {
218
+ const config = JSON.parse(readFileSync(oldMcpPath, "utf8"));
219
+ delete config.mcpServers?.["context-mode"];
220
+ delete config.mcpServers?.["supi-context-mode"];
221
+
222
+ if (!config.mcpServers || Object.keys(config.mcpServers).length === 0) {
223
+ rmSync(oldMcpPath);
224
+ } else {
225
+ writeFileSync(oldMcpPath, JSON.stringify(config, null, 2));
226
+ }
227
+ } catch {
228
+ try { rmSync(oldMcpPath); } catch { /* best effort */ }
229
+ }
230
+ }
231
+
177
232
  // ── Command registration ─────────────────────────────────
178
233
 
179
234
  export function registerUpdateCommand(platform: Platform): void {
@@ -1,22 +1,22 @@
1
1
  // src/config/defaults.ts
2
- import type { SupipowersConfig, Profile } from "../types.js";
2
+ import type { SupipowersConfig } from "../types.js";
3
3
 
4
4
  export const DEFAULT_CONFIG: SupipowersConfig = {
5
5
  version: "1.0.0",
6
- defaultProfile: "thorough",
6
+ quality: {
7
+ gates: {},
8
+ },
7
9
  lsp: {
8
10
  setupGuide: true,
9
11
  },
10
- notifications: {
11
- verbosity: "normal",
12
- },
13
12
  qa: {
14
13
  framework: null,
15
- command: null,
16
14
  e2e: false,
17
15
  },
18
16
  release: {
19
17
  channels: [],
18
+ tagFormat: "v${version}",
19
+ customChannels: {},
20
20
  },
21
21
  contextMode: {
22
22
  enabled: true,
@@ -33,36 +33,3 @@ export const DEFAULT_CONFIG: SupipowersConfig = {
33
33
  closeSessionsOnExit: false,
34
34
  },
35
35
  };
36
-
37
- export const BUILTIN_PROFILES: Record<string, Profile> = {
38
- quick: {
39
- name: "quick",
40
- gates: {
41
- lspDiagnostics: true,
42
- aiReview: { enabled: true, depth: "quick" },
43
- codeQuality: false,
44
- testSuite: false,
45
- e2e: false,
46
- },
47
- },
48
- thorough: {
49
- name: "thorough",
50
- gates: {
51
- lspDiagnostics: true,
52
- aiReview: { enabled: true, depth: "deep" },
53
- codeQuality: true,
54
- testSuite: false,
55
- e2e: false,
56
- },
57
- },
58
- "full-regression": {
59
- name: "full-regression",
60
- gates: {
61
- lspDiagnostics: true,
62
- aiReview: { enabled: true, depth: "deep" },
63
- codeQuality: true,
64
- testSuite: true,
65
- e2e: true,
66
- },
67
- },
68
- };