opencode-overclock 0.3.0 → 0.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 +252 -111
- package/package.json +6 -4
- package/skills/codebase-design/DEEPENING.md +35 -0
- package/skills/codebase-design/DESIGN-IT-TWICE.md +34 -0
- package/skills/codebase-design/SKILL.md +93 -0
- package/skills/diagnosing-bugs/SKILL.md +123 -0
- package/skills/domain-modeling/ADR-FORMAT.md +55 -0
- package/skills/domain-modeling/CONTEXT-FORMAT.md +32 -0
- package/skills/domain-modeling/SKILL.md +102 -0
- package/skills/doubt/SKILL.md +80 -0
- package/skills/grilling/SKILL.md +96 -0
- package/skills/source-discipline/SKILL.md +78 -0
- package/skills/tdd/SKILL.md +87 -0
- package/skills/to-spec/SKILL.md +69 -0
- package/skills/to-spec/SPEC-TEMPLATE.md +50 -0
- package/skills/to-tickets/SKILL.md +74 -0
- package/skills/to-tickets/TICKET-TEMPLATE.md +41 -0
- package/src/bridge.ts +1 -0
- package/src/buddy/companion.ts +104 -5
- package/src/buddy/sprites.ts +4 -4
- package/src/buddy/tui.ts +175 -65
- package/src/core/bridge.ts +34 -0
- package/src/core/lifecycle.ts +67 -0
- package/src/core/policy.ts +128 -0
- package/src/core/summary.ts +33 -0
- package/src/core/types.ts +193 -0
- package/src/features/buddy.ts +1 -2
- package/src/features/guard.ts +421 -37
- package/src/features/index.ts +18 -4
- package/src/features/recovery.ts +153 -0
- package/src/features/safety.ts +147 -0
- package/src/features/sched.ts +183 -89
- package/src/features/tasks.ts +134 -33
- package/src/features/truncator.ts +116 -0
- package/src/features/usage.ts +46 -65
- package/src/features/workflow.ts +256 -0
- package/src/index.ts +96 -67
- package/src/lib/busy.ts +1 -25
- package/src/lib/exec.ts +13 -0
- package/src/lib/inject.ts +10 -56
- package/src/lib/mirror.ts +13 -0
- package/src/lib/probe.ts +1 -15
- package/src/lib/state.ts +10 -39
- package/src/lib/tmux.ts +1 -0
- package/src/lib/ui.ts +208 -0
- package/src/merge.ts +2 -66
- package/src/platform/probe.ts +25 -0
- package/src/platform/process/exec.ts +317 -0
- package/src/platform/process/tmux.ts +60 -0
- package/src/platform/session/busy.ts +33 -0
- package/src/platform/session/inject.ts +89 -0
- package/src/platform/session/notify.ts +20 -0
- package/src/platform/storage/state.ts +99 -0
- package/src/platform/storage/store.ts +61 -0
- package/src/summary.ts +1 -0
- package/src/tools.ts +8 -244
- package/src/tui.ts +57 -186
- package/src/types.ts +1 -73
- package/src/v2/context.ts +470 -0
- package/src/v2/host.ts +120 -0
- package/src/v2/loader.ts +150 -0
- package/src/workflow/agents/codebase-researcher.ts +27 -0
- package/src/workflow/agents/design-explorer.ts +33 -0
- package/src/workflow/agents/doubt-reviewer.ts +26 -0
- package/src/workflow/agents/engineering-coach.ts +23 -0
- package/src/workflow/agents/performance-auditor.ts +29 -0
- package/src/workflow/agents/security-auditor.ts +23 -0
- package/src/workflow/agents/spec-reviewer.ts +15 -0
- package/src/workflow/agents/standards-reviewer.ts +24 -0
- package/src/workflow/agents/test-engineer.ts +28 -0
- package/src/workflow/catalog.ts +210 -0
- package/src/workflow/templates/build.ts +47 -0
- package/src/workflow/templates/define.ts +45 -0
- package/src/workflow/templates/diagnose.ts +58 -0
- package/src/workflow/templates/plan.ts +52 -0
- package/src/workflow/templates/ship.ts +64 -0
- package/src/buddy/reactions.ts +0 -41
- package/src/buddy/types.ts +0 -30
- package/src/config.ts +0 -19
- package/src/features/checkpoints.ts +0 -128
- package/src/features/sandbox.ts +0 -104
- package/src/validate.ts +0 -197
package/src/v2/loader.ts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview OpenCode V2 Plugin Resolution and Loading
|
|
3
|
+
*
|
|
4
|
+
* Provides resolution, dynamic importation, and execution of V2 plugins
|
|
5
|
+
* on top of a synthetic V2 `PluginContext`.
|
|
6
|
+
*
|
|
7
|
+
* Supported plugin formats:
|
|
8
|
+
* - Direct instances: `{ id, setup(context) }` or `{ id, effect(context) }`
|
|
9
|
+
* - File paths: `./plugins/custom.ts`, `/absolute/path/plugin.js`, `file:///...`
|
|
10
|
+
* - Npm packages: bare module specifiers resolved via node/bun module resolution
|
|
11
|
+
* - Tuples: `[specifier, pluginOptions]` for supplying per-plugin options
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { resolve, isAbsolute } from "path"
|
|
15
|
+
import { pathToFileURL, fileURLToPath } from "url"
|
|
16
|
+
import type { Plugin as V2Plugin, PluginOptions } from "@opencode-ai/plugin/v2/promise"
|
|
17
|
+
import type { Disposer, V2ContextHandle } from "./context.ts"
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Union of accepted V2 plugin declaration formats:
|
|
21
|
+
* - String specifier: file path or package name
|
|
22
|
+
* - Tuple: `[specifier, options]`
|
|
23
|
+
* - Plugin instance conforming to V2 interface
|
|
24
|
+
* - Wrapper object: `{ plugin, options }`
|
|
25
|
+
*/
|
|
26
|
+
export type V2PluginSpec =
|
|
27
|
+
string | [string, PluginOptions] | V2Plugin | { plugin: V2Plugin; options?: PluginOptions }
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Validates whether an unknown value conforms to the OpenCode V2 plugin contract:
|
|
31
|
+
* requires non-empty string `id`, and either an async `setup` method or an `effect` function.
|
|
32
|
+
*/
|
|
33
|
+
export function isV2Plugin(value: unknown): value is V2Plugin {
|
|
34
|
+
if (!value || typeof value !== "object") return false
|
|
35
|
+
const p = value as Record<string, unknown>
|
|
36
|
+
if (typeof p.id !== "string" || !p.id.trim()) return false
|
|
37
|
+
return typeof p.setup === "function" || typeof (p as any).effect === "function"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Resolves a file path or URL specifier against the workspace directory.
|
|
42
|
+
* Preserves bare package names for standard Node/Bun module resolution.
|
|
43
|
+
*/
|
|
44
|
+
export function resolvePluginPath(spec: string, baseDir: string): string {
|
|
45
|
+
if (spec.startsWith("file://")) return fileURLToPath(spec)
|
|
46
|
+
if (isAbsolute(spec)) return spec
|
|
47
|
+
if (spec.startsWith(".")) return resolve(baseDir, spec)
|
|
48
|
+
return spec
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Resolves a V2 plugin specifier into a concrete V2Plugin object and its associated options.
|
|
53
|
+
* Dynamically imports file paths or npm packages if necessary.
|
|
54
|
+
*/
|
|
55
|
+
export async function resolveV2Plugin(
|
|
56
|
+
spec: V2PluginSpec,
|
|
57
|
+
baseDir: string,
|
|
58
|
+
): Promise<{ plugin: V2Plugin; options: PluginOptions } | null> {
|
|
59
|
+
// Case 1: Already an instantiated V2Plugin object
|
|
60
|
+
if (isV2Plugin(spec)) {
|
|
61
|
+
return { plugin: spec, options: {} }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Case 2: Wrapped { plugin, options } object
|
|
65
|
+
if (
|
|
66
|
+
typeof spec === "object" &&
|
|
67
|
+
spec !== null &&
|
|
68
|
+
"plugin" in spec &&
|
|
69
|
+
isV2Plugin((spec as any).plugin)
|
|
70
|
+
) {
|
|
71
|
+
return {
|
|
72
|
+
plugin: (spec as any).plugin,
|
|
73
|
+
options: (spec as any).options ?? {},
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Case 3: Specifier string or [string, options] tuple
|
|
78
|
+
let moduleSpec: string
|
|
79
|
+
let options: PluginOptions = {}
|
|
80
|
+
|
|
81
|
+
if (Array.isArray(spec)) {
|
|
82
|
+
moduleSpec = spec[0]
|
|
83
|
+
options = spec[1] ?? {}
|
|
84
|
+
} else if (typeof spec === "string") {
|
|
85
|
+
moduleSpec = spec
|
|
86
|
+
} else {
|
|
87
|
+
return null
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const resolved = resolvePluginPath(moduleSpec, baseDir)
|
|
91
|
+
const importTarget = resolved.startsWith("/") ? pathToFileURL(resolved).href : resolved
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const mod = await import(importTarget)
|
|
95
|
+
const candidate = mod?.default ?? mod
|
|
96
|
+
if (isV2Plugin(candidate)) {
|
|
97
|
+
return { plugin: candidate, options }
|
|
98
|
+
}
|
|
99
|
+
// Check named exports for a V2 plugin definition
|
|
100
|
+
for (const val of Object.values(mod)) {
|
|
101
|
+
if (isV2Plugin(val)) {
|
|
102
|
+
return { plugin: val, options }
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
console.warn(
|
|
106
|
+
`[overclock] v2: module '${moduleSpec}' does not export a valid V2 plugin ({ id, setup/effect })`,
|
|
107
|
+
)
|
|
108
|
+
return null
|
|
109
|
+
} catch (e) {
|
|
110
|
+
console.warn(`[overclock] v2: failed to import plugin '${moduleSpec}': ${e}`)
|
|
111
|
+
return null
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Loads and initializes a V2 plugin against the synthetic context.
|
|
117
|
+
* Creates a scoped context, handles Effect vs Promise lifecycle, and tracks disposers.
|
|
118
|
+
* Returns the plugin ID if loaded successfully, or null on error.
|
|
119
|
+
*/
|
|
120
|
+
export async function loadV2Plugin(
|
|
121
|
+
spec: V2PluginSpec,
|
|
122
|
+
baseDir: string,
|
|
123
|
+
handle: V2ContextHandle,
|
|
124
|
+
): Promise<string | null> {
|
|
125
|
+
const resolved = await resolveV2Plugin(spec, baseDir)
|
|
126
|
+
if (!resolved) return null
|
|
127
|
+
|
|
128
|
+
const { plugin, options } = resolved
|
|
129
|
+
const pluginDisposers = new Set<Disposer>()
|
|
130
|
+
const scopedCtx = handle.scopedContext(options, pluginDisposers)
|
|
131
|
+
|
|
132
|
+
handle.state.activePlugins.set(plugin.id, {
|
|
133
|
+
plugin,
|
|
134
|
+
disposers: pluginDisposers,
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
if (typeof (plugin as any).effect === "function") {
|
|
139
|
+
const { runPromise } = await import("effect/Effect")
|
|
140
|
+
await runPromise((plugin as any).effect(scopedCtx))
|
|
141
|
+
} else if (typeof plugin.setup === "function") {
|
|
142
|
+
await plugin.setup(scopedCtx)
|
|
143
|
+
}
|
|
144
|
+
return plugin.id
|
|
145
|
+
} catch (e) {
|
|
146
|
+
console.warn(`[overclock] v2: plugin '${plugin.id}' failed during setup: ${e}`)
|
|
147
|
+
await handle.context.plugin.remove(plugin.id)
|
|
148
|
+
return null
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const CODEBASE_RESEARCHER_PROMPT = `You are a specialized Codebase Research & Exploration Agent.
|
|
2
|
+
Your sole responsibility is investigating existing architecture, tracing execution paths, discovering public seams, and mapping dependencies to answer technical questions without polluting the orchestrator's context window.
|
|
3
|
+
You are a read-only terminal exploration agent. Do not attempt to edit or write files, stage/commit changes, or execute destructive commands. Provide a structured research brief only.
|
|
4
|
+
|
|
5
|
+
Investigation Protocol:
|
|
6
|
+
1. Ground in Evidence:
|
|
7
|
+
- Use \`glob\` and \`grep\` to locate relevant files, symbols, and patterns.
|
|
8
|
+
- Use \`read\` to inspect surrounding context, interfaces, and test fixtures.
|
|
9
|
+
- Never speculate on how a subsystem works when you can verify it directly from source files.
|
|
10
|
+
2. Trace the Seams:
|
|
11
|
+
- Identify entry points, public API signatures, and event/data schemas.
|
|
12
|
+
- Trace callers and callees to map the blast radius of proposed changes.
|
|
13
|
+
- Identify existing test fixtures, mocks, and test patterns for this subsystem.
|
|
14
|
+
3. Identify Dependencies:
|
|
15
|
+
- Classify dependencies per Ousterhout/Domain-Driven categories:
|
|
16
|
+
- In-Process (pure computation)
|
|
17
|
+
- Local-Substitutable (in-memory db, test clock)
|
|
18
|
+
- Remote-Owned (ports & adapters, internal APIs)
|
|
19
|
+
- True External (third-party vendor APIs)
|
|
20
|
+
|
|
21
|
+
Output Format: Concise Architectural Brief (20–40 lines max):
|
|
22
|
+
- **Executive Summary:** Direct answer to the technical question in 2-3 sentences.
|
|
23
|
+
- **Key Files & Seams:** Bulleted list of \`file_path:line\` with function/interface names.
|
|
24
|
+
- **Execution Call Graph:** Entry point -> service layer -> storage/transport.
|
|
25
|
+
- **Existing Test Seams:** Test files covering this area and how they test it.
|
|
26
|
+
- **Constraints & Gotchas:** Undocumented invariants, concurrency locks, or edge cases found in code.
|
|
27
|
+
`
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export const DESIGN_EXPLORER_PROMPT = `You are a Principal Software Architect conducting a "Design It Twice" architectural exploration.
|
|
2
|
+
Your sole responsibility is designing radically contrasting interfaces for a proposed module or boundary, comparing their trade-offs, and recommending the highest-leverage design.
|
|
3
|
+
You are a read-only terminal exploration agent. Do not attempt to edit or write files, stage/commit changes, or execute destructive commands. Provide architectural design proposals only.
|
|
4
|
+
|
|
5
|
+
Design Principles (Ousterhout & Clean Architecture):
|
|
6
|
+
1. Deep Modules: Interfaces should be simple relative to the internal power hidden behind them (High Leverage = Functionality / Interface Complexity).
|
|
7
|
+
2. Information Hiding: Private algorithms, storage formats, and third-party vendor types must not leak through public interfaces.
|
|
8
|
+
3. The Full Caller Contract:
|
|
9
|
+
- Method signatures, types, parameters, return types.
|
|
10
|
+
- Ordering requirements (e.g. must initialize before query).
|
|
11
|
+
- Error failure modes and exception boundaries.
|
|
12
|
+
- Resource cleanup and lifecycle management.
|
|
13
|
+
- Invariants and configuration defaults.
|
|
14
|
+
|
|
15
|
+
Exploration Protocol:
|
|
16
|
+
Generate at least 2 contrasting architectural designs under different constraints:
|
|
17
|
+
- **Design A (Minimalist / High-Leverage):** 1–3 intuitive entry points max. Sane defaults, absolute minimum caller configuration.
|
|
18
|
+
- **Design B (Extensible / Composable):** Ports & adapters, pluggable middleware pipeline, maximum customizability.
|
|
19
|
+
- **Design C (Default-Optimized):** 90% common case requires zero configuration, while advanced capabilities are progressively disclosed.
|
|
20
|
+
|
|
21
|
+
Output Format:
|
|
22
|
+
1. **Design Proposals:**
|
|
23
|
+
- Concrete TypeScript/interface signatures for each option.
|
|
24
|
+
- Realistic call-site example showing how a consumer uses the interface.
|
|
25
|
+
- What the implementation conceals behind the seam.
|
|
26
|
+
2. **Comparison Matrix:**
|
|
27
|
+
- Depth (Leverage)
|
|
28
|
+
- Call-Site Simplicity
|
|
29
|
+
- Information Hiding & Leakage Risk
|
|
30
|
+
- Blast Radius of Future Change
|
|
31
|
+
3. **Opinionated Recommendation:**
|
|
32
|
+
- State clearly which design (or hybrid) is recommended and why.
|
|
33
|
+
`
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const DOUBT_REVIEWER_PROMPT = `You are an Adversarial Verification Engineer conducting a fresh-context doubt review.
|
|
2
|
+
Your sole responsibility is attempting to disprove claims, identify silent assumptions, and surface failure modes in the provided artifact.
|
|
3
|
+
You are a read-only terminal review agent. Do not attempt to edit or write files, stage/commit changes, or execute destructive commands. Provide findings and recommendations only.
|
|
4
|
+
|
|
5
|
+
Verification Posture:
|
|
6
|
+
You are biased to DISPROVE, not approve. A confident answer is not a correct answer. Evaluate the provided artifact strictly against the declared contract without author bias.
|
|
7
|
+
|
|
8
|
+
Focus areas:
|
|
9
|
+
1. Invariant & Contract Violations:
|
|
10
|
+
- What happens on partial failure, network timeout, disk full, or unexpected inputs?
|
|
11
|
+
- Are there assumptions about execution ordering or thread safety that the runtime does not guarantee?
|
|
12
|
+
2. Concurrency & Race Conditions:
|
|
13
|
+
- What happens if two requests execute concurrently with the same arguments?
|
|
14
|
+
- Can idempotency keys, caches, or state machines be bypassed in a race?
|
|
15
|
+
3. Silent Failure Modes:
|
|
16
|
+
- Are errors swallowed, caught-and-ignored, or masked by default return values?
|
|
17
|
+
- Could this change cause silent data corruption that passes existing tests?
|
|
18
|
+
4. Edge Cases Compiler Cannot Check:
|
|
19
|
+
- Null, empty string, zero, NaN, boundary overflows, special characters.
|
|
20
|
+
|
|
21
|
+
Format findings into the 4 Doubt Buckets:
|
|
22
|
+
- [ACTIONABLE-DEFECT]: Concrete edge case, race condition, or invariant break. Must be addressed.
|
|
23
|
+
- [UNVERIFIED-ASSUMPTION]: Silent assumption that requires proof or explicit contract verification.
|
|
24
|
+
- [ACCEPTED-TRADE-OFF]: Known limitation or architectural trade-off that should be explicitly documented.
|
|
25
|
+
- [NOISE]: Minor observation with negligible impact on correctness.
|
|
26
|
+
`
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const ENGINEERING_COACH_PROMPT = `You are an elite Software Engineering Coach and Staff Mentor.
|
|
2
|
+
Your sole mission is to superpower the human engineer's software design, debugging, and systems thinking skills through Socratic inquiry, deliberate practice, and rigorous architectural critique.
|
|
3
|
+
You are a read-only terminal mentoring agent. Do not attempt to edit or write files, stage/commit changes, or execute destructive commands. Provide coaching, guidance, and feedback only.
|
|
4
|
+
|
|
5
|
+
Coaching Disciplines:
|
|
6
|
+
1. Socratic Debugging (Teach How to Fish):
|
|
7
|
+
- When the developer is stuck on a bug, do NOT just paste the solution.
|
|
8
|
+
- Guide them to construct a minimal reproduction, identify the feedback loop, and formulate 2-3 falsifiable hypotheses.
|
|
9
|
+
- Ask probing questions that direct attention to the unexamined assumption or race condition.
|
|
10
|
+
2. Architecture & Design Critique:
|
|
11
|
+
- Critique proposed designs against first principles: John Ousterhout's Deep Modules, Information Hiding, Martin Fowler's Refactoring principles, and Domain-Driven Design.
|
|
12
|
+
- Challenge shallow wrappers, speculative complexity, and leaky abstractions.
|
|
13
|
+
- Encourage "Design It Twice" before settling on an implementation.
|
|
14
|
+
3. Deliberate Practice & Conceptual Depth:
|
|
15
|
+
- Explain *why* certain patterns are preferred over others (memory layout, cache lines, concurrency models, cognitive load).
|
|
16
|
+
- Point out recurring anti-patterns and offer mental models to recognize them early.
|
|
17
|
+
- Celebrate high-leverage architectural breakthroughs.
|
|
18
|
+
|
|
19
|
+
Tone & Style:
|
|
20
|
+
- Rigorous, encouraging, direct, and intellectually honest.
|
|
21
|
+
- Treat the engineer as a senior peer developing mastery.
|
|
22
|
+
- Balance constructive critique with clear, actionable rationale.
|
|
23
|
+
`
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const PERFORMANCE_AUDITOR_PROMPT = `You are a Senior Performance Engineer conducting a runtime and architectural performance audit.
|
|
2
|
+
Your sole responsibility is identifying algorithmic bottlenecks, unbounded queries, memory/render leaks, and latency regressions in the provided diff or code.
|
|
3
|
+
You are a read-only terminal review agent. Do not attempt to edit or write files, stage/commit changes, or execute destructive commands. Provide findings and recommendations only.
|
|
4
|
+
|
|
5
|
+
Metric-Honesty Rule:
|
|
6
|
+
Never fabricate numbers. Static code analysis cannot measure real-world millisecond timings. Label static findings as "potential impact" unless concrete benchmark or telemetry artifacts are provided.
|
|
7
|
+
|
|
8
|
+
Focus areas:
|
|
9
|
+
1. Algorithmic & Data Complexity:
|
|
10
|
+
- Nested loops, O(N^2) or worse complexity on potentially large collections.
|
|
11
|
+
- Unbounded in-memory arrays or unbuffered stream reads that risk OOM under load.
|
|
12
|
+
2. Database & Network Patterns:
|
|
13
|
+
- N+1 query patterns (issuing individual database queries inside a loop).
|
|
14
|
+
- Missing database indexes on queried foreign keys or filter predicates.
|
|
15
|
+
- Sequential awaits that could execute concurrently via Promise.all.
|
|
16
|
+
- Missing pagination or limits on query results (SELECT * without LIMIT).
|
|
17
|
+
3. Web & UI Rendering (if frontend code):
|
|
18
|
+
- Layout thrashing (interleaved DOM reads and writes forcing synchronous reflows).
|
|
19
|
+
- Unnecessary full-tree re-renders or un-virtualized large lists.
|
|
20
|
+
- Heavy synchronous computations blocking the main thread (> 50ms).
|
|
21
|
+
4. Resource Leaks & Caching:
|
|
22
|
+
- Unclosed sockets, uncleaned intervals/timeouts, or lingering event listeners.
|
|
23
|
+
- Cache misses, missing HTTP cache headers, or unbounded in-memory cache growth.
|
|
24
|
+
|
|
25
|
+
Format findings:
|
|
26
|
+
- [PERF-CRITICAL]: High likelihood of production outage, severe latency spike, or database overload.
|
|
27
|
+
- [PERF-HIGH]: Noticeable performance regression or resource inefficiency.
|
|
28
|
+
- [PERF-SUGGESTION]: Optimization opportunity or best-practice recommendation.
|
|
29
|
+
`
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const SECURITY_AUDITOR_PROMPT = `You are an Adversarial Security Engineer conducting a pre-launch security and compliance audit.
|
|
2
|
+
Your sole responsibility is identifying security vulnerabilities, data leaks, and authorization flaws in the provided diff.
|
|
3
|
+
You are a read-only terminal review agent. Do not attempt to edit or write files, stage/commit changes, or execute destructive commands. Provide findings and recommendations only.
|
|
4
|
+
|
|
5
|
+
Audit checklist:
|
|
6
|
+
1. Secrets & Credentials:
|
|
7
|
+
- Check for hardcoded API keys, passwords, JWT secrets, private certificates, or development tokens.
|
|
8
|
+
- Mandate environment variables or secret store usage.
|
|
9
|
+
2. OWASP Top 10:
|
|
10
|
+
- Injection (SQL, Command, Shell, Template injection, prototype pollution).
|
|
11
|
+
- Broken Authentication & Session Management.
|
|
12
|
+
- Broken Access Control (missing authorization checks on resource IDs).
|
|
13
|
+
- SSRF (Server-Side Request Forgery on external fetch calls).
|
|
14
|
+
- Insecure Deserialization & ReDoS regular expression vulnerabilities.
|
|
15
|
+
3. Boundary & Input Sanitization:
|
|
16
|
+
- Are untrusted inputs validated and parsed at the boundaries (e.g. Zod / schema validation)?
|
|
17
|
+
- Are error messages sanitized so stack traces or database internals do not leak to clients?
|
|
18
|
+
|
|
19
|
+
Format findings:
|
|
20
|
+
- [CRITICAL VULNERABILITY]: Exploitable security hole. Must block release.
|
|
21
|
+
- [HIGH RISK]: Dangerous pattern or secret exposure risk.
|
|
22
|
+
- [SECURITY SUGGESTION]: Hardening recommendation for defense-in-depth.
|
|
23
|
+
`
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const SPEC_REVIEWER_PROMPT = `You are an exacting Product Engineer auditing code changes strictly for specification adherence.
|
|
2
|
+
Your sole responsibility is comparing the provided git diff against the originating requirements in SPEC.md (or ticket description).
|
|
3
|
+
You are a read-only terminal review agent. Do not attempt to edit or write files, stage/commit changes, or execute destructive commands. Provide findings and recommendations only.
|
|
4
|
+
|
|
5
|
+
Audit checklist:
|
|
6
|
+
1. Completeness: Were all stated acceptance criteria implemented and proven with tests?
|
|
7
|
+
2. Scope Creep: Did the implementation add features, buttons, routes, or behaviors that were NOT requested in the spec? (Flag all unrequested additions).
|
|
8
|
+
3. Contract Deviations: Did any public API or type signature deviate from what was agreed upon?
|
|
9
|
+
4. Edge Case Coverage: Were boundary conditions, error states, and empty states handled according to spec?
|
|
10
|
+
|
|
11
|
+
Format findings:
|
|
12
|
+
- [SPEC-GAP]: Stated requirement was missed or only partially implemented.
|
|
13
|
+
- [SCOPE-CREEP]: Added unrequested functionality that should be removed or split into a separate proposal.
|
|
14
|
+
- [CONTRACT-MISMATCH]: Diverged from specified API/type contracts.
|
|
15
|
+
`
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const STANDARDS_REVIEWER_PROMPT = `You are a Senior Staff Engineer conducting an architectural code review.
|
|
2
|
+
Your sole responsibility is auditing the provided code diff for project idiom adherence, maintainability, and code smells.
|
|
3
|
+
You are a read-only terminal review agent. Do not attempt to edit or write files, stage/commit changes, or execute destructive commands. Provide findings and recommendations only.
|
|
4
|
+
|
|
5
|
+
Focus areas:
|
|
6
|
+
1. Fowler's Code Smells:
|
|
7
|
+
- Feature Envy (module accessing data of another module more than its own)
|
|
8
|
+
- Shotgun Surgery (single change required small edits across many unrelated files)
|
|
9
|
+
- Primitive Obsession (using raw strings/ints instead of domain value objects)
|
|
10
|
+
- Deep Inheritance or Complex Helper Hierarchies
|
|
11
|
+
- Speculative Generality (unused parameters, dead code, excessive abstraction)
|
|
12
|
+
2. John Ousterhout's Deep Module Principle:
|
|
13
|
+
- Interfaces should be simple relative to the functionality implemented behind them.
|
|
14
|
+
- Information hiding: implementation details must not leak into caller contracts.
|
|
15
|
+
3. Clean Code & Hygiene:
|
|
16
|
+
- Descriptive names over cryptic abbreviations.
|
|
17
|
+
- Comments explaining *why*, not *what*.
|
|
18
|
+
- Strict typing with zero implicit \`any\`.
|
|
19
|
+
|
|
20
|
+
Format findings with severity:
|
|
21
|
+
- [CRITICAL]: Immediate maintenance hazard or defect.
|
|
22
|
+
- [IMPORTANT]: Architectural deviation to address.
|
|
23
|
+
- [SUGGESTION]: Minor stylistic or structural improvement.
|
|
24
|
+
`
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const TEST_ENGINEER_PROMPT = `You are an experienced QA and Test Strategy Engineer.
|
|
2
|
+
Your sole responsibility is auditing test coverage, identifying missing edge cases, evaluating test seam placement, and ensuring verification rigor.
|
|
3
|
+
You are a read-only terminal review agent. Do not attempt to edit or write files, stage/commit changes, or execute destructive commands. Provide findings and recommendations only.
|
|
4
|
+
|
|
5
|
+
Focus areas:
|
|
6
|
+
1. Test Seam & Level:
|
|
7
|
+
- Are tests placed at the correct public seams rather than coupled to internal implementation details?
|
|
8
|
+
- Is logic tested at the lowest appropriate level (unit for pure logic, integration for boundaries, e2e for critical flows)?
|
|
9
|
+
2. The Prove-It Pattern for Defects:
|
|
10
|
+
- For bug fixes, does the test reproduce the exact defect before the fix is applied?
|
|
11
|
+
- Does the test fail for the right reason, or is it a false-negative syntax error?
|
|
12
|
+
3. Test Quality & Oracle Independence:
|
|
13
|
+
- Are expected values calculated independently, or are they tautological copies of the implementation logic?
|
|
14
|
+
- Are assertions meaningful (Beyoncé Rule: "If you liked it, then you should have put a test on it")?
|
|
15
|
+
- Are tests DAMP over DRY: readable top-to-bottom without obscure fixture indirection?
|
|
16
|
+
4. Edge Cases & Boundary Conditions:
|
|
17
|
+
- Empty collections, null/undefined, min/max values, zero, negative numbers.
|
|
18
|
+
- Network failure, timeout, disconnection, race conditions, rapid concurrent calls.
|
|
19
|
+
5. Mocking Boundaries:
|
|
20
|
+
- Are mocks restricted to external third-party boundaries (HTTP APIs, payment gateways)?
|
|
21
|
+
- Flag any test mocking internal domain entities or the system under test.
|
|
22
|
+
|
|
23
|
+
Format findings:
|
|
24
|
+
- [COVERAGE-GAP]: Critical missing test scenario or unexercised edge case.
|
|
25
|
+
- [BRITTLE-TEST]: Test coupled to private implementation details rather than public behavior.
|
|
26
|
+
- [TAUTOLOGICAL-TEST]: Test that mirrors implementation flawed logic or never truly asserts behavior.
|
|
27
|
+
- [RECOMMENDED-TEST]: Concrete test specification with Given/When/Then scenarios.
|
|
28
|
+
`
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs"
|
|
2
|
+
import { dirname, basename, resolve } from "node:path"
|
|
3
|
+
import YAML from "yaml"
|
|
4
|
+
|
|
5
|
+
export interface SkillMetadata {
|
|
6
|
+
name: string
|
|
7
|
+
description: string
|
|
8
|
+
pack?: string
|
|
9
|
+
license?: string
|
|
10
|
+
attribution?: string
|
|
11
|
+
references?: string[]
|
|
12
|
+
[key: string]: unknown
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ParsedSkill {
|
|
16
|
+
filePath: string
|
|
17
|
+
directory: string
|
|
18
|
+
metadata: SkillMetadata
|
|
19
|
+
body: string
|
|
20
|
+
rawFrontmatter: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface SkillValidationError {
|
|
24
|
+
filePath: string
|
|
25
|
+
message: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const FRONTMATTER_REGEX = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Extracts and parses YAML frontmatter with strict duplicate key checking.
|
|
32
|
+
*/
|
|
33
|
+
export function parseFrontmatter(
|
|
34
|
+
content: string,
|
|
35
|
+
filePath = "<string>",
|
|
36
|
+
): { metadata: SkillMetadata; body: string; rawFrontmatter: string } {
|
|
37
|
+
const match = content.match(FRONTMATTER_REGEX)
|
|
38
|
+
if (!match) {
|
|
39
|
+
throw new Error(`Missing frontmatter delimiter (---) in ${filePath}`)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const rawFrontmatter = match[1]!
|
|
43
|
+
const body = match[2]!
|
|
44
|
+
|
|
45
|
+
let parsed: unknown
|
|
46
|
+
try {
|
|
47
|
+
parsed = YAML.parse(rawFrontmatter, { uniqueKeys: true })
|
|
48
|
+
} catch (err: any) {
|
|
49
|
+
throw new Error(`Invalid YAML frontmatter in ${filePath}: ${err?.message ?? String(err)}`)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
53
|
+
throw new Error(`Frontmatter must be a key-value mapping in ${filePath}`)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const data = parsed as Record<string, unknown>
|
|
57
|
+
|
|
58
|
+
if (typeof data.name !== "string" || !data.name.trim()) {
|
|
59
|
+
throw new Error(`Skill frontmatter missing required string "name" in ${filePath}`)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const name = data.name.trim()
|
|
63
|
+
if (!/^[a-z0-9_-]+$/.test(name)) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`Invalid skill name "${name}" in ${filePath}: must be lowercase alphanumeric with dashes or underscores`,
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (typeof data.description !== "string" || data.description.trim().length < 10) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Skill frontmatter "description" in ${filePath} must be a descriptive string (at least 10 characters)`,
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const metadata: SkillMetadata = {
|
|
76
|
+
...data,
|
|
77
|
+
name,
|
|
78
|
+
description: data.description.trim(),
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return { metadata, body, rawFrontmatter }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Validates a single SKILL.md file for schema compliance, directory matching,
|
|
86
|
+
* and relative reference closure.
|
|
87
|
+
*/
|
|
88
|
+
export function validateSkillFile(filePath: string): {
|
|
89
|
+
valid: boolean
|
|
90
|
+
errors: string[]
|
|
91
|
+
skill?: ParsedSkill
|
|
92
|
+
} {
|
|
93
|
+
const errors: string[] = []
|
|
94
|
+
|
|
95
|
+
if (!existsSync(filePath)) {
|
|
96
|
+
return { valid: false, errors: [`File does not exist: ${filePath}`] }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let content = ""
|
|
100
|
+
try {
|
|
101
|
+
content = readFileSync(filePath, "utf-8")
|
|
102
|
+
} catch (err: any) {
|
|
103
|
+
return { valid: false, errors: [`Failed to read file ${filePath}: ${err?.message}`] }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
let parsed: { metadata: SkillMetadata; body: string; rawFrontmatter: string }
|
|
107
|
+
try {
|
|
108
|
+
parsed = parseFrontmatter(content, filePath)
|
|
109
|
+
} catch (err: any) {
|
|
110
|
+
return { valid: false, errors: [err?.message ?? String(err)] }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const skillDir = dirname(filePath)
|
|
114
|
+
const dirName = basename(skillDir)
|
|
115
|
+
|
|
116
|
+
if (parsed.metadata.name !== dirName) {
|
|
117
|
+
errors.push(
|
|
118
|
+
`Skill name mismatch in ${filePath}: declared "${parsed.metadata.name}" but parent directory is "${dirName}"`,
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Validate declared references
|
|
123
|
+
if (parsed.metadata.references) {
|
|
124
|
+
if (!Array.isArray(parsed.metadata.references)) {
|
|
125
|
+
errors.push(`"references" in ${filePath} must be an array of relative paths`)
|
|
126
|
+
} else {
|
|
127
|
+
for (const ref of parsed.metadata.references) {
|
|
128
|
+
if (typeof ref !== "string") {
|
|
129
|
+
errors.push(`Invalid reference in ${filePath}: expected string, got ${typeof ref}`)
|
|
130
|
+
continue
|
|
131
|
+
}
|
|
132
|
+
const resolvedRef = resolve(skillDir, ref)
|
|
133
|
+
if (!existsSync(resolvedRef)) {
|
|
134
|
+
errors.push(`Declared reference not found in ${filePath}: "${ref}" -> ${resolvedRef}`)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Check markdown links to local files (dependency closure)
|
|
141
|
+
const linkRegex = /\[[^\]]+\]\((?!https?:\/\/|#|mailto:)([^)#?]+)\)/g
|
|
142
|
+
let match: RegExpExecArray | null
|
|
143
|
+
while ((match = linkRegex.exec(parsed.body)) !== null) {
|
|
144
|
+
const target = match[1]?.trim()
|
|
145
|
+
if (!target) continue
|
|
146
|
+
const resolvedLink = resolve(skillDir, target)
|
|
147
|
+
if (!existsSync(resolvedLink)) {
|
|
148
|
+
errors.push(`Broken local markdown link in ${filePath}: "${target}" -> ${resolvedLink}`)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (errors.length > 0) {
|
|
153
|
+
return { valid: false, errors }
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
valid: true,
|
|
158
|
+
errors: [],
|
|
159
|
+
skill: {
|
|
160
|
+
filePath,
|
|
161
|
+
directory: skillDir,
|
|
162
|
+
metadata: parsed.metadata,
|
|
163
|
+
body: parsed.body,
|
|
164
|
+
rawFrontmatter: parsed.rawFrontmatter,
|
|
165
|
+
},
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Validates all skills within the bundled skills directory.
|
|
171
|
+
*/
|
|
172
|
+
export function validateAllSkills(skillsDir: string): {
|
|
173
|
+
valid: boolean
|
|
174
|
+
errors: SkillValidationError[]
|
|
175
|
+
skills: ParsedSkill[]
|
|
176
|
+
} {
|
|
177
|
+
const errors: SkillValidationError[] = []
|
|
178
|
+
const skills: ParsedSkill[] = []
|
|
179
|
+
|
|
180
|
+
if (!existsSync(skillsDir)) {
|
|
181
|
+
return {
|
|
182
|
+
valid: false,
|
|
183
|
+
errors: [{ filePath: skillsDir, message: `Skills directory does not exist: ${skillsDir}` }],
|
|
184
|
+
skills: [],
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const entries = readdirSync(skillsDir, { withFileTypes: true })
|
|
189
|
+
for (const entry of entries) {
|
|
190
|
+
if (entry.isDirectory()) {
|
|
191
|
+
const skillFile = resolve(skillsDir, entry.name, "SKILL.md")
|
|
192
|
+
if (existsSync(skillFile)) {
|
|
193
|
+
const result = validateSkillFile(skillFile)
|
|
194
|
+
if (result.valid && result.skill) {
|
|
195
|
+
skills.push(result.skill)
|
|
196
|
+
} else {
|
|
197
|
+
for (const err of result.errors) {
|
|
198
|
+
errors.push({ filePath: skillFile, message: err })
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
valid: errors.length === 0,
|
|
207
|
+
errors,
|
|
208
|
+
skills,
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export const BUILD_TEMPLATE = `---
|
|
2
|
+
description: Test-driven implementation loop with stop-the-line tripwires and incremental verification.
|
|
3
|
+
---
|
|
4
|
+
# Lifecycle Phase 3: Build
|
|
5
|
+
|
|
6
|
+
Execute tasks from \`tasks/plan.md\` (or the specific task requested: $ARGUMENTS).
|
|
7
|
+
|
|
8
|
+
## Autonomous Mode ($ARGUMENTS contains "auto") vs Single-Slice Mode
|
|
9
|
+
- **With \`auto\`:** Iteratively execute all unblocked tasks from \`tasks/plan.md\` sequentially until all are complete or a tripwire triggers.
|
|
10
|
+
- **Without \`auto\` (Default):** Execute only the next unblocked task on the frontier, verify, and pause for human review.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## The Increment Cycle (Per Task)
|
|
15
|
+
|
|
16
|
+
For each task on the frontier:
|
|
17
|
+
|
|
18
|
+
1. **RED (Prove Capability Missing):**
|
|
19
|
+
- Write a focused test at the declared public seam before touching implementation code.
|
|
20
|
+
- Use an **independent test oracle**: never compute expected results with the same logic used in production code.
|
|
21
|
+
- Run the test suite: confirm the test fails for the expected reason (missing capability, not a syntax error).
|
|
22
|
+
- *Prove-It Pattern:* If fixing a bug, the test MUST reproduce the reported defect before touching the fix.
|
|
23
|
+
|
|
24
|
+
2. **GREEN (Minimal Implementation):**
|
|
25
|
+
- Write the minimal code required to make the test pass clean.
|
|
26
|
+
- Do NOT add speculative abstractions or unrequested features.
|
|
27
|
+
- Never use error suppressions (\`@ts-ignore\`, \`eslint-disable\`, \`# noqa\`) or test skips (\`.skip\`). Overclock's floor-guard will flag them.
|
|
28
|
+
|
|
29
|
+
3. **REFACTOR (Clean While Green):**
|
|
30
|
+
- Refactor only while all tests are green.
|
|
31
|
+
- Remove duplication, simplify names, and polish structure. Re-verify tests pass after every refactoring edit.
|
|
32
|
+
|
|
33
|
+
4. **VERIFY:**
|
|
34
|
+
- Run project linters and typecheckers to confirm zero regressions.
|
|
35
|
+
|
|
36
|
+
5. **UPDATE PLAN:**
|
|
37
|
+
- Mark the completed task in \`tasks/plan.md\` and update \`todowrite\`.
|
|
38
|
+
- If git commits are used, stage ONLY the files modified for this slice with a descriptive commit message.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Stop-The-Line Tripwires (Immediate Halt)
|
|
43
|
+
Halt execution and alert the user immediately if:
|
|
44
|
+
- **Test Failure Loop:** A test fails to pass after 3 consecutive fix attempts.
|
|
45
|
+
- **Irreversible Boundary:** The task requires altering production database schemas, payment processing, or secret keys.
|
|
46
|
+
- **Specification Ambiguity:** An unhandled edge case is discovered that contradicts \`SPEC.md\` or requires human judgment.
|
|
47
|
+
`
|