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/bin/ctx-mode-wrapper.mjs
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Wrapper for context-mode MCP server that preserves the project directory.
|
|
3
|
-
// OMP launches MCP servers with cwd set to the project directory, but
|
|
4
|
-
// context-mode's start.mjs immediately does process.chdir(__dirname),
|
|
5
|
-
// losing the project path. This wrapper captures cwd first.
|
|
6
|
-
//
|
|
7
|
-
// Setting CLAUDE_PROJECT_DIR causes start.mjs to also write a CLAUDE.md
|
|
8
|
-
// in the project root. This is harmless (OMP doesn't read it) but the
|
|
9
|
-
// user should gitignore it. We also write .omp/APPEND_SYSTEM.md with routing
|
|
10
|
-
// rules since that's what OMP actually loads as system prompt.
|
|
11
|
-
|
|
12
|
-
import { resolve, join, dirname } from "node:path";
|
|
13
|
-
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
14
|
-
import { fileURLToPath } from "node:url";
|
|
15
|
-
import { homedir } from "node:os";
|
|
16
|
-
|
|
17
|
-
const __wrapperDir = dirname(fileURLToPath(import.meta.url));
|
|
18
|
-
|
|
19
|
-
// Capture the real project directory BEFORE start.mjs clobbers it
|
|
20
|
-
const projectDir = resolve(process.cwd());
|
|
21
|
-
process.env.CLAUDE_PROJECT_DIR = projectDir;
|
|
22
|
-
|
|
23
|
-
// Note: context-mode uses per-PID ephemeral FTS5 databases that are cleaned
|
|
24
|
-
// up on process exit. Within a session, indexed content persists and ctx_search
|
|
25
|
-
// can query it. Across sessions, content must be re-indexed.
|
|
26
|
-
// The SKILL.md routing rules emphasize using ctx_search for follow-ups.
|
|
27
|
-
|
|
28
|
-
// Resolve start.mjs path from the first CLI argument
|
|
29
|
-
const startMjs = process.argv[2];
|
|
30
|
-
if (!startMjs) {
|
|
31
|
-
process.stderr.write("ctx-mode-wrapper: missing start.mjs path argument\n");
|
|
32
|
-
process.exit(1);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Write .omp/APPEND_SYSTEM.md with routing rules (idempotent — only if marker absent)
|
|
36
|
-
const ROUTING_MARKER = "# context-mode — MANDATORY routing rules";
|
|
37
|
-
try {
|
|
38
|
-
// Find SKILL.md from multiple possible locations
|
|
39
|
-
const skillCandidates = [
|
|
40
|
-
join(homedir(), ".omp", "agent", "skills", "context-mode", "SKILL.md"),
|
|
41
|
-
join(__wrapperDir, "..", "skills", "context-mode", "SKILL.md"),
|
|
42
|
-
];
|
|
43
|
-
let skillContent = null;
|
|
44
|
-
for (const candidate of skillCandidates) {
|
|
45
|
-
try { skillContent = readFileSync(candidate, "utf-8"); break; } catch { /* next */ }
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (skillContent && skillContent.includes(ROUTING_MARKER)) {
|
|
49
|
-
const ompDir = join(projectDir, ".omp");
|
|
50
|
-
const systemMdPath = join(ompDir, "APPEND_SYSTEM.md");
|
|
51
|
-
|
|
52
|
-
if (!existsSync(ompDir)) mkdirSync(ompDir, { recursive: true });
|
|
53
|
-
|
|
54
|
-
if (!existsSync(systemMdPath)) {
|
|
55
|
-
writeFileSync(systemMdPath, skillContent);
|
|
56
|
-
} else {
|
|
57
|
-
const existing = readFileSync(systemMdPath, "utf-8");
|
|
58
|
-
if (!existing.includes(ROUTING_MARKER)) {
|
|
59
|
-
writeFileSync(systemMdPath, existing.trimEnd() + "\n\n" + skillContent);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
} catch { /* best effort — don't block server startup */ }
|
|
64
|
-
|
|
65
|
-
// Dynamic import to run start.mjs (server starts here)
|
|
66
|
-
await import(startMjs);
|
package/src/config/profiles.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
// src/config/profiles.ts
|
|
2
|
-
import * as fs from "node:fs";
|
|
3
|
-
import * as path from "node:path";
|
|
4
|
-
import type { Profile, SupipowersConfig } from "../types.js";
|
|
5
|
-
import type { PlatformPaths } from "../platform/types.js";
|
|
6
|
-
import { BUILTIN_PROFILES } from "./defaults.js";
|
|
7
|
-
|
|
8
|
-
function getProfilesDir(paths: PlatformPaths, cwd: string): string {
|
|
9
|
-
return paths.project(cwd, "profiles");
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/** Load a profile by name. Checks project dir first, then built-ins. */
|
|
13
|
-
export function loadProfile(paths: PlatformPaths, cwd: string, name: string): Profile | null {
|
|
14
|
-
// Check project-level custom profiles
|
|
15
|
-
const customPath = path.join(getProfilesDir(paths, cwd), `${name}.json`);
|
|
16
|
-
if (fs.existsSync(customPath)) {
|
|
17
|
-
try {
|
|
18
|
-
return JSON.parse(fs.readFileSync(customPath, "utf-8")) as Profile;
|
|
19
|
-
} catch {
|
|
20
|
-
// fall through to built-in
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return BUILTIN_PROFILES[name] ?? null;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/** Resolve the active profile from config, with optional override */
|
|
27
|
-
export function resolveProfile(
|
|
28
|
-
paths: PlatformPaths,
|
|
29
|
-
cwd: string,
|
|
30
|
-
config: SupipowersConfig,
|
|
31
|
-
override?: string
|
|
32
|
-
): Profile {
|
|
33
|
-
const name = override ?? config.defaultProfile;
|
|
34
|
-
const profile = loadProfile(paths, cwd, name);
|
|
35
|
-
if (!profile) {
|
|
36
|
-
// Fallback to thorough if configured profile doesn't exist
|
|
37
|
-
return BUILTIN_PROFILES["thorough"];
|
|
38
|
-
}
|
|
39
|
-
return profile;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** List all available profiles (built-in + custom) */
|
|
43
|
-
export function listProfiles(paths: PlatformPaths, cwd: string): string[] {
|
|
44
|
-
const names = new Set(Object.keys(BUILTIN_PROFILES));
|
|
45
|
-
const dir = getProfilesDir(paths, cwd);
|
|
46
|
-
if (fs.existsSync(dir)) {
|
|
47
|
-
for (const file of fs.readdirSync(dir)) {
|
|
48
|
-
if (file.endsWith(".json")) {
|
|
49
|
-
names.add(file.replace(".json", ""));
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return [...names].sort();
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Save a custom profile */
|
|
57
|
-
export function saveProfile(paths: PlatformPaths, cwd: string, profile: Profile): void {
|
|
58
|
-
const dir = getProfilesDir(paths, cwd);
|
|
59
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
60
|
-
fs.writeFileSync(
|
|
61
|
-
path.join(dir, `${profile.name}.json`),
|
|
62
|
-
JSON.stringify(profile, null, 2) + "\n"
|
|
63
|
-
);
|
|
64
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// src/context-mode/installer.ts
|
|
2
|
-
import { detectContextMode } from "./detector.js";
|
|
3
|
-
import { DEPENDENCIES, installDep } from "../deps/registry.js";
|
|
4
|
-
import type { ExecResult } from "../platform/types.js";
|
|
5
|
-
|
|
6
|
-
type ExecFn = (cmd: string, args: string[]) => Promise<ExecResult>;
|
|
7
|
-
|
|
8
|
-
/** Installation status */
|
|
9
|
-
export interface ContextModeInstallStatus {
|
|
10
|
-
cliInstalled: boolean;
|
|
11
|
-
mcpConfigured: boolean;
|
|
12
|
-
toolsAvailable: boolean;
|
|
13
|
-
version: string | null;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** Check context-mode installation status */
|
|
17
|
-
export async function checkInstallation(
|
|
18
|
-
exec: ExecFn,
|
|
19
|
-
activeTools: string[],
|
|
20
|
-
): Promise<ContextModeInstallStatus> {
|
|
21
|
-
const status = detectContextMode(activeTools);
|
|
22
|
-
const dep = DEPENDENCIES.find((d) => d.binary === "context-mode");
|
|
23
|
-
const check = dep ? await dep.checkFn(exec) : { installed: false };
|
|
24
|
-
|
|
25
|
-
return {
|
|
26
|
-
cliInstalled: check.installed,
|
|
27
|
-
mcpConfigured: status.available,
|
|
28
|
-
toolsAvailable: status.available,
|
|
29
|
-
version: check.version ?? null,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** Install context-mode globally */
|
|
34
|
-
export async function installContextMode(
|
|
35
|
-
exec: ExecFn,
|
|
36
|
-
): Promise<{ success: boolean; error?: string }> {
|
|
37
|
-
return installDep(exec, "context-mode");
|
|
38
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { GateResult } from "../types.js";
|
|
2
|
-
|
|
3
|
-
export function buildAiReviewPrompt(
|
|
4
|
-
changedFiles: string[],
|
|
5
|
-
depth: "quick" | "deep"
|
|
6
|
-
): string {
|
|
7
|
-
const depthInstructions =
|
|
8
|
-
depth === "quick"
|
|
9
|
-
? "Do a quick scan: check for obvious bugs, security issues, and naming problems."
|
|
10
|
-
: [
|
|
11
|
-
"Do a thorough review covering:",
|
|
12
|
-
"- Correctness and edge cases",
|
|
13
|
-
"- Security vulnerabilities (OWASP top 10)",
|
|
14
|
-
"- Performance concerns",
|
|
15
|
-
"- Code clarity and maintainability",
|
|
16
|
-
"- Error handling completeness",
|
|
17
|
-
"- Test coverage gaps",
|
|
18
|
-
].join("\n");
|
|
19
|
-
|
|
20
|
-
return [
|
|
21
|
-
"Review the following changed files:",
|
|
22
|
-
...changedFiles.map((f) => `- ${f}`),
|
|
23
|
-
"",
|
|
24
|
-
depthInstructions,
|
|
25
|
-
"",
|
|
26
|
-
"For each issue found, report:",
|
|
27
|
-
"- Severity: error | warning | info",
|
|
28
|
-
"- File and line number",
|
|
29
|
-
"- Description of the issue",
|
|
30
|
-
"- Suggested fix",
|
|
31
|
-
].join("\n");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function createAiReviewResult(
|
|
35
|
-
issues: { severity: "error" | "warning" | "info"; message: string; file?: string; line?: number }[]
|
|
36
|
-
): GateResult {
|
|
37
|
-
const hasErrors = issues.some((i) => i.severity === "error");
|
|
38
|
-
return {
|
|
39
|
-
gate: "ai-review",
|
|
40
|
-
passed: !hasErrors,
|
|
41
|
-
issues,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import type { Profile, GateResult, ReviewReport } from "../types.js";
|
|
2
|
-
import { buildLspGatePrompt } from "./lsp-gate.js";
|
|
3
|
-
import { buildAiReviewPrompt } from "./ai-review-gate.js";
|
|
4
|
-
import { buildTestGatePrompt } from "./test-gate.js";
|
|
5
|
-
|
|
6
|
-
export interface GateRunnerOptions {
|
|
7
|
-
profile: Profile;
|
|
8
|
-
changedFiles: string[];
|
|
9
|
-
testCommand: string | null;
|
|
10
|
-
lspAvailable: boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function getActiveGates(profile: Profile, lspAvailable: boolean): string[] {
|
|
14
|
-
const gates: string[] = [];
|
|
15
|
-
if (profile.gates.lspDiagnostics && lspAvailable) gates.push("lsp-diagnostics");
|
|
16
|
-
if (profile.gates.aiReview.enabled) gates.push("ai-review");
|
|
17
|
-
if (profile.gates.codeQuality) gates.push("code-quality");
|
|
18
|
-
if (profile.gates.testSuite) gates.push("test-suite");
|
|
19
|
-
if (profile.gates.e2e) gates.push("e2e");
|
|
20
|
-
return gates;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function buildReviewPrompt(options: GateRunnerOptions): string {
|
|
24
|
-
const { profile, changedFiles, testCommand, lspAvailable } = options;
|
|
25
|
-
const sections: string[] = [
|
|
26
|
-
"# Code Review",
|
|
27
|
-
"",
|
|
28
|
-
`Profile: ${profile.name}`,
|
|
29
|
-
"",
|
|
30
|
-
"Run the following quality checks and report results for each:",
|
|
31
|
-
"",
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
if (profile.gates.lspDiagnostics && lspAvailable) {
|
|
35
|
-
sections.push("## 1. LSP Diagnostics", buildLspGatePrompt(changedFiles), "");
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (profile.gates.aiReview.enabled) {
|
|
39
|
-
sections.push(
|
|
40
|
-
"## 2. Code Review",
|
|
41
|
-
buildAiReviewPrompt(changedFiles, profile.gates.aiReview.depth),
|
|
42
|
-
""
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (profile.gates.testSuite) {
|
|
47
|
-
sections.push(
|
|
48
|
-
"## 3. Test Suite",
|
|
49
|
-
buildTestGatePrompt(testCommand, false),
|
|
50
|
-
""
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return sections.join("\n");
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function createReviewReport(
|
|
58
|
-
profile: string,
|
|
59
|
-
gates: GateResult[]
|
|
60
|
-
): ReviewReport {
|
|
61
|
-
return {
|
|
62
|
-
profile,
|
|
63
|
-
timestamp: new Date().toISOString(),
|
|
64
|
-
gates,
|
|
65
|
-
passed: gates.every((g) => g.passed),
|
|
66
|
-
};
|
|
67
|
-
}
|
package/src/quality/lsp-gate.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { GateResult } from "../types.js";
|
|
2
|
-
|
|
3
|
-
export function buildLspGatePrompt(changedFiles: string[]): string {
|
|
4
|
-
return [
|
|
5
|
-
"Run LSP diagnostics on these files and report results:",
|
|
6
|
-
...changedFiles.map((f) => `- ${f}`),
|
|
7
|
-
"",
|
|
8
|
-
'Use the lsp tool with action "diagnostics" for each file.',
|
|
9
|
-
"Summarize: total errors, total warnings, and list each issue.",
|
|
10
|
-
].join("\n");
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function createLspGateResult(
|
|
14
|
-
hasErrors: boolean,
|
|
15
|
-
errorCount: number,
|
|
16
|
-
warningCount: number,
|
|
17
|
-
issues: { severity: "error" | "warning" | "info"; message: string; file?: string; line?: number }[]
|
|
18
|
-
): GateResult {
|
|
19
|
-
return {
|
|
20
|
-
gate: "lsp-diagnostics",
|
|
21
|
-
passed: !hasErrors,
|
|
22
|
-
issues,
|
|
23
|
-
};
|
|
24
|
-
}
|
package/src/quality/test-gate.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import type { GateResult } from "../types.js";
|
|
2
|
-
|
|
3
|
-
export function buildTestGatePrompt(
|
|
4
|
-
testCommand: string | null,
|
|
5
|
-
changedOnly: boolean,
|
|
6
|
-
changedFiles?: string[]
|
|
7
|
-
): string {
|
|
8
|
-
const cmd = testCommand ?? "npm test";
|
|
9
|
-
const scope = changedOnly && changedFiles
|
|
10
|
-
? `Only run tests related to: ${changedFiles.join(", ")}`
|
|
11
|
-
: "Run the full test suite.";
|
|
12
|
-
|
|
13
|
-
return [
|
|
14
|
-
scope,
|
|
15
|
-
"",
|
|
16
|
-
`Command: ${cmd}`,
|
|
17
|
-
"",
|
|
18
|
-
"Report the results:",
|
|
19
|
-
"- Total tests, passed, failed, skipped",
|
|
20
|
-
"- For each failure: test name, file, error message",
|
|
21
|
-
].join("\n");
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function createTestGateResult(
|
|
25
|
-
passed: boolean,
|
|
26
|
-
totalTests: number,
|
|
27
|
-
failedTests: number,
|
|
28
|
-
failures: { message: string; file?: string }[]
|
|
29
|
-
): GateResult {
|
|
30
|
-
return {
|
|
31
|
-
gate: "test-suite",
|
|
32
|
-
passed,
|
|
33
|
-
issues: failures.map((f) => ({
|
|
34
|
-
severity: "error" as const,
|
|
35
|
-
message: `Test failed: ${f.message}`,
|
|
36
|
-
file: f.file,
|
|
37
|
-
})),
|
|
38
|
-
};
|
|
39
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Start the visual companion server and output connection info
|
|
3
|
-
# Usage: start-server.sh [--host <bind-host>] [--url-host <display-host>] [--foreground]
|
|
4
|
-
|
|
5
|
-
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
-
|
|
7
|
-
# Parse arguments
|
|
8
|
-
FOREGROUND="false"
|
|
9
|
-
BIND_HOST="127.0.0.1"
|
|
10
|
-
URL_HOST=""
|
|
11
|
-
while [[ $# -gt 0 ]]; do
|
|
12
|
-
case "$1" in
|
|
13
|
-
--host)
|
|
14
|
-
BIND_HOST="$2"
|
|
15
|
-
shift 2
|
|
16
|
-
;;
|
|
17
|
-
--url-host)
|
|
18
|
-
URL_HOST="$2"
|
|
19
|
-
shift 2
|
|
20
|
-
;;
|
|
21
|
-
--foreground|--no-daemon)
|
|
22
|
-
FOREGROUND="true"
|
|
23
|
-
shift
|
|
24
|
-
;;
|
|
25
|
-
*)
|
|
26
|
-
echo "{\"error\": \"Unknown argument: $1\"}"
|
|
27
|
-
exit 1
|
|
28
|
-
;;
|
|
29
|
-
esac
|
|
30
|
-
done
|
|
31
|
-
|
|
32
|
-
if [[ -z "$URL_HOST" ]]; then
|
|
33
|
-
if [[ "$BIND_HOST" == "127.0.0.1" || "$BIND_HOST" == "localhost" ]]; then
|
|
34
|
-
URL_HOST="localhost"
|
|
35
|
-
else
|
|
36
|
-
URL_HOST="$BIND_HOST"
|
|
37
|
-
fi
|
|
38
|
-
fi
|
|
39
|
-
|
|
40
|
-
# Session dir must be set via environment
|
|
41
|
-
SCREEN_DIR="${SUPI_VISUAL_DIR}"
|
|
42
|
-
if [[ -z "$SCREEN_DIR" ]]; then
|
|
43
|
-
echo '{"error": "SUPI_VISUAL_DIR environment variable not set"}'
|
|
44
|
-
exit 1
|
|
45
|
-
fi
|
|
46
|
-
|
|
47
|
-
PID_FILE="${SCREEN_DIR}/.server.pid"
|
|
48
|
-
LOG_FILE="${SCREEN_DIR}/.server.log"
|
|
49
|
-
|
|
50
|
-
# Create session directory if needed
|
|
51
|
-
mkdir -p "$SCREEN_DIR"
|
|
52
|
-
|
|
53
|
-
# Kill any existing server for this session
|
|
54
|
-
if [[ -f "$PID_FILE" ]]; then
|
|
55
|
-
old_pid=$(cat "$PID_FILE")
|
|
56
|
-
kill "$old_pid" 2>/dev/null
|
|
57
|
-
rm -f "$PID_FILE"
|
|
58
|
-
fi
|
|
59
|
-
|
|
60
|
-
cd "$SCRIPT_DIR"
|
|
61
|
-
|
|
62
|
-
# Foreground mode
|
|
63
|
-
if [[ "$FOREGROUND" == "true" ]]; then
|
|
64
|
-
echo "$$" > "$PID_FILE"
|
|
65
|
-
env SUPI_VISUAL_DIR="$SCREEN_DIR" SUPI_VISUAL_HOST="$BIND_HOST" SUPI_VISUAL_URL_HOST="$URL_HOST" node index.js
|
|
66
|
-
exit $?
|
|
67
|
-
fi
|
|
68
|
-
|
|
69
|
-
# Background mode
|
|
70
|
-
nohup env SUPI_VISUAL_DIR="$SCREEN_DIR" SUPI_VISUAL_HOST="$BIND_HOST" SUPI_VISUAL_URL_HOST="$URL_HOST" node index.js > "$LOG_FILE" 2>&1 &
|
|
71
|
-
SERVER_PID=$!
|
|
72
|
-
disown "$SERVER_PID" 2>/dev/null
|
|
73
|
-
echo "$SERVER_PID" > "$PID_FILE"
|
|
74
|
-
|
|
75
|
-
# Wait for server-started message
|
|
76
|
-
for i in {1..50}; do
|
|
77
|
-
if grep -q "server-started" "$LOG_FILE" 2>/dev/null; then
|
|
78
|
-
# Verify server is still alive
|
|
79
|
-
alive="true"
|
|
80
|
-
for _ in {1..20}; do
|
|
81
|
-
if ! kill -0 "$SERVER_PID" 2>/dev/null; then
|
|
82
|
-
alive="false"
|
|
83
|
-
break
|
|
84
|
-
fi
|
|
85
|
-
sleep 0.1
|
|
86
|
-
done
|
|
87
|
-
if [[ "$alive" != "true" ]]; then
|
|
88
|
-
echo "{\"error\": \"Server started but was killed. Retry with --foreground\"}"
|
|
89
|
-
exit 1
|
|
90
|
-
fi
|
|
91
|
-
grep "server-started" "$LOG_FILE" | head -1
|
|
92
|
-
exit 0
|
|
93
|
-
fi
|
|
94
|
-
sleep 0.1
|
|
95
|
-
done
|
|
96
|
-
|
|
97
|
-
echo '{"error": "Server failed to start within 5 seconds"}'
|
|
98
|
-
exit 1
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Stop the visual companion server
|
|
3
|
-
# Usage: stop-server.sh <screen_dir>
|
|
4
|
-
|
|
5
|
-
SCREEN_DIR="$1"
|
|
6
|
-
|
|
7
|
-
if [[ -z "$SCREEN_DIR" ]]; then
|
|
8
|
-
echo '{"error": "Usage: stop-server.sh <screen_dir>"}'
|
|
9
|
-
exit 1
|
|
10
|
-
fi
|
|
11
|
-
|
|
12
|
-
PID_FILE="${SCREEN_DIR}/.server.pid"
|
|
13
|
-
|
|
14
|
-
if [[ -f "$PID_FILE" ]]; then
|
|
15
|
-
pid=$(cat "$PID_FILE")
|
|
16
|
-
kill "$pid" 2>/dev/null
|
|
17
|
-
rm -f "$PID_FILE" "${SCREEN_DIR}/.server.log"
|
|
18
|
-
echo '{"status": "stopped"}'
|
|
19
|
-
else
|
|
20
|
-
echo '{"status": "not_running"}'
|
|
21
|
-
fi
|