git-vibe-setup 2.0.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 ADDED
@@ -0,0 +1,11 @@
1
+ # git-vibe-setup
2
+
3
+ Local initializer for GitVibe consumer repositories.
4
+
5
+ ```bash
6
+ npx --package=git-vibe-setup git-vibe-setup
7
+ ```
8
+
9
+ The command writes `.github` and `.git-vibe` starter files, pins reusable
10
+ workflow refs to the latest stable `markhuangai/git-vibe` release, and fails
11
+ before writing if release lookup or target-file validation fails.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ interface SetupCliRuntime {
3
+ cwd?: string;
4
+ error?: (message: string) => void;
5
+ fetchImpl?: typeof fetch;
6
+ log?: (message: string) => void;
7
+ repositoryRoot?: string;
8
+ }
9
+ export declare function runSetup(runtime?: SetupCliRuntime): Promise<void>;
10
+ export declare function setupCli(runtime?: SetupCliRuntime): Promise<number>;
11
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+ import { resolve } from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { fileURLToPath } from "node:url";
5
+ import { blockingInstallPaths, buildInstallFiles, existingFilesError, installFiles, } from "./install.js";
6
+ import { renderManualSetupInstructions } from "./instructions.js";
7
+ import { latestStableReleaseTag } from "./releases.js";
8
+ export async function runSetup(runtime = {}) {
9
+ const cwd = runtime.cwd || process.cwd();
10
+ const repositoryRoot = runtime.repositoryRoot || packageRoot();
11
+ const releaseTag = await latestStableReleaseTag(runtime.fetchImpl || fetch);
12
+ const files = buildInstallFiles({ cwd, releaseTag, repositoryRoot });
13
+ const blockingPaths = blockingInstallPaths(files);
14
+ if (blockingPaths.length > 0)
15
+ throw existingFilesError(blockingPaths, cwd);
16
+ installFiles(files);
17
+ (runtime.log || console.log)(renderManualSetupInstructions(releaseTag));
18
+ }
19
+ export async function setupCli(runtime = {}) {
20
+ try {
21
+ await runSetup(runtime);
22
+ return 0;
23
+ }
24
+ catch (error) {
25
+ const message = error instanceof Error ? error.message : String(error);
26
+ (runtime.error || console.error)(message);
27
+ return 1;
28
+ }
29
+ }
30
+ function packageRoot() {
31
+ return fileURLToPath(new URL("../", import.meta.url));
32
+ }
33
+ /* c8 ignore start */
34
+ if (isDirectRun(import.meta.url)) {
35
+ const exitCode = await setupCli();
36
+ process.exitCode = exitCode;
37
+ }
38
+ /* c8 ignore stop */
39
+ function isDirectRun(moduleUrl, entrypoint = process.argv[1]) {
40
+ return Boolean(entrypoint && moduleUrl === pathToFileURL(resolve(entrypoint)).href);
41
+ }
@@ -0,0 +1,14 @@
1
+ export interface InstallFile {
2
+ content: string;
3
+ sourcePath: string;
4
+ targetPath: string;
5
+ }
6
+ export declare function buildInstallFiles(options: {
7
+ cwd: string;
8
+ releaseTag: string;
9
+ repositoryRoot: string;
10
+ }): InstallFile[];
11
+ export declare function blockingInstallPaths(files: InstallFile[]): string[];
12
+ export declare function installFiles(files: InstallFile[]): void;
13
+ export declare function existingFilesError(paths: string[], cwd: string): Error;
14
+ export declare function pinWorkflowReleaseRefs(content: string, releaseTag: string): string;
@@ -0,0 +1,94 @@
1
+ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
+ import { dirname, join, relative } from "node:path";
3
+ export function buildInstallFiles(options) {
4
+ return installSources(options.repositoryRoot).flatMap((source) => listRelativeFiles(source.sourceDirectory).map((relativePath) => {
5
+ const sourcePath = join(source.sourceDirectory, relativePath);
6
+ const targetPath = join(options.cwd, source.targetDirectory, relativePath);
7
+ const content = readFileSync(sourcePath, "utf8");
8
+ return {
9
+ content: pinWorkflowReleaseRefs(content, options.releaseTag),
10
+ sourcePath,
11
+ targetPath,
12
+ };
13
+ }));
14
+ }
15
+ export function blockingInstallPaths(files) {
16
+ return files
17
+ .map((file) => file.targetPath)
18
+ .filter((targetPath) => existsSync(targetPath))
19
+ .sort();
20
+ }
21
+ export function installFiles(files) {
22
+ const createdDirectories = [];
23
+ const createdFiles = [];
24
+ try {
25
+ for (const file of files) {
26
+ ensureDirectory(dirname(file.targetPath), createdDirectories);
27
+ writeFileSync(file.targetPath, file.content, { flag: "wx" });
28
+ createdFiles.push(file.targetPath);
29
+ }
30
+ }
31
+ catch (error) {
32
+ rollbackInstall(createdFiles, createdDirectories);
33
+ throw error;
34
+ }
35
+ }
36
+ export function existingFilesError(paths, cwd) {
37
+ const listed = paths.map((path) => `- ${relative(cwd, path) || path}`).join("\n");
38
+ return new Error(`git-vibe-setup found existing GitVibe files and did not overwrite them:\n${listed}\nRemove the listed files before running setup again.`);
39
+ }
40
+ export function pinWorkflowReleaseRefs(content, releaseTag) {
41
+ return content.replace(/(uses:\s*markhuangai\/git-vibe\/\.github\/workflows\/[^\s@]+)@[^\s]+/g, (_match, workflowReference) => `${workflowReference}@${releaseTag}`);
42
+ }
43
+ function installSources(repositoryRoot) {
44
+ return [
45
+ {
46
+ sourceDirectory: join(repositoryRoot, "templates", ".github"),
47
+ targetDirectory: ".github",
48
+ },
49
+ {
50
+ sourceDirectory: join(repositoryRoot, "templates", ".git-vibe"),
51
+ targetDirectory: ".git-vibe",
52
+ },
53
+ ];
54
+ }
55
+ function listRelativeFiles(directory) {
56
+ return readdirSync(directory, { withFileTypes: true })
57
+ .flatMap((entry) => {
58
+ const entryPath = join(directory, entry.name);
59
+ if (entry.isDirectory()) {
60
+ return listRelativeFiles(entryPath).map((path) => join(entry.name, path));
61
+ }
62
+ /* c8 ignore next */
63
+ return entry.isFile() ? [entry.name] : [];
64
+ })
65
+ .sort();
66
+ }
67
+ function ensureDirectory(directory, createdDirectories) {
68
+ const missing = missingDirectories(directory);
69
+ for (const path of missing) {
70
+ mkdirSync(path);
71
+ createdDirectories.push(path);
72
+ }
73
+ }
74
+ function missingDirectories(directory) {
75
+ const missing = [];
76
+ let current = directory;
77
+ while (!existsSync(current)) {
78
+ missing.push(current);
79
+ const parent = dirname(current);
80
+ /* c8 ignore next */
81
+ if (parent === current)
82
+ break;
83
+ current = parent;
84
+ }
85
+ return missing.reverse();
86
+ }
87
+ function rollbackInstall(createdFiles, createdDirectories) {
88
+ for (const file of [...createdFiles].reverse()) {
89
+ rmSync(file, { force: true });
90
+ }
91
+ for (const directory of [...createdDirectories].reverse()) {
92
+ rmSync(directory, { force: true, recursive: false });
93
+ }
94
+ }
@@ -0,0 +1 @@
1
+ export declare function renderManualSetupInstructions(releaseTag: string): string;
@@ -0,0 +1,25 @@
1
+ const requiredSecrets = [
2
+ ["GITVIBE_AI_ENV_JSON", "JSON env bundle for AI provider config and CLI auth."],
3
+ ["GITVIBE_GITHUB_TOKEN", "Fine-grained PAT for GitVibe workflow and server writes."],
4
+ ["WEBHOOK_SECRET", "Webhook shared secret mapped to GITHUB_WEBHOOK_SECRET in deployment."],
5
+ ];
6
+ const usefulVariables = [
7
+ "GITVIBE_BASE_BRANCH",
8
+ "GITVIBE_DISCUSSION_CATEGORY",
9
+ "GITVIBE_RUNNER",
10
+ "GITVIBE_LOG_LEVEL",
11
+ ];
12
+ export function renderManualSetupInstructions(releaseTag) {
13
+ const lines = [
14
+ `GitVibe starter files installed with reusable workflows pinned to ${releaseTag}.`,
15
+ "",
16
+ "Configure these GitHub secrets manually before running the workflows:",
17
+ ...requiredSecrets.map(([name, description]) => `- ${name}: ${description}`),
18
+ "",
19
+ "Optional repository variables:",
20
+ ...usefulVariables.map((name) => `- ${name}`),
21
+ "",
22
+ `Reference bundle shape: https://github.com/markhuangai/git-vibe/blob/${releaseTag}/examples/consumer/GITVIBE_AI_ENV_JSON.example.json`,
23
+ ];
24
+ return lines.join("\n");
25
+ }
@@ -0,0 +1,11 @@
1
+ export interface GitHubRelease {
2
+ created_at?: string;
3
+ draft?: boolean;
4
+ prerelease?: boolean;
5
+ published_at?: string;
6
+ tag_name?: string;
7
+ }
8
+ export declare class ReleaseLookupError extends Error {
9
+ }
10
+ export declare function latestStableReleaseTag(fetchImpl?: typeof fetch): Promise<string>;
11
+ export declare function selectLatestStableRelease(releases: GitHubRelease[]): GitHubRelease | undefined;
@@ -0,0 +1,65 @@
1
+ export class ReleaseLookupError extends Error {
2
+ }
3
+ const releasesUrl = "https://api.github.com/repos/markhuangai/git-vibe/releases";
4
+ const releasesPerPage = 100;
5
+ export async function latestStableReleaseTag(fetchImpl = fetch) {
6
+ const releases = await fetchReleases(fetchImpl);
7
+ const release = selectLatestStableRelease(releases);
8
+ if (!release?.tag_name) {
9
+ throw new ReleaseLookupError("git-vibe-setup could not check the latest GitVibe update because no stable release is available. No files were written.");
10
+ }
11
+ return release.tag_name;
12
+ }
13
+ export function selectLatestStableRelease(releases) {
14
+ return releases
15
+ .filter((release) => !release.draft && !release.prerelease && release.tag_name)
16
+ .sort(compareReleaseFreshness)[0];
17
+ }
18
+ async function fetchReleases(fetchImpl) {
19
+ const releases = [];
20
+ for (let page = 1;; page += 1) {
21
+ const data = await fetchReleasePage(fetchImpl, page);
22
+ releases.push(...data);
23
+ if (data.length < releasesPerPage)
24
+ return releases;
25
+ }
26
+ }
27
+ async function fetchReleasePage(fetchImpl, page) {
28
+ let response;
29
+ try {
30
+ response = await fetchImpl(releasePageUrl(page), {
31
+ headers: {
32
+ accept: "application/vnd.github+json",
33
+ "user-agent": "git-vibe-setup",
34
+ "x-github-api-version": "2022-11-28",
35
+ },
36
+ });
37
+ }
38
+ catch {
39
+ throw unavailableReleaseError();
40
+ }
41
+ if (!response.ok)
42
+ throw unavailableReleaseError();
43
+ try {
44
+ const data = await response.json();
45
+ return Array.isArray(data) ? data : [];
46
+ }
47
+ catch {
48
+ throw unavailableReleaseError();
49
+ }
50
+ }
51
+ function releasePageUrl(page) {
52
+ const url = new URL(releasesUrl);
53
+ url.searchParams.set("page", String(page));
54
+ url.searchParams.set("per_page", String(releasesPerPage));
55
+ return url.toString();
56
+ }
57
+ function compareReleaseFreshness(left, right) {
58
+ return releaseTime(right) - releaseTime(left);
59
+ }
60
+ function releaseTime(release) {
61
+ return Date.parse(release.published_at || release.created_at || "") || 0;
62
+ }
63
+ function unavailableReleaseError() {
64
+ return new ReleaseLookupError("git-vibe-setup could not check the latest GitVibe update because the GitHub release service is unavailable. No files were written.");
65
+ }
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "git-vibe-setup",
3
+ "version": "2.0.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "bin": {
7
+ "git-vibe-setup": "./dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "templates",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc --project tsconfig.build.json",
16
+ "check": "prettier --check . && eslint . && corepack pnpm typecheck && corepack pnpm test && corepack pnpm build",
17
+ "test": "vitest run",
18
+ "typecheck": "tsc --project tsconfig.json --noEmit"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "^25.6.0",
22
+ "typescript": "^6.0.3",
23
+ "vitest": "^4.1.5"
24
+ }
25
+ }
@@ -0,0 +1,7 @@
1
+ # Correctness Reviewer
2
+
3
+ Review the stage result for behavioral correctness. Check that conclusions are
4
+ grounded in the GitHub context and repository evidence, and that any required
5
+ next action is specific enough to execute.
6
+
7
+ Return only the current stage schema.
@@ -0,0 +1,7 @@
1
+ # Maintainability Reviewer
2
+
3
+ Review the stage result for implementation clarity, long-term maintenance,
4
+ operability, and fit with existing repository patterns. Prefer small,
5
+ evidence-backed changes over broad redesigns.
6
+
7
+ Return only the current stage schema.
@@ -0,0 +1,7 @@
1
+ # Security Reviewer
2
+
3
+ Review the stage result for token handling, permissions, untrusted input, file
4
+ access, workflow authority, and GitHub write safety. Flag only concrete risks
5
+ that affect the requested work.
6
+
7
+ Return only the current stage schema.
@@ -0,0 +1,105 @@
1
+ # Copy this file to .github/git-vibe.yml in the consumer repository.
2
+
3
+ version: 1
4
+
5
+ branches:
6
+ base: ""
7
+
8
+ runner:
9
+ default: ubuntu-latest
10
+
11
+ github_auth:
12
+ mode: webhook-pat
13
+ # GitHub Actions Secret name. Stores the GitHub write token.
14
+ token_secret: GITVIBE_GITHUB_TOKEN
15
+
16
+ ai:
17
+ default_profile: local_proxy
18
+ profiles:
19
+ local_proxy:
20
+ enabled: true
21
+ adapter: ai-sdk-agentool
22
+ provider:
23
+ type: openai-compatible # openai | anthropic | openai-compatible
24
+ # Model names are configuration, not credentials.
25
+ model: glm-5
26
+ # Keys inside GITVIBE_AI_ENV_JSON.
27
+ base_url:
28
+ from_bundle: GITVIBE_AI_BASE_URL
29
+ api_key:
30
+ from_bundle: GITVIBE_AI_API_KEY
31
+ reasoning:
32
+ effort: high
33
+ generation:
34
+ temperature: 0.2
35
+ max_output_tokens: 6000
36
+ max_steps: 90
37
+ codex_cli:
38
+ enabled: false
39
+ adapter: cli-codex
40
+ # Key inside GITVIBE_AI_ENV_JSON. Stores compact auth.json contents.
41
+ auth_json:
42
+ from_bundle: CODEX_AUTH_JSON
43
+ model: gpt-5.3-codex
44
+ reasoning:
45
+ effort: high
46
+ summary: concise
47
+ claude_code:
48
+ enabled: false
49
+ adapter: cli-claude-code
50
+ # Key inside GITVIBE_AI_ENV_JSON. Stores the Claude Code OAuth access token.
51
+ env:
52
+ CLAUDE_CODE_OAUTH_TOKEN:
53
+ from_bundle: CLAUDE_OAUTH_TOKEN
54
+ model: opus
55
+ reasoning:
56
+ effort: xhigh
57
+ role_groups:
58
+ review_gate:
59
+ synthesizer: local_proxy
60
+ parallel: 2
61
+ roles:
62
+ - role: correctness.md
63
+ profile: local_proxy
64
+ - role: security.md
65
+ profile: local_proxy
66
+ - role: maintainability.md
67
+ profile: local_proxy
68
+ budgets:
69
+ default_timeout_minutes: 60
70
+ implementation_timeout_minutes: 120
71
+ feedback_timeout_minutes: 120
72
+ publish_timeout_minutes: 15
73
+ default_max_turns: 90
74
+ implementation_max_turns: 120
75
+ feedback_max_turns: 120
76
+ stages:
77
+ investigate:
78
+ role_group: review_gate
79
+ validate:
80
+ role_group: review_gate
81
+ decompose:
82
+ profile: local_proxy
83
+ materialize:
84
+ profile: local_proxy
85
+ review-matrix:
86
+ role_group: review_gate
87
+ implement:
88
+ profile: local_proxy
89
+ create-pr:
90
+ profile: local_proxy
91
+ address-pr-feedback:
92
+ profile: local_proxy
93
+
94
+ bug_investigation:
95
+ auto_start_on_new_bug: false
96
+ community_trigger:
97
+ enabled: false
98
+ reaction: "+1"
99
+ threshold: 6
100
+ eligible_labels:
101
+ - git-vibe:bug
102
+ dispatch: investigate
103
+
104
+ tests:
105
+ commands: []
@@ -0,0 +1,34 @@
1
+ name: GitVibe address feedback
2
+ run-name: "[git-vibe][address-feedback]: PR #${{ inputs.pr-number }}"
3
+
4
+ on:
5
+ workflow_dispatch:
6
+ inputs:
7
+ pr-number:
8
+ description: Pull request number with feedback to address.
9
+ required: true
10
+ type: string
11
+ dry-run:
12
+ description: Validate without writing to GitHub.
13
+ required: false
14
+ type: boolean
15
+ default: false
16
+ source-comment:
17
+ description: JSON source comment metadata for replying to command comments.
18
+ required: false
19
+ type: string
20
+ default: ""
21
+
22
+ jobs:
23
+ address-feedback:
24
+ uses: markhuangai/git-vibe/.github/workflows/address-feedback.yml@v2
25
+ with:
26
+ pr-number: ${{ inputs.pr-number }}
27
+ runner: ubuntu-latest
28
+ timeout_minutes: 120
29
+ max_turns: 120
30
+ dry-run: ${{ inputs.dry-run }}
31
+ source-comment: ${{ inputs.source-comment }}
32
+ secrets:
33
+ GITVIBE_GITHUB_TOKEN: ${{ secrets.GITVIBE_GITHUB_TOKEN }}
34
+ GITVIBE_AI_ENV_JSON: ${{ secrets.GITVIBE_AI_ENV_JSON }}
@@ -0,0 +1,34 @@
1
+ name: GitVibe decompose
2
+ run-name: "[git-vibe][decompose]: Discussion #${{ inputs.discussion-number }}"
3
+
4
+ on:
5
+ workflow_dispatch:
6
+ inputs:
7
+ discussion-number:
8
+ description: Discussion number to decompose.
9
+ required: true
10
+ type: string
11
+ dry-run:
12
+ description: Validate without writing to GitHub.
13
+ required: false
14
+ type: boolean
15
+ default: false
16
+ source-comment:
17
+ description: JSON source comment metadata for replying to command comments.
18
+ required: false
19
+ type: string
20
+ default: ""
21
+
22
+ jobs:
23
+ decompose:
24
+ uses: markhuangai/git-vibe/.github/workflows/decompose.yml@v2
25
+ with:
26
+ discussion-number: ${{ inputs.discussion-number }}
27
+ runner: ubuntu-latest
28
+ timeout_minutes: 60
29
+ max_turns: 90
30
+ dry-run: ${{ inputs.dry-run }}
31
+ source-comment: ${{ inputs.source-comment }}
32
+ secrets:
33
+ GITVIBE_GITHUB_TOKEN: ${{ secrets.GITVIBE_GITHUB_TOKEN }}
34
+ GITVIBE_AI_ENV_JSON: ${{ secrets.GITVIBE_AI_ENV_JSON }}
@@ -0,0 +1,39 @@
1
+ name: GitVibe develop
2
+ run-name: "[git-vibe][develop]: Issue #${{ inputs.issue-number }}"
3
+
4
+ on:
5
+ workflow_dispatch:
6
+ inputs:
7
+ issue-number:
8
+ description: Approved implementation issue number.
9
+ required: true
10
+ type: string
11
+ dry-run:
12
+ description: Validate without writing to GitHub.
13
+ required: false
14
+ type: boolean
15
+ default: false
16
+ source-comment:
17
+ description: JSON source comment metadata for replying to command comments.
18
+ required: false
19
+ type: string
20
+ default: ""
21
+
22
+ jobs:
23
+ develop:
24
+ uses: markhuangai/git-vibe/.github/workflows/develop.yml@v2
25
+ with:
26
+ issue-number: ${{ inputs.issue-number }}
27
+ runner: ubuntu-latest
28
+ implementation_timeout_minutes: 120
29
+ review_timeout_minutes: 60
30
+ publish_timeout_minutes: 15
31
+ max_turns: 90
32
+ implementation_max_turns: 120
33
+ validation_repair_attempts: 2
34
+ validation_repair_max_turns: 90
35
+ dry-run: ${{ inputs.dry-run }}
36
+ source-comment: ${{ inputs.source-comment }}
37
+ secrets:
38
+ GITVIBE_GITHUB_TOKEN: ${{ secrets.GITVIBE_GITHUB_TOKEN }}
39
+ GITVIBE_AI_ENV_JSON: ${{ secrets.GITVIBE_AI_ENV_JSON }}
@@ -0,0 +1,34 @@
1
+ name: GitVibe investigate
2
+ run-name: "[git-vibe][investigate]: Issue #${{ inputs.issue-number }}"
3
+
4
+ on:
5
+ workflow_dispatch:
6
+ inputs:
7
+ issue-number:
8
+ description: Issue number to investigate.
9
+ required: true
10
+ type: string
11
+ dry-run:
12
+ description: Validate without writing to GitHub.
13
+ required: false
14
+ type: boolean
15
+ default: false
16
+ source-comment:
17
+ description: JSON source comment metadata for replying to command comments.
18
+ required: false
19
+ type: string
20
+ default: ""
21
+
22
+ jobs:
23
+ investigate:
24
+ uses: markhuangai/git-vibe/.github/workflows/investigate.yml@v2
25
+ with:
26
+ issue-number: ${{ inputs.issue-number }}
27
+ runner: ubuntu-latest
28
+ timeout_minutes: 60
29
+ max_turns: 90
30
+ dry-run: ${{ inputs.dry-run }}
31
+ source-comment: ${{ inputs.source-comment }}
32
+ secrets:
33
+ GITVIBE_GITHUB_TOKEN: ${{ secrets.GITVIBE_GITHUB_TOKEN }}
34
+ GITVIBE_AI_ENV_JSON: ${{ secrets.GITVIBE_AI_ENV_JSON }}
@@ -0,0 +1,34 @@
1
+ name: GitVibe materialize
2
+ run-name: "[git-vibe][materialize]: Discussion #${{ inputs.discussion-number }}"
3
+
4
+ on:
5
+ workflow_dispatch:
6
+ inputs:
7
+ discussion-number:
8
+ description: Discussion number to materialize.
9
+ required: true
10
+ type: string
11
+ dry-run:
12
+ description: Validate without writing to GitHub.
13
+ required: false
14
+ type: boolean
15
+ default: false
16
+ source-comment:
17
+ description: JSON source comment metadata for replying to command comments.
18
+ required: false
19
+ type: string
20
+ default: ""
21
+
22
+ jobs:
23
+ materialize:
24
+ uses: markhuangai/git-vibe/.github/workflows/materialize.yml@v2
25
+ with:
26
+ discussion-number: ${{ inputs.discussion-number }}
27
+ runner: ubuntu-latest
28
+ timeout_minutes: 60
29
+ max_turns: 90
30
+ dry-run: ${{ inputs.dry-run }}
31
+ source-comment: ${{ inputs.source-comment }}
32
+ secrets:
33
+ GITVIBE_GITHUB_TOKEN: ${{ secrets.GITVIBE_GITHUB_TOKEN }}
34
+ GITVIBE_AI_ENV_JSON: ${{ secrets.GITVIBE_AI_ENV_JSON }}
@@ -0,0 +1,41 @@
1
+ name: GitVibe validate
2
+ run-name: "[git-vibe][validate]: ${{ inputs.discussion-number != '' && format('Discussion #{0}', inputs.discussion-number) || inputs.issue-number != '' && format('Issue #{0}', inputs.issue-number) || 'Artifact' }}"
3
+
4
+ on:
5
+ workflow_dispatch:
6
+ inputs:
7
+ issue-number:
8
+ description: Issue number to validate.
9
+ required: false
10
+ type: string
11
+ default: ""
12
+ discussion-number:
13
+ description: Discussion number to validate.
14
+ required: false
15
+ type: string
16
+ default: ""
17
+ dry-run:
18
+ description: Validate without writing to GitHub.
19
+ required: false
20
+ type: boolean
21
+ default: false
22
+ source-comment:
23
+ description: JSON source comment metadata for replying to command comments.
24
+ required: false
25
+ type: string
26
+ default: ""
27
+
28
+ jobs:
29
+ validate:
30
+ uses: markhuangai/git-vibe/.github/workflows/validate.yml@v2
31
+ with:
32
+ issue-number: ${{ inputs.issue-number }}
33
+ discussion-number: ${{ inputs.discussion-number }}
34
+ runner: ubuntu-latest
35
+ timeout_minutes: 60
36
+ max_turns: 90
37
+ dry-run: ${{ inputs.dry-run }}
38
+ source-comment: ${{ inputs.source-comment }}
39
+ secrets:
40
+ GITVIBE_GITHUB_TOKEN: ${{ secrets.GITVIBE_GITHUB_TOKEN }}
41
+ GITVIBE_AI_ENV_JSON: ${{ secrets.GITVIBE_AI_ENV_JSON }}
@@ -0,0 +1,8 @@
1
+ {
2
+ "CLAUDE_OAUTH_TOKEN": "replace-with-claude-oauth-token",
3
+ "CODEX_AUTH_JSON": "{\"tokens\":[]}",
4
+ "GITVIBE_AI_API_KEY": "replace-with-ai-provider-api-key",
5
+ "GITVIBE_AI_BASE_URL": "https://api.provider.example/v1",
6
+ "MINIMAX_API_KEY": "replace-with-minimax-api-key",
7
+ "MINIMAX_ANTHROPIC_BASE_URL": "https://api.minimax.example/anthropic"
8
+ }