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.
- package/README.md +118 -56
- package/bin/install.ts +48 -128
- package/package.json +11 -3
- package/skills/code-review/SKILL.md +137 -40
- package/skills/context-mode/SKILL.md +67 -56
- package/skills/creating-supi-agents/SKILL.md +204 -0
- package/skills/debugging/SKILL.md +86 -40
- package/skills/fix-pr/SKILL.md +96 -65
- package/skills/planning/SKILL.md +103 -46
- package/skills/qa-strategy/SKILL.md +68 -46
- package/skills/receiving-code-review/SKILL.md +60 -53
- package/skills/release/SKILL.md +111 -39
- package/skills/tdd/SKILL.md +118 -67
- package/skills/verification/SKILL.md +71 -37
- package/src/bootstrap.ts +27 -5
- package/src/commands/agents.ts +249 -0
- package/src/commands/ai-review.ts +1113 -0
- package/src/commands/config.ts +224 -95
- package/src/commands/doctor.ts +19 -13
- package/src/commands/fix-pr.ts +8 -11
- package/src/commands/generate.ts +200 -0
- package/src/commands/model-picker.ts +5 -15
- package/src/commands/model.ts +4 -5
- package/src/commands/optimize-context.ts +202 -0
- package/src/commands/plan.ts +148 -92
- package/src/commands/qa.ts +14 -23
- package/src/commands/release.ts +504 -275
- package/src/commands/review.ts +643 -86
- package/src/commands/status.ts +44 -17
- package/src/commands/supi.ts +69 -41
- package/src/commands/update.ts +57 -2
- package/src/config/defaults.ts +6 -39
- package/src/config/loader.ts +388 -40
- package/src/config/model-resolver.ts +26 -22
- package/src/config/schema.ts +113 -48
- package/src/context/analyzer.ts +61 -2
- package/src/context/optimizer.ts +199 -0
- package/src/context-mode/compressor.ts +14 -11
- package/src/context-mode/detector.ts +16 -54
- package/src/context-mode/event-extractor.ts +45 -16
- package/src/context-mode/event-store.ts +225 -16
- package/src/context-mode/hooks.ts +195 -22
- package/src/context-mode/knowledge/chunker.ts +235 -0
- package/src/context-mode/knowledge/store.ts +187 -0
- package/src/context-mode/routing.ts +12 -23
- package/src/context-mode/sandbox/executor.ts +183 -0
- package/src/context-mode/sandbox/runners.ts +40 -0
- package/src/context-mode/snapshot-builder.ts +243 -7
- package/src/context-mode/tools.ts +440 -0
- package/src/context-mode/web/fetcher.ts +117 -0
- package/src/context-mode/web/html-to-md.ts +293 -0
- package/src/debug/logger.ts +107 -0
- package/src/deps/registry.ts +0 -20
- package/src/docs/drift.ts +454 -0
- package/src/fix-pr/fetch-comments.ts +66 -0
- package/src/git/commit-msg.ts +2 -1
- package/src/git/commit.ts +123 -141
- package/src/git/conventions.ts +2 -2
- package/src/git/status.ts +4 -1
- package/src/lsp/bridge.ts +138 -12
- package/src/planning/approval-flow.ts +125 -19
- package/src/planning/plan-writer-prompt.ts +4 -11
- package/src/planning/planning-ask-tool.ts +81 -0
- package/src/planning/prompt-builder.ts +9 -169
- package/src/planning/system-prompt.ts +290 -0
- package/src/platform/omp.ts +50 -4
- package/src/platform/progress.ts +182 -0
- package/src/platform/test-utils.ts +4 -1
- package/src/platform/tui-colors.ts +30 -0
- package/src/platform/types.ts +1 -0
- package/src/qa/detect-app-type.ts +102 -0
- package/src/qa/discover-routes.ts +353 -0
- package/src/quality/ai-session.ts +96 -0
- package/src/quality/ai-setup.ts +86 -0
- package/src/quality/gates/ai-review.ts +129 -0
- package/src/quality/gates/build.ts +8 -0
- package/src/quality/gates/command.ts +150 -0
- package/src/quality/gates/format.ts +28 -0
- package/src/quality/gates/lint.ts +22 -0
- package/src/quality/gates/lsp-diagnostics.ts +84 -0
- package/src/quality/gates/test-suite.ts +8 -0
- package/src/quality/gates/typecheck.ts +22 -0
- package/src/quality/registry.ts +25 -0
- package/src/quality/review-gates.ts +33 -0
- package/src/quality/runner.ts +268 -0
- package/src/quality/schemas.ts +48 -0
- package/src/quality/setup.ts +227 -0
- package/src/release/changelog.ts +7 -3
- package/src/release/channels/custom.ts +43 -0
- package/src/release/channels/gitea.ts +35 -0
- package/src/release/channels/github.ts +35 -0
- package/src/release/channels/gitlab.ts +35 -0
- package/src/release/channels/registry.ts +52 -0
- package/src/release/channels/types.ts +27 -0
- package/src/release/detector.ts +10 -63
- package/src/release/executor.ts +61 -51
- package/src/release/prompt.ts +38 -38
- package/src/release/version.ts +129 -10
- package/src/review/agent-loader.ts +331 -0
- package/src/review/consolidator.ts +180 -0
- package/src/review/default-agents/correctness.md +72 -0
- package/src/review/default-agents/maintainability.md +64 -0
- package/src/review/default-agents/security.md +67 -0
- package/src/review/fixer.ts +219 -0
- package/src/review/multi-agent-runner.ts +135 -0
- package/src/review/output.ts +147 -0
- package/src/review/prompts/agent-review-wrapper.md +36 -0
- package/src/review/prompts/fix-findings.md +32 -0
- package/src/review/prompts/fix-output-schema.md +18 -0
- package/src/review/prompts/invalid-output-retry.md +22 -0
- package/src/review/prompts/output-instructions.md +14 -0
- package/src/review/prompts/review-output-schema.md +38 -0
- package/src/review/prompts/single-review.md +53 -0
- package/src/review/prompts/validation-review.md +30 -0
- package/src/review/runner.ts +128 -0
- package/src/review/scope.ts +353 -0
- package/src/review/template.ts +15 -0
- package/src/review/types.ts +296 -0
- package/src/review/validator.ts +160 -0
- package/src/storage/plans.ts +5 -3
- package/src/storage/reports.ts +50 -7
- package/src/storage/review-sessions.ts +117 -0
- package/src/text.ts +19 -0
- package/src/types.ts +336 -26
- package/src/utils/paths.ts +39 -0
- package/src/visual/companion.ts +5 -3
- package/src/visual/start-server.ts +101 -0
- package/src/visual/stop-server.ts +39 -0
- package/bin/ctx-mode-wrapper.mjs +0 -66
- package/src/config/profiles.ts +0 -64
- package/src/context-mode/installer.ts +0 -38
- package/src/quality/ai-review-gate.ts +0 -43
- package/src/quality/gate-runner.ts +0 -67
- package/src/quality/lsp-gate.ts +0 -24
- package/src/quality/test-gate.ts +0 -39
- package/src/visual/scripts/start-server.sh +0 -98
- package/src/visual/scripts/stop-server.sh +0 -21
package/src/bootstrap.ts
CHANGED
|
@@ -6,8 +6,9 @@ import { registerSupiCommand, handleSupi } from "./commands/supi.js";
|
|
|
6
6
|
import { registerConfigCommand, handleConfig } from "./commands/config.js";
|
|
7
7
|
import { registerStatusCommand, handleStatus } from "./commands/status.js";
|
|
8
8
|
import { registerPlanCommand, getActiveVisualSessionDir, setActiveVisualSessionDir } from "./commands/plan.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { stopVisualServer } from "./visual/stop-server.js";
|
|
10
|
+
import { registerChecksCommand, handleChecksCommand } from "./commands/review.js";
|
|
11
|
+
import { registerAiReviewCommand, handleAiReview } from "./commands/ai-review.js";
|
|
11
12
|
import { registerQaCommand } from "./commands/qa.js";
|
|
12
13
|
import { registerReleaseCommand, handleRelease } from "./commands/release.js";
|
|
13
14
|
import { registerUpdateCommand, handleUpdate } from "./commands/update.js";
|
|
@@ -17,7 +18,10 @@ import { registerModelCommand, handleModel } from "./commands/model.js";
|
|
|
17
18
|
import { executeManagerAction } from "./mcp/manager-tool.js";
|
|
18
19
|
import { registerFixPrCommand } from "./commands/fix-pr.js";
|
|
19
20
|
import { registerContextCommand, handleContext } from "./commands/context.js";
|
|
21
|
+
import { registerOptimizeContextCommand, handleOptimizeContext } from "./commands/optimize-context.js";
|
|
20
22
|
import { registerCommitCommand, handleCommit } from "./commands/commit.js";
|
|
23
|
+
import { registerGenerateCommand } from "./commands/generate.js";
|
|
24
|
+
import { registerAgentsCommand, handleAgents } from "./commands/agents.js";
|
|
21
25
|
import { loadConfig } from "./config/loader.js";
|
|
22
26
|
import { registerContextModeHooks } from "./context-mode/hooks.js";
|
|
23
27
|
import { loadMcpRegistry } from "./mcp/config.js";
|
|
@@ -25,6 +29,8 @@ import { McpcClient } from "./mcp/mcpc.js";
|
|
|
25
29
|
import { parseTags, computeActiveServers } from "./mcp/activation.js";
|
|
26
30
|
import { initializeMcpServers, shutdownMcpServers } from "./mcp/lifecycle.js";
|
|
27
31
|
import { registerPlanApprovalHook } from "./planning/approval-flow.js";
|
|
32
|
+
import { registerPlanningSystemPromptHook } from "./planning/system-prompt.js";
|
|
33
|
+
import { registerPlanningAskTool } from "./planning/planning-ask-tool.js";
|
|
28
34
|
|
|
29
35
|
// TUI-only commands — intercepted at the input level to prevent
|
|
30
36
|
// message submission and "Working..." indicator
|
|
@@ -32,13 +38,17 @@ const TUI_COMMANDS: Record<string, (platform: Platform, ctx: any, args?: string)
|
|
|
32
38
|
"supi": (platform, ctx) => handleSupi(platform, ctx),
|
|
33
39
|
"supi:config": (platform, ctx) => handleConfig(platform, ctx),
|
|
34
40
|
"supi:status": (platform, ctx) => handleStatus(platform, ctx),
|
|
41
|
+
"supi:review": (platform, ctx) => handleAiReview(platform, ctx),
|
|
35
42
|
"supi:update": (platform, ctx) => handleUpdate(platform, ctx),
|
|
36
43
|
"supi:doctor": (platform, ctx) => handleDoctor(platform, ctx),
|
|
37
44
|
"supi:mcp": (platform, ctx) => handleMcp(platform, ctx),
|
|
38
45
|
"supi:model": (platform, ctx) => handleModel(platform, ctx),
|
|
39
46
|
"supi:context": (platform, ctx) => handleContext(platform, ctx),
|
|
47
|
+
"supi:optimize-context": (platform, ctx) => handleOptimizeContext(platform, ctx),
|
|
40
48
|
"supi:commit": (platform, ctx, args) => handleCommit(platform, ctx, args),
|
|
41
49
|
"supi:release": (platform, ctx, args) => handleRelease(platform, ctx, args),
|
|
50
|
+
"supi:checks": (platform, ctx, args) => handleChecksCommand(platform, ctx, args),
|
|
51
|
+
"supi:agents": (platform, ctx, args) => handleAgents(platform, ctx, args),
|
|
42
52
|
};
|
|
43
53
|
|
|
44
54
|
let pendingTags: string[] = [];
|
|
@@ -59,7 +69,8 @@ export function bootstrap(platform: Platform): void {
|
|
|
59
69
|
registerConfigCommand(platform);
|
|
60
70
|
registerStatusCommand(platform);
|
|
61
71
|
registerPlanCommand(platform);
|
|
62
|
-
|
|
72
|
+
registerChecksCommand(platform);
|
|
73
|
+
registerAiReviewCommand(platform);
|
|
63
74
|
registerQaCommand(platform);
|
|
64
75
|
registerReleaseCommand(platform);
|
|
65
76
|
registerUpdateCommand(platform);
|
|
@@ -68,11 +79,15 @@ export function bootstrap(platform: Platform): void {
|
|
|
68
79
|
registerMcpCommand(platform);
|
|
69
80
|
registerModelCommand(platform);
|
|
70
81
|
registerContextCommand(platform);
|
|
82
|
+
registerOptimizeContextCommand(platform);
|
|
71
83
|
registerCommitCommand(platform);
|
|
84
|
+
registerGenerateCommand(platform);
|
|
85
|
+
registerAgentsCommand(platform);
|
|
72
86
|
|
|
73
87
|
|
|
74
88
|
// Register plan approval flow (agent_end hook for plan approval UI)
|
|
75
89
|
registerPlanApprovalHook(platform);
|
|
90
|
+
registerPlanningAskTool(platform);
|
|
76
91
|
|
|
77
92
|
|
|
78
93
|
// Intercept TUI-only commands at the input level — this runs BEFORE
|
|
@@ -108,6 +123,10 @@ export function bootstrap(platform: Platform): void {
|
|
|
108
123
|
registerContextModeHooks(platform, config);
|
|
109
124
|
|
|
110
125
|
|
|
126
|
+
// Planning-mode prompt override — registered after context-mode so it wins
|
|
127
|
+
// when /supi:plan is active and otherwise stays dormant.
|
|
128
|
+
registerPlanningSystemPromptHook(platform);
|
|
129
|
+
|
|
111
130
|
// MCP per-turn activation
|
|
112
131
|
platform.on("before_agent_start", async (event, ctx) => {
|
|
113
132
|
const registry = loadMcpRegistry(platform.paths, ctx.cwd);
|
|
@@ -136,11 +155,14 @@ export function bootstrap(platform: Platform): void {
|
|
|
136
155
|
// Clean up any leftover visual companion from a previous session
|
|
137
156
|
const previousVisualDir = getActiveVisualSessionDir();
|
|
138
157
|
if (previousVisualDir) {
|
|
139
|
-
|
|
140
|
-
platform.exec("bash", [stopScript, previousVisualDir], { cwd: getScriptsDir() }).catch(() => {});
|
|
158
|
+
stopVisualServer(previousVisualDir);
|
|
141
159
|
setActiveVisualSessionDir(null);
|
|
142
160
|
}
|
|
143
161
|
|
|
162
|
+
// Clear leftover model-override status from a previous session.
|
|
163
|
+
// OMP's StatusLine never clears hook statuses on /new, so extensions must do it.
|
|
164
|
+
ctx.ui?.setStatus?.("supi-model", undefined);
|
|
165
|
+
|
|
144
166
|
// MCP: always register mcpc_manager tool (agent needs it even with zero servers)
|
|
145
167
|
if (platform.registerTool) {
|
|
146
168
|
registerMcpcManagerTool(platform, ctx);
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import type { Platform } from "../platform/types.js";
|
|
2
|
+
import {
|
|
3
|
+
loadMergedReviewAgents,
|
|
4
|
+
writeAgentFile,
|
|
5
|
+
addAgentToConfig,
|
|
6
|
+
getReviewAgentsDir,
|
|
7
|
+
getReviewAgentsConfigPath,
|
|
8
|
+
getGlobalReviewAgentsDir,
|
|
9
|
+
getGlobalReviewAgentsConfigPath,
|
|
10
|
+
} from "../review/agent-loader.js";
|
|
11
|
+
import { selectModelFromList } from "./model.js";
|
|
12
|
+
import type { ConfiguredReviewAgent } from "../types.js";
|
|
13
|
+
import creatingAgentsSkill from "../../skills/creating-supi-agents/SKILL.md" with { type: "text" };
|
|
14
|
+
|
|
15
|
+
// ── List View ──────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
function buildAgentDashboard(agents: ConfiguredReviewAgent[]): string {
|
|
18
|
+
const nameCol = 18;
|
|
19
|
+
const modelCol = 24;
|
|
20
|
+
const scopeCol = 10;
|
|
21
|
+
|
|
22
|
+
const lines: string[] = [
|
|
23
|
+
"\n Review Agents\n",
|
|
24
|
+
` ${"name".padEnd(nameCol)} ${"model".padEnd(modelCol)} ${"scope".padEnd(scopeCol)} focus`,
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
for (const agent of agents) {
|
|
28
|
+
const name = agent.name.padEnd(nameCol);
|
|
29
|
+
const model = (agent.model ?? "—").padEnd(modelCol);
|
|
30
|
+
const scope = (agent.scope ?? "project").padEnd(scopeCol);
|
|
31
|
+
const focus = agent.focus
|
|
32
|
+
? agent.focus.length > 40
|
|
33
|
+
? agent.focus.slice(0, 37) + "..."
|
|
34
|
+
: agent.focus
|
|
35
|
+
: "—";
|
|
36
|
+
lines.push(` ${name} ${model} ${scope} ${focus}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const globalCount = agents.filter((a) => a.scope === "global").length;
|
|
40
|
+
const projectCount = agents.filter((a) => a.scope === "project" || !a.scope).length;
|
|
41
|
+
lines.push("");
|
|
42
|
+
lines.push(` ${agents.length} agent(s) (${projectCount} project, ${globalCount} global)`);
|
|
43
|
+
lines.push("");
|
|
44
|
+
|
|
45
|
+
return lines.join("\n");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ── Create Flow ────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
const KEBAB_CASE_RE = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
51
|
+
|
|
52
|
+
export async function runAgentCreateFlow(platform: Platform, ctx: any): Promise<void> {
|
|
53
|
+
if (!ctx.hasUI) {
|
|
54
|
+
ctx.ui.notify("Agent creation requires interactive mode", "warning");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Step 1: Scope selection
|
|
59
|
+
const scopeChoice = await ctx.ui.select("Where should this agent live?", [
|
|
60
|
+
"This project",
|
|
61
|
+
"Global",
|
|
62
|
+
], { helpText: "Select scope · Esc to cancel" });
|
|
63
|
+
|
|
64
|
+
if (!scopeChoice) return;
|
|
65
|
+
const scope: "global" | "project" = scopeChoice === "Global" ? "global" : "project";
|
|
66
|
+
|
|
67
|
+
// Step 2: Agent name
|
|
68
|
+
const nameInput = await ctx.ui.input("Agent name (kebab-case)", {
|
|
69
|
+
helpText: "e.g. performance, api-design, accessibility",
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (!nameInput) return;
|
|
73
|
+
const agentName = nameInput.trim().toLowerCase();
|
|
74
|
+
|
|
75
|
+
if (!KEBAB_CASE_RE.test(agentName)) {
|
|
76
|
+
ctx.ui.notify(`Invalid agent name "${agentName}" — must be kebab-case (e.g. "my-agent")`, "error");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Check for name collision in target scope
|
|
81
|
+
try {
|
|
82
|
+
const existing = await loadMergedReviewAgents(platform.paths, ctx.cwd);
|
|
83
|
+
const collision = existing.agents.find(
|
|
84
|
+
(a) => a.name === agentName && (a.scope ?? "project") === scope,
|
|
85
|
+
);
|
|
86
|
+
if (collision) {
|
|
87
|
+
ctx.ui.notify(`Agent "${agentName}" already exists in ${scope} scope`, "error");
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
} catch {
|
|
91
|
+
// If loading fails (e.g., no project dir), we can continue
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Step 3: Model selection
|
|
95
|
+
const modelInput = await selectModelFromList(ctx);
|
|
96
|
+
// null means "inherit default" — that's fine
|
|
97
|
+
|
|
98
|
+
// Step 4: Prompt source
|
|
99
|
+
const promptChoice = await ctx.ui.select("Agent prompt", [
|
|
100
|
+
"Send a prompt",
|
|
101
|
+
"Create from zero",
|
|
102
|
+
], { helpText: "Choose how to provide the agent prompt" });
|
|
103
|
+
|
|
104
|
+
if (!promptChoice) return;
|
|
105
|
+
|
|
106
|
+
if (promptChoice === "Create from zero") {
|
|
107
|
+
// Load the creating-supi-agents skill via steer
|
|
108
|
+
loadSkillAndSteer(platform, ctx, scope, agentName, modelInput);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// "Send a prompt" path
|
|
113
|
+
const promptBody = await ctx.ui.input("Paste your agent prompt", {
|
|
114
|
+
helpText: "The instructions the agent follows when reviewing code",
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (!promptBody?.trim()) {
|
|
118
|
+
ctx.ui.notify("Agent creation cancelled — empty prompt", "warning");
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Step 5: Save
|
|
123
|
+
const agentsDir = scope === "global"
|
|
124
|
+
? getGlobalReviewAgentsDir(platform.paths)
|
|
125
|
+
: getReviewAgentsDir(platform.paths, ctx.cwd);
|
|
126
|
+
const configPath = scope === "global"
|
|
127
|
+
? getGlobalReviewAgentsConfigPath(platform.paths)
|
|
128
|
+
: getReviewAgentsConfigPath(platform.paths, ctx.cwd);
|
|
129
|
+
|
|
130
|
+
const fileName = writeAgentFile(agentsDir, agentName, {
|
|
131
|
+
name: agentName,
|
|
132
|
+
description: `${agentName} review agent`,
|
|
133
|
+
focus: null,
|
|
134
|
+
}, promptBody.trim());
|
|
135
|
+
|
|
136
|
+
await addAgentToConfig(configPath, {
|
|
137
|
+
name: agentName,
|
|
138
|
+
enabled: true,
|
|
139
|
+
data: fileName,
|
|
140
|
+
model: modelInput,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
ctx.ui.notify(`Agent "${agentName}" created (${scope})`, "info");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ── Skill Integration (steer pattern) ──────────────────────────
|
|
147
|
+
|
|
148
|
+
function loadSkillAndSteer(
|
|
149
|
+
platform: Platform,
|
|
150
|
+
ctx: any,
|
|
151
|
+
scope: "global" | "project",
|
|
152
|
+
agentName: string,
|
|
153
|
+
model: string | null,
|
|
154
|
+
): void {
|
|
155
|
+
const agentsDir = scope === "global"
|
|
156
|
+
? getGlobalReviewAgentsDir(platform.paths)
|
|
157
|
+
: getReviewAgentsDir(platform.paths, ctx.cwd);
|
|
158
|
+
const configPath = scope === "global"
|
|
159
|
+
? getGlobalReviewAgentsConfigPath(platform.paths)
|
|
160
|
+
: getReviewAgentsConfigPath(platform.paths, ctx.cwd);
|
|
161
|
+
|
|
162
|
+
const prompt = buildSkillSteerPrompt(agentName, scope, agentsDir, configPath, model);
|
|
163
|
+
|
|
164
|
+
platform.sendMessage(
|
|
165
|
+
{
|
|
166
|
+
customType: "supi-agents-create",
|
|
167
|
+
content: [{ type: "text", text: prompt }],
|
|
168
|
+
display: "none",
|
|
169
|
+
},
|
|
170
|
+
{ deliverAs: "steer", triggerTurn: true },
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function buildSkillSteerPrompt(
|
|
175
|
+
agentName: string,
|
|
176
|
+
scope: "global" | "project",
|
|
177
|
+
agentsDir: string,
|
|
178
|
+
configPath: string,
|
|
179
|
+
model: string | null,
|
|
180
|
+
): string {
|
|
181
|
+
return `You are guiding the user through creating a new AI review agent for supipowers' multi-agent code review pipeline.
|
|
182
|
+
|
|
183
|
+
## Agent Details (already collected)
|
|
184
|
+
- **Name**: ${agentName}
|
|
185
|
+
- **Scope**: ${scope}
|
|
186
|
+
- **Model**: ${model ?? "inherit default"}
|
|
187
|
+
- **Target directory**: ${agentsDir}
|
|
188
|
+
- **Config path**: ${configPath}
|
|
189
|
+
|
|
190
|
+
## Skill Instructions
|
|
191
|
+
|
|
192
|
+
${creatingAgentsSkill}
|
|
193
|
+
|
|
194
|
+
## Save Instructions
|
|
195
|
+
|
|
196
|
+
Once the user approves the agent design, save it:
|
|
197
|
+
1. Write the markdown file to: ${agentsDir}/${agentName}.md
|
|
198
|
+
- The file MUST have YAML frontmatter (name, description, focus) and a prompt body ending with {output_instructions}
|
|
199
|
+
2. Update config at: ${configPath}
|
|
200
|
+
- Add entry: { name: "${agentName}", enabled: true, data: "${agentName}.md", model: ${model ? `"${model}"` : "null"} }
|
|
201
|
+
|
|
202
|
+
Use the \`writeAgentFile\` and \`addAgentToConfig\` functions from \`src/review/agent-loader.ts\` if you have tool access, or write the files directly.
|
|
203
|
+
|
|
204
|
+
Start by asking the user about the goal/focus of their "${agentName}" agent.`;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ── Command Entry Point ────────────────────────────────────────
|
|
208
|
+
|
|
209
|
+
export function handleAgents(platform: Platform, ctx: any, args?: string): void {
|
|
210
|
+
if (args?.trim() === "create") {
|
|
211
|
+
runAgentCreateFlow(platform, ctx).catch((err: Error) => {
|
|
212
|
+
ctx.ui.notify(`Agent creation error: ${err.message}`, "error");
|
|
213
|
+
});
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Solo invocation: show dashboard
|
|
218
|
+
showAgentsDashboard(platform, ctx).catch((err: Error) => {
|
|
219
|
+
ctx.ui.notify(`Error loading agents: ${err.message}`, "error");
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async function showAgentsDashboard(platform: Platform, ctx: any): Promise<void> {
|
|
224
|
+
const result = await loadMergedReviewAgents(platform.paths, ctx.cwd);
|
|
225
|
+
const dashboard = buildAgentDashboard(result.agents);
|
|
226
|
+
ctx.ui.notify(dashboard, "info");
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// ── Registration ───────────────────────────────────────────────
|
|
230
|
+
|
|
231
|
+
const SUBCOMMANDS = [
|
|
232
|
+
{ name: "create", description: "Create a new review agent" },
|
|
233
|
+
] as const;
|
|
234
|
+
|
|
235
|
+
export function registerAgentsCommand(platform: Platform): void {
|
|
236
|
+
platform.registerCommand("supi:agents", {
|
|
237
|
+
description: "List and manage review agents",
|
|
238
|
+
getArgumentCompletions(prefix: string) {
|
|
239
|
+
const lower = prefix.toLowerCase();
|
|
240
|
+
const matches = SUBCOMMANDS
|
|
241
|
+
.filter((s) => s.name.startsWith(lower))
|
|
242
|
+
.map((s) => ({ value: `${s.name} `, label: s.name, description: s.description }));
|
|
243
|
+
return matches.length > 0 ? matches : null;
|
|
244
|
+
},
|
|
245
|
+
async handler(args: string | undefined, ctx: any) {
|
|
246
|
+
handleAgents(platform, ctx, args);
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
}
|