pi-agent-toolkit 0.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/dist/dotfiles/AGENTS.md +197 -0
- package/dist/dotfiles/APPEND_SYSTEM.md +78 -0
- package/dist/dotfiles/agent-modes.json +12 -0
- package/dist/dotfiles/agent-skills/exa-search/.env.example +4 -0
- package/dist/dotfiles/agent-skills/exa-search/SKILL.md +234 -0
- package/dist/dotfiles/agent-skills/exa-search/scripts/exa-api.cjs +197 -0
- package/dist/dotfiles/auth.json.template +5 -0
- package/dist/dotfiles/damage-control-rules.yaml +318 -0
- package/dist/dotfiles/extensions/btw.ts +1031 -0
- package/dist/dotfiles/extensions/commit-approval.ts +590 -0
- package/dist/dotfiles/extensions/context.ts +578 -0
- package/dist/dotfiles/extensions/control.ts +1748 -0
- package/dist/dotfiles/extensions/damage-control/index.ts +543 -0
- package/dist/dotfiles/extensions/damage-control/node_modules/.package-lock.json +22 -0
- package/dist/dotfiles/extensions/damage-control/package-lock.json +28 -0
- package/dist/dotfiles/extensions/damage-control/package.json +7 -0
- package/dist/dotfiles/extensions/dirty-repo-guard.ts +56 -0
- package/dist/dotfiles/extensions/exa-enforce.ts +51 -0
- package/dist/dotfiles/extensions/exa-search-tool.ts +384 -0
- package/dist/dotfiles/extensions/execute-command/index.ts +82 -0
- package/dist/dotfiles/extensions/files.ts +1112 -0
- package/dist/dotfiles/extensions/loop.ts +446 -0
- package/dist/dotfiles/extensions/pr-approval.ts +730 -0
- package/dist/dotfiles/extensions/qna-interactive.ts +532 -0
- package/dist/dotfiles/extensions/question-mode.ts +242 -0
- package/dist/dotfiles/extensions/require-session-name-on-exit.ts +141 -0
- package/dist/dotfiles/extensions/review.ts +2091 -0
- package/dist/dotfiles/extensions/session-breakdown.ts +1629 -0
- package/dist/dotfiles/extensions/term-notify.ts +150 -0
- package/dist/dotfiles/extensions/tilldone.ts +527 -0
- package/dist/dotfiles/extensions/todos.ts +2082 -0
- package/dist/dotfiles/extensions/tools.ts +146 -0
- package/dist/dotfiles/extensions/uv.ts +123 -0
- package/dist/dotfiles/global-skills/brainstorm/SKILL.md +10 -0
- package/dist/dotfiles/global-skills/cli-detector/SKILL.md +192 -0
- package/dist/dotfiles/global-skills/gh-issue-creator/SKILL.md +173 -0
- package/dist/dotfiles/global-skills/google-chat-cards-v2/SKILL.md +237 -0
- package/dist/dotfiles/global-skills/google-chat-cards-v2/references/bridge_tap_implementation.md +466 -0
- package/dist/dotfiles/global-skills/technical-docs/SKILL.md +204 -0
- package/dist/dotfiles/global-skills/technical-docs/references/diagrams.md +168 -0
- package/dist/dotfiles/global-skills/technical-docs/references/examples.md +449 -0
- package/dist/dotfiles/global-skills/technical-docs/scripts/validate_docs.py +352 -0
- package/dist/dotfiles/global-skills/whats-new/SKILL.md +159 -0
- package/dist/dotfiles/intercepted-commands/pip +7 -0
- package/dist/dotfiles/intercepted-commands/pip3 +7 -0
- package/dist/dotfiles/intercepted-commands/poetry +10 -0
- package/dist/dotfiles/intercepted-commands/python +104 -0
- package/dist/dotfiles/intercepted-commands/python3 +104 -0
- package/dist/dotfiles/mcp.json.template +32 -0
- package/dist/dotfiles/models.json +27 -0
- package/dist/dotfiles/settings.json +25 -0
- package/dist/index.js +1344 -0
- package/package.json +34 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tools Extension
|
|
3
|
+
*
|
|
4
|
+
* Provides a /tools command to enable/disable tools interactively.
|
|
5
|
+
* Tool selection persists across session reloads and respects branch navigation.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* 1. Copy this file to ~/.pi/agent/extensions/ or your project's .pi/extensions/
|
|
9
|
+
* 2. Use /tools to open the tool selector
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { ExtensionAPI, ExtensionContext, ToolInfo } from "@mariozechner/pi-coding-agent";
|
|
13
|
+
import { getSettingsListTheme } from "@mariozechner/pi-coding-agent";
|
|
14
|
+
import { Container, type SettingItem, SettingsList } from "@mariozechner/pi-tui";
|
|
15
|
+
|
|
16
|
+
// State persisted to session
|
|
17
|
+
interface ToolsState {
|
|
18
|
+
enabledTools: string[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default function toolsExtension(pi: ExtensionAPI) {
|
|
22
|
+
// Track enabled tools
|
|
23
|
+
let enabledTools: Set<string> = new Set();
|
|
24
|
+
let allTools: ToolInfo[] = [];
|
|
25
|
+
|
|
26
|
+
// Persist current state
|
|
27
|
+
function persistState() {
|
|
28
|
+
pi.appendEntry<ToolsState>("tools-config", {
|
|
29
|
+
enabledTools: Array.from(enabledTools),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Apply current tool selection
|
|
34
|
+
function applyTools() {
|
|
35
|
+
pi.setActiveTools(Array.from(enabledTools));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Find the last tools-config entry in the current branch
|
|
39
|
+
function restoreFromBranch(ctx: ExtensionContext) {
|
|
40
|
+
allTools = pi.getAllTools();
|
|
41
|
+
|
|
42
|
+
// Get entries in current branch only
|
|
43
|
+
const branchEntries = ctx.sessionManager.getBranch();
|
|
44
|
+
let savedTools: string[] | undefined;
|
|
45
|
+
|
|
46
|
+
for (const entry of branchEntries) {
|
|
47
|
+
if (entry.type === "custom" && entry.customType === "tools-config") {
|
|
48
|
+
const data = entry.data as ToolsState | undefined;
|
|
49
|
+
if (data?.enabledTools) {
|
|
50
|
+
savedTools = data.enabledTools;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (savedTools) {
|
|
56
|
+
// Restore saved tool selection (filter to only tools that still exist)
|
|
57
|
+
const allToolNames = allTools.map((t) => t.name);
|
|
58
|
+
enabledTools = new Set(savedTools.filter((t: string) => allToolNames.includes(t)));
|
|
59
|
+
applyTools();
|
|
60
|
+
} else {
|
|
61
|
+
// No saved state - sync with currently active tools
|
|
62
|
+
enabledTools = new Set(pi.getActiveTools());
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Register /tools command
|
|
67
|
+
pi.registerCommand("tools", {
|
|
68
|
+
description: "Enable/disable tools",
|
|
69
|
+
handler: async (_args, ctx) => {
|
|
70
|
+
// Refresh tool list
|
|
71
|
+
allTools = pi.getAllTools();
|
|
72
|
+
|
|
73
|
+
await ctx.ui.custom((tui, theme, _kb, done) => {
|
|
74
|
+
// Build settings items for each tool
|
|
75
|
+
const items: SettingItem[] = allTools.map((tool) => ({
|
|
76
|
+
id: tool.name,
|
|
77
|
+
label: tool.name,
|
|
78
|
+
currentValue: enabledTools.has(tool.name) ? "enabled" : "disabled",
|
|
79
|
+
values: ["enabled", "disabled"],
|
|
80
|
+
}));
|
|
81
|
+
|
|
82
|
+
const container = new Container();
|
|
83
|
+
container.addChild(
|
|
84
|
+
new (class {
|
|
85
|
+
render(_width: number) {
|
|
86
|
+
return [theme.fg("accent", theme.bold("Tool Configuration")), ""];
|
|
87
|
+
}
|
|
88
|
+
invalidate() {}
|
|
89
|
+
})(),
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const settingsList = new SettingsList(
|
|
93
|
+
items,
|
|
94
|
+
Math.min(items.length + 2, 15),
|
|
95
|
+
getSettingsListTheme(),
|
|
96
|
+
(id, newValue) => {
|
|
97
|
+
// Update enabled state and apply immediately
|
|
98
|
+
if (newValue === "enabled") {
|
|
99
|
+
enabledTools.add(id);
|
|
100
|
+
} else {
|
|
101
|
+
enabledTools.delete(id);
|
|
102
|
+
}
|
|
103
|
+
applyTools();
|
|
104
|
+
persistState();
|
|
105
|
+
},
|
|
106
|
+
() => {
|
|
107
|
+
// Close dialog
|
|
108
|
+
done(undefined);
|
|
109
|
+
},
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
container.addChild(settingsList);
|
|
113
|
+
|
|
114
|
+
const component = {
|
|
115
|
+
render(width: number) {
|
|
116
|
+
return container.render(width);
|
|
117
|
+
},
|
|
118
|
+
invalidate() {
|
|
119
|
+
container.invalidate();
|
|
120
|
+
},
|
|
121
|
+
handleInput(data: string) {
|
|
122
|
+
settingsList.handleInput?.(data);
|
|
123
|
+
tui.requestRender();
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
return component;
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Restore state on session start
|
|
133
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
134
|
+
restoreFromBranch(ctx);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Restore state when navigating the session tree
|
|
138
|
+
pi.on("session_tree", async (_event, ctx) => {
|
|
139
|
+
restoreFromBranch(ctx);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Restore state after forking
|
|
143
|
+
pi.on("session_fork", async (_event, ctx) => {
|
|
144
|
+
restoreFromBranch(ctx);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UV Extension - Redirects Python tooling to uv equivalents
|
|
3
|
+
*
|
|
4
|
+
* This extension wraps the bash tool to prepend intercepted-commands to PATH,
|
|
5
|
+
* which contains shim scripts that intercept common Python tooling commands
|
|
6
|
+
* and redirect agents to use uv instead.
|
|
7
|
+
*
|
|
8
|
+
* Intercepted commands:
|
|
9
|
+
* - pip/pip3: Blocked with suggestions to use `uv add` or `uv run --with`
|
|
10
|
+
* - poetry: Blocked with uv equivalents (uv init, uv add, uv sync, uv run)
|
|
11
|
+
* - python/python3: Redirected through `uv run` to a real interpreter path,
|
|
12
|
+
* with special handling to block `python -m pip`, `python -m venv`, and
|
|
13
|
+
* `python -m py_compile`
|
|
14
|
+
*
|
|
15
|
+
* The shim scripts are located in the intercepted-commands directory and
|
|
16
|
+
* provide helpful error messages with the equivalent uv commands.
|
|
17
|
+
*
|
|
18
|
+
* Note: PATH shims are bypassable via explicit interpreter paths
|
|
19
|
+
* (for example `.venv/bin/python`). To close that gap, this extension also
|
|
20
|
+
* blocks disallowed invocations at bash spawn time.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
24
|
+
import { createBashTool } from "@mariozechner/pi-coding-agent";
|
|
25
|
+
import { dirname, join } from "path";
|
|
26
|
+
import { fileURLToPath } from "url";
|
|
27
|
+
|
|
28
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
29
|
+
const interceptedCommandsPath = join(__dirname, "..", "intercepted-commands");
|
|
30
|
+
|
|
31
|
+
function getBlockedCommandMessage(command: string): string | null {
|
|
32
|
+
// Match commands at the start of a shell segment (start/newline/; /&& /|| /|)
|
|
33
|
+
const pipCommandPattern = /(?:^|\n|[;|&]{1,2})\s*(?:\S+\/)?pip\s*(?:$|\s)/m;
|
|
34
|
+
const pip3CommandPattern = /(?:^|\n|[;|&]{1,2})\s*(?:\S+\/)?pip3\s*(?:$|\s)/m;
|
|
35
|
+
const poetryCommandPattern = /(?:^|\n|[;|&]{1,2})\s*(?:\S+\/)?poetry\s*(?:$|\s)/m;
|
|
36
|
+
|
|
37
|
+
// Match python invocations including explicit paths like .venv/bin/python
|
|
38
|
+
// and .venv/bin/python3.12.
|
|
39
|
+
const pythonPipPattern =
|
|
40
|
+
/(?:^|\n|[;|&]{1,2})\s*(?:\S+\/)?python(?:3(?:\.\d+)?)?\b[^\n;|&]*(?:\s-m\s*pip\b|\s-mpip\b)/m;
|
|
41
|
+
const pythonVenvPattern =
|
|
42
|
+
/(?:^|\n|[;|&]{1,2})\s*(?:\S+\/)?python(?:3(?:\.\d+)?)?\b[^\n;|&]*(?:\s-m\s*venv\b|\s-mvenv\b)/m;
|
|
43
|
+
const pythonPyCompilePattern =
|
|
44
|
+
/(?:^|\n|[;|&]{1,2})\s*(?:\S+\/)?python(?:3(?:\.\d+)?)?\b[^\n;|&]*(?:\s-m\s*py_compile\b|\s-mpy_compile\b)/m;
|
|
45
|
+
|
|
46
|
+
if (pipCommandPattern.test(command)) {
|
|
47
|
+
return [
|
|
48
|
+
"Error: pip is disabled. Use uv instead:",
|
|
49
|
+
"",
|
|
50
|
+
" To install a package for a script: uv run --with PACKAGE python script.py",
|
|
51
|
+
" To add a dependency to the project: uv add PACKAGE",
|
|
52
|
+
"",
|
|
53
|
+
].join("\n");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (pip3CommandPattern.test(command)) {
|
|
57
|
+
return [
|
|
58
|
+
"Error: pip3 is disabled. Use uv instead:",
|
|
59
|
+
"",
|
|
60
|
+
" To install a package for a script: uv run --with PACKAGE python script.py",
|
|
61
|
+
" To add a dependency to the project: uv add PACKAGE",
|
|
62
|
+
"",
|
|
63
|
+
].join("\n");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (poetryCommandPattern.test(command)) {
|
|
67
|
+
return [
|
|
68
|
+
"Error: poetry is disabled. Use uv instead:",
|
|
69
|
+
"",
|
|
70
|
+
" To initialize a project: uv init",
|
|
71
|
+
" To add a dependency: uv add PACKAGE",
|
|
72
|
+
" To sync dependencies: uv sync",
|
|
73
|
+
" To run commands: uv run COMMAND",
|
|
74
|
+
"",
|
|
75
|
+
].join("\n");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (pythonPipPattern.test(command)) {
|
|
79
|
+
return [
|
|
80
|
+
"Error: 'python -m pip' is disabled. Use uv instead:",
|
|
81
|
+
"",
|
|
82
|
+
" To install a package for a script: uv run --with PACKAGE python script.py",
|
|
83
|
+
" To add a dependency to the project: uv add PACKAGE",
|
|
84
|
+
"",
|
|
85
|
+
].join("\n");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (pythonVenvPattern.test(command)) {
|
|
89
|
+
return [
|
|
90
|
+
"Error: 'python -m venv' is disabled. Use uv instead:",
|
|
91
|
+
"",
|
|
92
|
+
" To create a virtual environment: uv venv",
|
|
93
|
+
"",
|
|
94
|
+
].join("\n");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (pythonPyCompilePattern.test(command)) {
|
|
98
|
+
return [
|
|
99
|
+
"Error: 'python -m py_compile' is disabled because it writes .pyc files to __pycache__.",
|
|
100
|
+
"",
|
|
101
|
+
" To verify syntax without bytecode output: uv run python -m ast path/to/file.py >/dev/null",
|
|
102
|
+
"",
|
|
103
|
+
].join("\n");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export default function (pi: ExtensionAPI) {
|
|
110
|
+
const cwd = process.cwd();
|
|
111
|
+
const bashTool = createBashTool(cwd, {
|
|
112
|
+
commandPrefix: `export PATH="${interceptedCommandsPath}:$PATH"`,
|
|
113
|
+
spawnHook: (ctx) => {
|
|
114
|
+
const blockedMessage = getBlockedCommandMessage(ctx.command);
|
|
115
|
+
if (blockedMessage) {
|
|
116
|
+
throw new Error(blockedMessage);
|
|
117
|
+
}
|
|
118
|
+
return ctx;
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
pi.registerTool(bashTool);
|
|
123
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: brainstorm
|
|
3
|
+
description: Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision tree. Use when user wants to stress-test a plan, get grilled on their design, or mentions "brainstorm".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer.
|
|
7
|
+
|
|
8
|
+
Ask the questions one at a time.
|
|
9
|
+
|
|
10
|
+
If a question can be answered by exploring the codebase, explore the codebase instead.
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cli-detector
|
|
3
|
+
description: >
|
|
4
|
+
Scan a repository to discover all external SaaS tools and services it integrates with,
|
|
5
|
+
then determine whether each has an official CLI. Use this skill whenever the user asks
|
|
6
|
+
to find CLIs for their project, audit third-party service integrations, discover what
|
|
7
|
+
external services a codebase depends on, check for official CLI tools, or wants to know
|
|
8
|
+
"what services does this repo use." Also trigger when the user asks about automating
|
|
9
|
+
service management, scripting deployments, or wants to interact with their project's
|
|
10
|
+
services from the terminal.
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# CLI Detector
|
|
14
|
+
|
|
15
|
+
Analyze a repository to identify every external SaaS service it integrates with, then
|
|
16
|
+
research whether each service provides an official CLI tool.
|
|
17
|
+
|
|
18
|
+
The workflow has three phases: **Detect**, **Verify**, **Report**. Do not skip or
|
|
19
|
+
reorder these phases.
|
|
20
|
+
|
|
21
|
+
## Phase 1: Detect services
|
|
22
|
+
|
|
23
|
+
Scan the repository using all applicable detection vectors below. Each vector catches
|
|
24
|
+
services the others miss, so work through every one that applies to this project's
|
|
25
|
+
language ecosystem.
|
|
26
|
+
|
|
27
|
+
### What counts as an "external service"
|
|
28
|
+
|
|
29
|
+
An external service is a hosted platform or SaaS product that the application connects
|
|
30
|
+
to over the network. The company behind it manages the infrastructure.
|
|
31
|
+
|
|
32
|
+
**Include:** Stripe, Sentry, Clerk, Auth0, Vercel, AWS S3, Twilio, SendGrid, Resend,
|
|
33
|
+
Datadog, LaunchDarkly, Algolia, Supabase, Neon, PlanetScale, Upstash, DigitalOcean,
|
|
34
|
+
Cloudflare, Firebase, GitHub (as a service), Netlify, Fly.io, Render, Railway, etc.
|
|
35
|
+
|
|
36
|
+
**Exclude (these are never external services):**
|
|
37
|
+
- Generic database clients: `mysql2`, `pg`, `psycopg2`, `database/sql`, `SQLAlchemy`
|
|
38
|
+
- Generic protocols: SSH libraries, HTTP clients (`axios`, `requests`, `fetch`)
|
|
39
|
+
- Frameworks: Next.js, Django, Rails, Express, FastAPI
|
|
40
|
+
- ORMs: Drizzle, Prisma, TypeORM, ActiveRecord
|
|
41
|
+
- UI libraries: React, Vue, Tailwind, Bootstrap
|
|
42
|
+
- Build tools, runtimes, test runners, linters, formatters
|
|
43
|
+
|
|
44
|
+
The test: if removing the integration means losing access to a *third-party managed
|
|
45
|
+
platform* (not just a protocol or library), it is an external service.
|
|
46
|
+
|
|
47
|
+
### Vector 1: Package manager manifests
|
|
48
|
+
|
|
49
|
+
Read dependency files for SDK packages from known service vendors.
|
|
50
|
+
|
|
51
|
+
| Ecosystem | Files |
|
|
52
|
+
|-----------|-------|
|
|
53
|
+
| Node.js / TypeScript | `package.json` |
|
|
54
|
+
| Python | `pyproject.toml`, `requirements.txt`, `setup.py`, `Pipfile` |
|
|
55
|
+
| Go | `go.mod` |
|
|
56
|
+
| Ruby | `Gemfile` |
|
|
57
|
+
| Rust | `Cargo.toml` |
|
|
58
|
+
| Java / Kotlin | `build.gradle`, `pom.xml` |
|
|
59
|
+
| PHP | `composer.json` |
|
|
60
|
+
| .NET | `*.csproj`, `packages.config` |
|
|
61
|
+
|
|
62
|
+
Vendor-namespaced packages are strong signals: `@sentry/nextjs`, `@clerk/nextjs`,
|
|
63
|
+
`stripe`, `boto3`, `google-cloud-storage`.
|
|
64
|
+
|
|
65
|
+
### Vector 2: Environment variables
|
|
66
|
+
|
|
67
|
+
Search source code for env var access patterns and collect all variable names.
|
|
68
|
+
|
|
69
|
+
| Language | Search pattern |
|
|
70
|
+
|----------|---------------|
|
|
71
|
+
| Node.js / TypeScript | `process.env.VARIABLE_NAME` |
|
|
72
|
+
| Python | `os.environ`, `os.getenv()` |
|
|
73
|
+
| Go | `os.Getenv("VARIABLE")` |
|
|
74
|
+
| Ruby | `ENV["VARIABLE"]`, `ENV.fetch` |
|
|
75
|
+
|
|
76
|
+
Also check `.env.example`, `.env.sample`, `.env.template` files.
|
|
77
|
+
|
|
78
|
+
Variable names reveal services: `STRIPE_SECRET_KEY` -> Stripe, `SENTRY_DSN` -> Sentry,
|
|
79
|
+
`CLERK_SECRET_KEY` -> Clerk, `RESEND_API_KEY` -> Resend, `DO_API_TOKEN` -> DigitalOcean,
|
|
80
|
+
`UPSTASH_REDIS_REST_URL` -> Upstash, `AWS_ACCESS_KEY_ID` -> AWS, etc.
|
|
81
|
+
|
|
82
|
+
### Vector 3: Configuration files
|
|
83
|
+
|
|
84
|
+
Service-specific config files at the project root:
|
|
85
|
+
|
|
86
|
+
`sentry.*.config.ts` -> Sentry, `vercel.json` / `.vercel/` -> Vercel,
|
|
87
|
+
`firebase.json` -> Firebase, `netlify.toml` -> Netlify, `fly.toml` -> Fly.io,
|
|
88
|
+
`wrangler.toml` -> Cloudflare Workers, `serverless.yml` -> check provider field,
|
|
89
|
+
`render.yaml` -> Render, `railway.json` -> Railway
|
|
90
|
+
|
|
91
|
+
### Vector 4: Source code imports and API URLs
|
|
92
|
+
|
|
93
|
+
Search for direct SDK imports and hardcoded API base URLs:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Service SDK imports (adapt patterns to the project's language)
|
|
97
|
+
grep -r "from '@sentry\|from \"@sentry\|require('@sentry" src/
|
|
98
|
+
grep -r "api.digitalocean.com\|api.stripe.com\|api.sendgrid.com" src/
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Vector 5: Implicit / indirect signals
|
|
102
|
+
|
|
103
|
+
Some services leave clues without explicit SDK imports. **Actively search** for these
|
|
104
|
+
patterns rather than waiting to stumble on them:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Vercel signals
|
|
108
|
+
grep -r "maxDuration" src/ --include="*.ts" --include="*.tsx" -l
|
|
109
|
+
grep -r "CRON_SECRET" src/ --include="*.ts" --include="*.tsx" -l
|
|
110
|
+
ls vercel.json .vercel/ 2>/dev/null
|
|
111
|
+
|
|
112
|
+
# Heroku signals
|
|
113
|
+
ls Procfile app.json 2>/dev/null
|
|
114
|
+
|
|
115
|
+
# Hosting platform from git remote
|
|
116
|
+
git remote -v 2>/dev/null
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
- **Vercel**: `maxDuration` exports in API route files are Vercel-specific serverless
|
|
120
|
+
config. `CRON_SECRET` is a Vercel Cron Jobs feature. `@vercel/*` packages.
|
|
121
|
+
- **GitHub**: git remote pointing to github.com, `.github/` directory with workflows.
|
|
122
|
+
- **GitLab**: git remote pointing to gitlab.com, `.gitlab-ci.yml`.
|
|
123
|
+
- **Heroku**: `Procfile`, `app.json`.
|
|
124
|
+
|
|
125
|
+
### Vector 6: CI/CD pipelines
|
|
126
|
+
|
|
127
|
+
Scan pipeline configs for service references not visible in application code:
|
|
128
|
+
|
|
129
|
+
- `.github/workflows/*.yml`: `uses:` actions, secrets references
|
|
130
|
+
- `.gitlab-ci.yml`, `.circleci/config.yml`, `Jenkinsfile`
|
|
131
|
+
|
|
132
|
+
## Phase 2: Verify CLI existence with Exa
|
|
133
|
+
|
|
134
|
+
This phase is mandatory. Do not determine CLI status from memory or training data.
|
|
135
|
+
|
|
136
|
+
Service CLIs are launched and deprecated frequently. Training data is often wrong
|
|
137
|
+
about whether a specific service has a CLI, especially for newer or smaller services.
|
|
138
|
+
The only reliable way to determine CLI status is to check externally.
|
|
139
|
+
|
|
140
|
+
### What qualifies as an "official CLI"
|
|
141
|
+
|
|
142
|
+
All four criteria must be met:
|
|
143
|
+
- Created and maintained by the service provider (not a community wrapper)
|
|
144
|
+
- Purpose-built to interact with that specific service
|
|
145
|
+
- Has official documentation from the provider
|
|
146
|
+
- Available through standard package managers (npm, brew, apt, pip, etc.)
|
|
147
|
+
|
|
148
|
+
### Verification procedure
|
|
149
|
+
|
|
150
|
+
For **every** service identified in Phase 1, call `exa_search` with the `answer`
|
|
151
|
+
endpoint:
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
exa_search endpoint=answer query="Does [SERVICE_NAME] have an official CLI tool?"
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
This returns the CLI name, install command, and source links. If the answer is
|
|
158
|
+
ambiguous or uncertain, follow up with a targeted doc-site search:
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
exa_search endpoint=search query="[SERVICE_NAME] CLI"
|
|
162
|
+
includeDomains=["official-docs-domain.com"]
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Do not mark any service as "No CLI" without first running an Exa query for it.
|
|
166
|
+
Even services that seem unlikely to have a CLI (auth providers, email services,
|
|
167
|
+
newer startups) should be verified. CLI tooling is expanding rapidly and assumptions
|
|
168
|
+
from training data are frequently wrong.
|
|
169
|
+
|
|
170
|
+
## Phase 3: Report
|
|
171
|
+
|
|
172
|
+
Present findings in two tables.
|
|
173
|
+
|
|
174
|
+
### Primary table: services with CLI status
|
|
175
|
+
|
|
176
|
+
| # | Service | Usage in This Repo | Official CLI? | CLI Name | Install |
|
|
177
|
+
|---|---------|-------------------|:---:|----------|---------|
|
|
178
|
+
| 1 | **Stripe** | Payment processing (`stripe` SDK, `STRIPE_SECRET_KEY`) | Yes | `stripe` | `brew install stripe/stripe-cli/stripe` |
|
|
179
|
+
| 2 | **SomeService** | Feature flags (`SOMESERVICE_API_KEY`) | No | N/A | N/A |
|
|
180
|
+
|
|
181
|
+
The "Usage in This Repo" column should include:
|
|
182
|
+
- What the service is used for (brief)
|
|
183
|
+
- How it was detected (SDK name, env var, config file)
|
|
184
|
+
|
|
185
|
+
### Secondary table: excluded items
|
|
186
|
+
|
|
187
|
+
| Tool | Reason excluded |
|
|
188
|
+
|------|----------------|
|
|
189
|
+
| MySQL (`mysql2`) | Generic database client, not an external service |
|
|
190
|
+
|
|
191
|
+
This table shows the user you considered these tools and correctly filtered them.
|
|
192
|
+
It demonstrates thoroughness.
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gh-issue-creator
|
|
3
|
+
description: Use when creating GitHub issues via the `gh` CLI. Covers body structure, issue type classification (bug, feature, task), label selection, and consistent formatting. Triggers on requests to file, create, open, or submit a GitHub issue.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GitHub Issue Creator
|
|
7
|
+
|
|
8
|
+
Create well-structured GitHub issues using the `gh` CLI with consistent formatting, appropriate labels, and type-specific body templates.
|
|
9
|
+
|
|
10
|
+
## Ground rules
|
|
11
|
+
|
|
12
|
+
- Always use `gh issue create` with `--title`, `--body`, and `--label` flags
|
|
13
|
+
- Auto-detect the repo from the current git context (do not ask the user to specify unless `gh` cannot resolve it)
|
|
14
|
+
- Never include AI attribution or emojis in issue titles or bodies
|
|
15
|
+
- Use imperative mood in titles (e.g., "Add retry logic" not "Added retry logic")
|
|
16
|
+
|
|
17
|
+
## Issue types and label mapping
|
|
18
|
+
|
|
19
|
+
Classify every issue into one of three types based on user intent. Map to the corresponding GitHub label:
|
|
20
|
+
|
|
21
|
+
| User intent | GitHub label | When to use |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| **Bug** | `bug` | Something is broken, produces wrong results, or crashes |
|
|
24
|
+
| **Feature** | `enhancement` | New capability, improvement, or behavioral change |
|
|
25
|
+
| **Task** | context-dependent | Maintenance, refactoring, docs, infra work, chores |
|
|
26
|
+
|
|
27
|
+
If the user says "feature request", "new feature", or "enhancement", use `enhancement`.
|
|
28
|
+
If the user says "bug", "broken", "regression", or "not working", use `bug`.
|
|
29
|
+
If the user says "task", "chore", "refactor", or "cleanup", pick the most fitting existing label (e.g., `documentation` for docs work) or omit `--label` entirely when nothing fits. Do not force a label.
|
|
30
|
+
|
|
31
|
+
When uncertain, ask the user which type fits before creating the issue.
|
|
32
|
+
|
|
33
|
+
## Title guidelines
|
|
34
|
+
|
|
35
|
+
- Short and descriptive, max 72 characters
|
|
36
|
+
- Imperative mood: "Add X", "Fix Y", "Update Z"
|
|
37
|
+
- Include the affected area when it adds clarity: "fix(routing): handle missing advertiser ID"
|
|
38
|
+
- No trailing punctuation
|
|
39
|
+
|
|
40
|
+
## Body structure by type
|
|
41
|
+
|
|
42
|
+
### Feature request (`enhancement`)
|
|
43
|
+
|
|
44
|
+
```markdown
|
|
45
|
+
## Summary
|
|
46
|
+
|
|
47
|
+
One paragraph describing what the feature does and why it matters.
|
|
48
|
+
|
|
49
|
+
## Motivation
|
|
50
|
+
|
|
51
|
+
- Why this is needed
|
|
52
|
+
- What problem it solves
|
|
53
|
+
- What is painful or missing today
|
|
54
|
+
|
|
55
|
+
## Proposed Changes
|
|
56
|
+
|
|
57
|
+
### Before
|
|
58
|
+
|
|
59
|
+
Show the current state -- code, config, architecture, or behavior.
|
|
60
|
+
Use code blocks when showing concrete artifacts.
|
|
61
|
+
|
|
62
|
+
### After
|
|
63
|
+
|
|
64
|
+
Show the proposed state with the same level of detail.
|
|
65
|
+
Before/after should be directly comparable.
|
|
66
|
+
|
|
67
|
+
## Implementation Phases
|
|
68
|
+
|
|
69
|
+
Numbered list of major steps if the work spans multiple PRs or stages.
|
|
70
|
+
Skip this section for small, single-PR features.
|
|
71
|
+
|
|
72
|
+
## Affected Files
|
|
73
|
+
|
|
74
|
+
List the key files or areas of the codebase that will change.
|
|
75
|
+
Group by category (runtime, config, tests, etc.) when helpful.
|
|
76
|
+
|
|
77
|
+
## Acceptance Criteria
|
|
78
|
+
|
|
79
|
+
- [ ] Checklist of conditions that must be true for the work to be complete
|
|
80
|
+
- [ ] Each item should be independently verifiable
|
|
81
|
+
- [ ] Include both functional and testing criteria
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Optional sections** (include when relevant):
|
|
85
|
+
- **Rollback Strategy** -- for risky or reversible changes
|
|
86
|
+
- **Risks** -- known risks and mitigations
|
|
87
|
+
- **References** -- links to external docs, RFCs, or related issues
|
|
88
|
+
|
|
89
|
+
### Bug report (`bug`)
|
|
90
|
+
|
|
91
|
+
```markdown
|
|
92
|
+
## Summary
|
|
93
|
+
|
|
94
|
+
One paragraph describing the bug and its impact.
|
|
95
|
+
|
|
96
|
+
## Steps to Reproduce
|
|
97
|
+
|
|
98
|
+
1. Numbered steps to trigger the bug
|
|
99
|
+
2. Be specific about inputs, environment, and timing
|
|
100
|
+
3. Include commands, config snippets, or screenshots as needed
|
|
101
|
+
|
|
102
|
+
## Expected Behavior
|
|
103
|
+
|
|
104
|
+
What should happen.
|
|
105
|
+
|
|
106
|
+
## Actual Behavior
|
|
107
|
+
|
|
108
|
+
What happens instead. Include error messages, logs, or stack traces in code blocks.
|
|
109
|
+
|
|
110
|
+
## Environment
|
|
111
|
+
|
|
112
|
+
- OS / runtime version
|
|
113
|
+
- Relevant dependency versions
|
|
114
|
+
- Any environment-specific context (staging vs prod, specific client config, etc.)
|
|
115
|
+
|
|
116
|
+
## Possible Cause
|
|
117
|
+
|
|
118
|
+
If known or suspected, describe the likely root cause.
|
|
119
|
+
Skip this section if unknown.
|
|
120
|
+
|
|
121
|
+
## Acceptance Criteria
|
|
122
|
+
|
|
123
|
+
- [ ] Bug no longer reproduces under the described steps
|
|
124
|
+
- [ ] Regression test added
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Task (no label or contextual label)
|
|
128
|
+
|
|
129
|
+
```markdown
|
|
130
|
+
## Summary
|
|
131
|
+
|
|
132
|
+
One paragraph describing the task and why it needs to happen.
|
|
133
|
+
|
|
134
|
+
## Context
|
|
135
|
+
|
|
136
|
+
Background information, motivation, or link to the broader initiative.
|
|
137
|
+
|
|
138
|
+
## Requirements
|
|
139
|
+
|
|
140
|
+
- Bulleted list of what the task must accomplish
|
|
141
|
+
- Be specific and verifiable
|
|
142
|
+
|
|
143
|
+
## Acceptance Criteria
|
|
144
|
+
|
|
145
|
+
- [ ] Checklist of done conditions
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Workflow
|
|
149
|
+
|
|
150
|
+
1. **Determine the issue type** from the user's request or ask if ambiguous
|
|
151
|
+
2. **Map to the correct label** using the table above
|
|
152
|
+
3. **Check existing labels** on the repo with `gh label list` to confirm the label exists
|
|
153
|
+
4. **Gather enough context** -- if the user's request is brief, check the codebase for relevant details (file paths, current behavior, config shapes) before drafting. Do not ask the user for information you can find yourself.
|
|
154
|
+
5. **Draft the title and body** using the appropriate template
|
|
155
|
+
6. **Create the issue** -- for short bodies use `gh issue create --title "..." --body "..." --label "..."`. For longer or complex bodies, write to a temp file and use `--body-file` to avoid shell escaping issues.
|
|
156
|
+
7. **Report the issue URL** back to the user
|
|
157
|
+
|
|
158
|
+
## Adapting the template
|
|
159
|
+
|
|
160
|
+
The body templates above are starting points. Adjust based on the content:
|
|
161
|
+
|
|
162
|
+
- **Drop empty sections** -- if there is no rollback strategy or the feature is trivial, omit those sections rather than leaving them blank
|
|
163
|
+
- **Add before/after blocks** -- whenever the change involves a concrete artifact (config, API shape, schema, data format), show the before and after states with code blocks
|
|
164
|
+
- **Scale detail to complexity** -- a one-line bug fix needs a shorter body than a multi-phase architectural change
|
|
165
|
+
- **Preserve the user's language** -- if the user provides specific wording or context, use it rather than rephrasing into generic template language
|
|
166
|
+
|
|
167
|
+
## What NOT to do
|
|
168
|
+
|
|
169
|
+
- Do not create issues without `--title` and `--body` flags (no interactive mode)
|
|
170
|
+
- Do not guess labels that do not exist on the repo
|
|
171
|
+
- Do not include a References section unless the user explicitly provides links or references to include
|
|
172
|
+
- Do not pad the body with boilerplate when the issue is simple
|
|
173
|
+
- Do not ask the user to specify the repo -- detect it from git context
|