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.
Files changed (82) hide show
  1. package/README.md +252 -111
  2. package/package.json +6 -4
  3. package/skills/codebase-design/DEEPENING.md +35 -0
  4. package/skills/codebase-design/DESIGN-IT-TWICE.md +34 -0
  5. package/skills/codebase-design/SKILL.md +93 -0
  6. package/skills/diagnosing-bugs/SKILL.md +123 -0
  7. package/skills/domain-modeling/ADR-FORMAT.md +55 -0
  8. package/skills/domain-modeling/CONTEXT-FORMAT.md +32 -0
  9. package/skills/domain-modeling/SKILL.md +102 -0
  10. package/skills/doubt/SKILL.md +80 -0
  11. package/skills/grilling/SKILL.md +96 -0
  12. package/skills/source-discipline/SKILL.md +78 -0
  13. package/skills/tdd/SKILL.md +87 -0
  14. package/skills/to-spec/SKILL.md +69 -0
  15. package/skills/to-spec/SPEC-TEMPLATE.md +50 -0
  16. package/skills/to-tickets/SKILL.md +74 -0
  17. package/skills/to-tickets/TICKET-TEMPLATE.md +41 -0
  18. package/src/bridge.ts +1 -0
  19. package/src/buddy/companion.ts +104 -5
  20. package/src/buddy/sprites.ts +4 -4
  21. package/src/buddy/tui.ts +175 -65
  22. package/src/core/bridge.ts +34 -0
  23. package/src/core/lifecycle.ts +67 -0
  24. package/src/core/policy.ts +128 -0
  25. package/src/core/summary.ts +33 -0
  26. package/src/core/types.ts +193 -0
  27. package/src/features/buddy.ts +1 -2
  28. package/src/features/guard.ts +421 -37
  29. package/src/features/index.ts +18 -4
  30. package/src/features/recovery.ts +153 -0
  31. package/src/features/safety.ts +147 -0
  32. package/src/features/sched.ts +183 -89
  33. package/src/features/tasks.ts +134 -33
  34. package/src/features/truncator.ts +116 -0
  35. package/src/features/usage.ts +46 -65
  36. package/src/features/workflow.ts +256 -0
  37. package/src/index.ts +96 -67
  38. package/src/lib/busy.ts +1 -25
  39. package/src/lib/exec.ts +13 -0
  40. package/src/lib/inject.ts +10 -56
  41. package/src/lib/mirror.ts +13 -0
  42. package/src/lib/probe.ts +1 -15
  43. package/src/lib/state.ts +10 -39
  44. package/src/lib/tmux.ts +1 -0
  45. package/src/lib/ui.ts +208 -0
  46. package/src/merge.ts +2 -66
  47. package/src/platform/probe.ts +25 -0
  48. package/src/platform/process/exec.ts +317 -0
  49. package/src/platform/process/tmux.ts +60 -0
  50. package/src/platform/session/busy.ts +33 -0
  51. package/src/platform/session/inject.ts +89 -0
  52. package/src/platform/session/notify.ts +20 -0
  53. package/src/platform/storage/state.ts +99 -0
  54. package/src/platform/storage/store.ts +61 -0
  55. package/src/summary.ts +1 -0
  56. package/src/tools.ts +8 -244
  57. package/src/tui.ts +57 -186
  58. package/src/types.ts +1 -73
  59. package/src/v2/context.ts +470 -0
  60. package/src/v2/host.ts +120 -0
  61. package/src/v2/loader.ts +150 -0
  62. package/src/workflow/agents/codebase-researcher.ts +27 -0
  63. package/src/workflow/agents/design-explorer.ts +33 -0
  64. package/src/workflow/agents/doubt-reviewer.ts +26 -0
  65. package/src/workflow/agents/engineering-coach.ts +23 -0
  66. package/src/workflow/agents/performance-auditor.ts +29 -0
  67. package/src/workflow/agents/security-auditor.ts +23 -0
  68. package/src/workflow/agents/spec-reviewer.ts +15 -0
  69. package/src/workflow/agents/standards-reviewer.ts +24 -0
  70. package/src/workflow/agents/test-engineer.ts +28 -0
  71. package/src/workflow/catalog.ts +210 -0
  72. package/src/workflow/templates/build.ts +47 -0
  73. package/src/workflow/templates/define.ts +45 -0
  74. package/src/workflow/templates/diagnose.ts +58 -0
  75. package/src/workflow/templates/plan.ts +52 -0
  76. package/src/workflow/templates/ship.ts +64 -0
  77. package/src/buddy/reactions.ts +0 -41
  78. package/src/buddy/types.ts +0 -30
  79. package/src/config.ts +0 -19
  80. package/src/features/checkpoints.ts +0 -128
  81. package/src/features/sandbox.ts +0 -104
  82. package/src/validate.ts +0 -197
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: to-spec
3
+ description: Synthesizes conversation context and requirements into a structured specification without reopening interviews. Use when requirements have been discussed and agreed upon, and you need to document the formal spec.
4
+ pack: core
5
+ license: MIT
6
+ attribution: Adapted from mattpocock/skills (MIT License)
7
+ references:
8
+ - SPEC-TEMPLATE.md
9
+ ---
10
+
11
+ # To Spec: Requirements Synthesis
12
+
13
+ Transform agreed conversation context, architecture boundaries, and requirements into a clear, testable specification.
14
+
15
+ ## Core Rule: No Renewed Interview
16
+
17
+ Do **NOT** reopen the interview loop. The time for grilling was during requirements elicitation (`grilling`). Now is the time for **synthesis**: consolidate what has already been agreed upon into an actionable document.
18
+
19
+ - Only pause to confirm testing seams if multiple viable seams exist.
20
+ - Do not ask open-ended questions about things already discussed.
21
+
22
+ ## When to Use
23
+
24
+ - Requirements have been gathered and agreed upon (e.g. following a grilling session).
25
+ - Drafting `SPEC.md` or updating an existing project specification.
26
+ - Translating high-level feature requests into concrete acceptance criteria and seams.
27
+
28
+ ## When NOT to Use
29
+
30
+ - Requirements are still vague or contradictory (use `grilling` first).
31
+ - Decomposing an already completed spec into executable tasks (use `to-tickets` instead).
32
+
33
+ ---
34
+
35
+ ## Synthesis Process
36
+
37
+ ### 1. Survey Codebase Context & Conventions
38
+
39
+ Inspect existing code to ground the spec:
40
+
41
+ - Check existing ubiquitous language (`CONTEXT.md`).
42
+ - Respect any relevant Architecture Decision Records (`docs/adr/`).
43
+ - Identify established test patterns and libraries in the repository.
44
+
45
+ ### 2. Identify the Public Testing Seams
46
+
47
+ Determine the cleanest boundaries at which automated tests will verify the feature:
48
+
49
+ - **Prefer existing seams:** Use existing module interfaces or API endpoints rather than creating artificial test-only hooks.
50
+ - **Prefer high seams:** Test through the public interface of the module or service.
51
+ - **Fewer seams is better:** The ideal number of external test seams across a feature is one or two.
52
+
53
+ Check with the user that the selected test seams match expectations before finalizing the document.
54
+
55
+ ### 3. Draft the Specification
56
+
57
+ Write `SPEC.md` (or the project's designated spec location) using the structured format in [SPEC-TEMPLATE.md](SPEC-TEMPLATE.md):
58
+
59
+ - **Problem Statement & Solution:** User-perspective framing.
60
+ - **Ubiquitous Language:** Canonical names and entities.
61
+ - **User Stories:** Extensive, numbered list with verifiable acceptance criteria.
62
+ - **Public Seams & Interfaces:** Explicit signatures, types, and invariants.
63
+ - **3-Tier Boundaries:** Always Do / Ask First / Never Do.
64
+ - **Out of Scope:** Concrete non-goals preventing scope creep.
65
+ - **Verification Strategy:** Automated commands that prove completion.
66
+
67
+ ### 4. Present for Confirmation
68
+
69
+ Present the synthesized specification to the human architect for approval. Once confirmed, proceed to task decomposition via `to-tickets`.
@@ -0,0 +1,50 @@
1
+ # Specification Template
2
+
3
+ ```markdown
4
+ # Specification: [Feature Name]
5
+
6
+ ## 1. Problem Statement
7
+
8
+ The problem that the user or system is facing, stated from the user's perspective. What friction, limitation, or deficiency currently exists?
9
+
10
+ ## 2. Proposed Solution
11
+
12
+ The high-level solution and intended user experience. How does this resolve the problem statement?
13
+
14
+ ## 3. Ubiquitous Language & Entities
15
+
16
+ Key terms defined precisely (referencing `CONTEXT.md` where established).
17
+
18
+ - **[Entity 1]:** [Definition]
19
+ - **[Entity 2]:** [Definition]
20
+
21
+ ## 4. User Stories & Acceptance Criteria
22
+
23
+ Numbered list of user stories covering all functional aspects:
24
+
25
+ 1. **As a** [actor], **I want** [capability], **so that** [outcome/benefit].
26
+ - **Given:** [initial state]
27
+ - **When:** [action taken]
28
+ - **Then:** [expected verifiable outcome]
29
+
30
+ ## 5. Public Seams & Interfaces
31
+
32
+ Explicit declarations of public types, API endpoints, function signatures, or CLI contracts:
33
+
34
+ - Prefer existing high-level seams over creating new low-level seams.
35
+ - Document inputs, outputs, errors, and invariants.
36
+
37
+ ## 6. 3-Tier Boundaries
38
+
39
+ - **Always Do:** Non-negotiables (invariants, validations, mandatory logging).
40
+ - **Ask First:** Irreversible actions requiring explicit human confirmation.
41
+ - **Never Do:** Prohibited patterns or anti-patterns.
42
+
43
+ ## 7. Out of Scope (Non-Goals)
44
+
45
+ Explicit list of items intentionally excluded from this increment.
46
+
47
+ ## 8. Verification Strategy
48
+
49
+ How the feature will be proven before merging (unit tests, integration smoke tests, automated reproduction commands).
50
+ ```
@@ -0,0 +1,74 @@
1
+ ---
2
+ name: to-tickets
3
+ description: Decomposes a specification or plan into a directed acyclic graph (DAG) of independently verifiable, tracer-bullet tasks. Use when planning implementation steps from a spec or readying work for execution.
4
+ pack: core
5
+ license: MIT
6
+ attribution: Adapted from mattpocock/skills (MIT License)
7
+ references:
8
+ - TICKET-TEMPLATE.md
9
+ ---
10
+
11
+ # To Tickets: Task Decomposition & Dependency Planning
12
+
13
+ Decompose a specification, feature plan, or design into an executable dependency DAG of **tracer-bullet tasks**.
14
+
15
+ ## Core Principles
16
+
17
+ ### 1. Vertical Tracer Bullets vs Horizontal Layers
18
+
19
+ - **Anti-pattern (Horizontal Slicing):** "Task 1: Build all database tables; Task 2: Build all API routes; Task 3: Build UI." Slices cannot be tested end-to-end, defer integration risks to the end, and leave software broken between steps.
20
+ - **Tracer Bullet (Vertical Slicing):** Each task cuts a narrow but COMPLETE path through schema, logic, interface, and tests. Each completed task delivers working, verifiable software at that seam.
21
+
22
+ ### 2. Context-Sized Increments
23
+
24
+ - Size each increment so it can be implemented, verified, and reasoned about within a single, fresh context window.
25
+ - Thin increments (~50-150 lines of focused diff) minimize regression risk and make rollbacks trivial.
26
+
27
+ ### 3. Explicit Blocking Edges & The Ready Frontier
28
+
29
+ - Every task explicitly declares its prerequisite blockers: `Blocked By: [Task IDs]`.
30
+ - Tasks with no blockers form the **Ready Frontier** and can be worked on immediately or in parallel.
31
+ - Maintain an accurate DAG so tasks are never started before their true foundations exist.
32
+
33
+ ### 4. The Wide-Refactor Exception: Expand-and-Contract
34
+
35
+ A **wide refactor** (e.g. renaming a ubiquitous column, changing a core function signature used across hundreds of files) cannot be landed in a single vertical slice without breaking the entire test suite.
36
+
37
+ Do NOT force wide refactors into single tracer bullets. Sequence them as **Expand-and-Contract**:
38
+
39
+ 1. **Expand:** Introduce the new interface or column alongside the old one. Both exist simultaneously; existing tests remain green.
40
+ 2. **Migrate:** Migrate callers in bounded batches (by directory or module). Each batch is an independent task blocked by Expand, keeping CI green at every step.
41
+ 3. **Contract:** Once all callers use the new interface, delete the old implementation and remove deprecation warnings. Blocked by all migration batches.
42
+ 4. _(Optional)_ When intermediate batches cannot stay green in isolation, execute on a dedicated integration branch with a final integrate-and-verify gate.
43
+
44
+ ---
45
+
46
+ ## The Decomposition Process
47
+
48
+ ### 1. Prefactoring First
49
+
50
+ Look for opportunities to refactor existing code before adding new logic:
51
+
52
+ > _"Make the change easy, then make the easy change."_ (Kent Beck)
53
+ > If prefactoring is needed, make it Task 1 on the frontier.
54
+
55
+ ### 2. Draft Tasks with Public Seams
56
+
57
+ For each task, define:
58
+
59
+ - **Title:** Concise imperative action.
60
+ - **Blocked By:** Explicit prerequisites.
61
+ - **Seam:** File path to the automated test suite or verification assertion that will prove completion.
62
+ - **Acceptance Criteria:** Verifiable conditions satisfying requirements.
63
+
64
+ ### 3. Output Location
65
+
66
+ By default, output the plan to `tasks/plan.md` in the workspace using the format in [TICKET-TEMPLATE.md](TICKET-TEMPLATE.md). If integrated with an external issue tracker (GitHub, Linear), format each task as an issue and link blocking dependencies.
67
+
68
+ ### 4. Confirm with Human Architect
69
+
70
+ Present the task breakdown to the user. Confirm:
71
+
72
+ - Granularity: Are any tasks too large or too trivial?
73
+ - Blocking Edges: Are dependencies minimal and strictly gating?
74
+ - Once confirmed, proceed to execution via `/build` or the `tdd` skill.
@@ -0,0 +1,41 @@
1
+ # Ticket & Plan Templates
2
+
3
+ ## Single Task Format (Markdown)
4
+
5
+ ```markdown
6
+ ### [TASK-NN]: [Concise Title in Imperative Mood]
7
+
8
+ - **Blocked By:** [TASK-XX, TASK-YY | None (Can start immediately)]
9
+ - **Seam:** [File path to test file, e.g. tests/unit/auth-token.test.ts]
10
+ - **Deliverable:** The end-to-end behavior this task makes work from the caller's perspective.
11
+ - **Acceptance Criteria:**
12
+ - [ ] Automated test at seam fails before implementation (Red).
13
+ - [ ] Implementation passes test without skips or suppressions (Green).
14
+ - [ ] Linters and typechecks pass clean.
15
+ ```
16
+
17
+ ---
18
+
19
+ ## Tasks Plan Document (`tasks/plan.md`)
20
+
21
+ ```markdown
22
+ # Implementation Plan: [Feature Name]
23
+
24
+ ## Frontier (Ready to Execute)
25
+
26
+ Tasks whose dependencies are completely satisfied.
27
+
28
+ - [ ] **Task 1: [Title]**
29
+ - **Blocked By:** None
30
+ - **Seam:** `test/feature-core.test.ts`
31
+ - **Scope:** [Description of vertical slice]
32
+
33
+ ## Sequence (Blocked)
34
+
35
+ Tasks waiting on prerequisite tasks.
36
+
37
+ - [ ] **Task 2: [Title]**
38
+ - **Blocked By:** Task 1
39
+ - **Seam:** `test/feature-api.test.ts`
40
+ - **Scope:** [Description of vertical slice]
41
+ ```
package/src/bridge.ts ADDED
@@ -0,0 +1 @@
1
+ export { createHybridPlugin, type HybridPlugin, type HybridPluginDefinition } from "./core/bridge.ts"
@@ -1,4 +1,74 @@
1
- import { SPECIES, type Companion, type CompanionStats, type Rarity } from "./types.ts"
1
+ import type { SpriteState } from "./sprites.ts"
2
+
3
+ export const SPECIES = [
4
+ "cat",
5
+ "dog",
6
+ "bunny",
7
+ "owl",
8
+ "bat",
9
+ "penguin",
10
+ "duck",
11
+ "ghost",
12
+ "slime",
13
+ ] as const
14
+ export type Species = (typeof SPECIES)[number]
15
+
16
+ export type Rarity = "common" | "uncommon" | "rare" | "legendary"
17
+
18
+ export interface CompanionStats {
19
+ patience: number
20
+ chaos: number
21
+ wisdom: number
22
+ snark: number
23
+ }
24
+
25
+ export interface Companion {
26
+ species: Species
27
+ rarity: Rarity
28
+ name: string
29
+ stats: CompanionStats
30
+ hatchedAt: number
31
+ }
32
+
33
+ export type ReactionKind = "done" | "error" | "permission" | "question" | "pet"
34
+
35
+ /** Speech-bubble line + which face the sprite pulls while it shows. */
36
+ export interface Reaction {
37
+ text: string
38
+ state: SpriteState
39
+ }
40
+
41
+ // Lines render into the sprite's 12-col effect row -- keep every line <= 12 chars.
42
+ const POOLS: Record<ReactionKind, { lines: string[]; state: SpriteState }> = {
43
+ done: { lines: ["cooked", "ate that", "big W", "say less", "we ball"], state: "idle" },
44
+ error: { lines: ["bruh", "ur cooked", "skill issue", "aint no way", "big L"], state: "alarmed" },
45
+ permission: { lines: ["let me cook", "valid?", "we good?", "bet?", "vibe check"], state: "curious" },
46
+ question: { lines: ["wym?", "the move?", "u tell me", "spill", "hbu?"], state: "curious" },
47
+ pet: { lines: ["pookie!", "w rizz", "ur valid", "slay", "ily"], state: "pet" },
48
+ }
49
+
50
+ /** Pure: pick a random line for a reaction kind. */
51
+ export function pickReaction(kind: ReactionKind, rng: () => number = Math.random): Reaction {
52
+ const pool = POOLS[kind]
53
+ return { text: pool.lines[Math.floor(rng() * pool.lines.length)]!, state: pool.state }
54
+ }
55
+
56
+ export interface ReactionGate {
57
+ /** True + arms the cooldown if enough time has passed since the last fire. */
58
+ tryFire(now?: number): boolean
59
+ }
60
+
61
+ /** Debounce for event-driven reactions -- keeps a busy session from spamming the bubble. */
62
+ export function createReactionGate(cooldownMs = 8000): ReactionGate {
63
+ let last = -Infinity
64
+ return {
65
+ tryFire(now: number = Date.now()): boolean {
66
+ if (now - last < cooldownMs) return false
67
+ last = now
68
+ return true
69
+ },
70
+ }
71
+ }
2
72
 
3
73
  const RARITY_WEIGHTS: { rarity: Rarity; weight: number }[] = [
4
74
  { rarity: "common", weight: 60 },
@@ -55,16 +125,45 @@ function rollStat(rng: () => number): number {
55
125
  }
56
126
 
57
127
  /**
58
- * Companions persist in TUI kv and outlive the sprite sheet, so an install that
59
- * hatched a species we have since retired would look it up and find no art. Move
60
- * it onto a species we still draw, keeping the identity that isn't the drawing:
61
- * same name, rarity, stats and hatch date. Returns undefined when nothing to do.
128
+ * Move companion onto an active species if its hatched species was retired.
62
129
  */
63
130
  export function migrateSpecies(c: Companion, rng: () => number = Math.random): Companion | undefined {
64
131
  if ((SPECIES as readonly string[]).includes(c.species)) return undefined
65
132
  return { ...c, species: pick(rng, SPECIES) }
66
133
  }
67
134
 
135
+ /** Short character descriptions for each species based on their idle fidget. */
136
+ export const SPECIES_DESCRIPTIONS: Record<Species, string> = {
137
+ cat: "tail flick",
138
+ dog: "ear perk",
139
+ bunny: "ear wiggle",
140
+ owl: "feather ruffle",
141
+ bat: "wing beat",
142
+ penguin: "waddle",
143
+ duck: "ripples",
144
+ ghost: "float",
145
+ slime: "squash",
146
+ }
147
+
148
+ /** Pure: formatted description for dialog options. */
149
+ export function speciesDescription(species: Species, isCurrent = false): string {
150
+ const desc = SPECIES_DESCRIPTIONS[species] ?? species
151
+ return isCurrent ? `${desc} (current)` : desc
152
+ }
153
+
154
+ /** Move companion to a new species, preserving name, stats, and hatchedAt. */
155
+ export function switchSpecies(c: Companion, species: Species): Companion {
156
+ if (!(SPECIES as readonly string[]).includes(species)) return c
157
+ return { ...c, species }
158
+ }
159
+
160
+ /** Pure: get the next species in the SPECIES rotation. */
161
+ export function cycleSpecies(current: Species): Species {
162
+ const idx = SPECIES.indexOf(current)
163
+ if (idx === -1) return SPECIES[0]
164
+ return SPECIES[(idx + 1) % SPECIES.length]!
165
+ }
166
+
68
167
  /** One-line card for the /oc-buddy toast. */
69
168
  export function describeCompanion(c: Companion): string {
70
169
  const s = c.stats
@@ -1,4 +1,4 @@
1
- import type { Species } from "./types.ts"
1
+ import type { Species } from "./companion.ts"
2
2
 
3
3
  /**
4
4
  * Every frame is padded to exactly SPRITE_WIDTH columns so animation never
@@ -35,8 +35,8 @@ interface SpeciesArt {
35
35
  /**
36
36
  * Which of the two poses a tick shows. Per-species on purpose: alternating
37
37
  * every tick reads as a strobe, and it makes every species move alike. A cat
38
- * flicks its tail rarely, a dog wags nonstop, a dragon's wingbeat is slow and
39
- * held at the top, a ghost never quite lands.
38
+ * flicks its tail rarely, a dog wags nonstop, a bat's wingbeat flutters rapidly,
39
+ * a ghost never quite lands.
40
40
  */
41
41
  beat: (t: number) => 0 | 1
42
42
  }
@@ -148,7 +148,7 @@ export function withBubble(frame: string, bubble: string | undefined): string {
148
148
  /** Pure: render one frame. `tick` drives idle fidget + blink; other states are static. */
149
149
  export function spriteFrame(species: Species, state: SpriteState, tick: number): string {
150
150
  const art = ART[species]
151
- const t = ((tick % 1000) + 1000) % 1000
151
+ const t = Math.max(0, tick)
152
152
  const body = art.idle[art.beat(t)]!
153
153
  const rest = art.idle[0]!
154
154