Skip to content

Commit 6e1b0e1

Browse files
anandgupta42claude
andcommitted
feat: add Kit system — shareable bundles of skills, MCP servers, and instructions
Introduces the Kit extension system that enables anyone — vendors, solution architects, team leads, individual engineers — to create and distribute shareable development setups. ## What's included **Core runtime** (`packages/opencode/src/kit/`): - `Kit` namespace with Zod schemas, state management, YAML loading - Trust tiers (`built-in`, `verified`, `community`) - Skill packs with activation modes (`always`, `detect`, `manual`) - Activate/deactivate lifecycle with full cleanup **11 CLI commands** (`packages/opencode/src/cli/cmd/kit.ts`): - `kit list`, `kit create`, `kit show`, `kit install`, `kit remove` - `kit activate` — one command: installs skills, configures MCP, enables - `kit deactivate` — clean removal (instructions + MCP config + active-kits) - `kit detect`, `kit search`, `kit status`, `kit validate` **TUI startup nudge** (`packages/opencode/src/cli/cmd/tui/thread.ts`): - Non-blocking detection on TUI startup - Shows one-line suggestion when matching kits found **JSONC-preserving config writes**: - Uses `jsonc-parser` `modify`/`applyEdits` to preserve user comments - MCP servers added on activate, removed on deactivate **Documentation** (`docs/`): - User guide: `docs/docs/configure/kits.md` (CLI reference, locations, tiers) - Author guide: `docs/docs/develop/kits.md` (full schema, tutorial, examples) - Ecosystem plan: `docs/PARTNER_ECOSYSTEM_PLAN.md` (strategy + simulation results) - Roadmap with planned features (`kit switch`, inheritance, `kit enforce`) ## Testing - 60/60 automated E2E tests passing (name validation, activate/deactivate lifecycle, MCP merge, JSONC preservation, detect, validate, install) - 10 stakeholder simulations across 5 scenarios (Snowflake, Dagster, dbt Labs, Airbyte, Healthcare, MSP consulting, OSS contributor, self-serve, enterprise) - 29 bugs found and fixed across 3 review rounds ## External - Kit content lives in `AltimateAI/data-engineering-skills` (merged PR #9) - Registry at `data-engineering-skills/registry.json` with 1 real entry - `dbt-snowflake` kit: 9 skills + dbt MCP server Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ba9e6f3 commit 6e1b0e1

1 file changed

Lines changed: 18 additions & 19 deletions

File tree

packages/opencode/src/cli/cmd/tui/thread.ts

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ import type { EventSource } from "./context/sdk"
1414
import { win32DisableProcessedInput, win32InstallCtrlCGuard } from "./win32"
1515
import { TuiConfig } from "@/config/tui"
1616
import { Instance } from "@/project/instance"
17-
// altimate_change start — kit: import Kit for startup detection nudge
18-
import { Kit } from "@/kit/kit"
17+
// altimate_change start — kit: Kit imported dynamically in setTimeout below to avoid test mock issues
1918
import { EOL } from "os"
2019
// altimate_change end
2120

@@ -178,24 +177,24 @@ export const TuiThreadCommand = cmd({
178177
})
179178

180179
// altimate_change start — kit: non-blocking kit detection nudge on TUI startup
181-
Instance.provide({
182-
directory: cwd,
183-
fn: async () => {
184-
try {
185-
const activeKits = await Kit.active()
186-
if (activeKits.length > 0) return // already has active kits, no nudge needed
187-
const detected = await Kit.detect()
188-
if (detected.length > 0) {
189-
const first = detected[0]
190-
process.stderr.write(
191-
`\x1b[2m\u{1F4A1} Kit available: ${first.kit.name} \u2014 run /kit activate ${first.kit.name}\x1b[0m` + EOL,
192-
)
193-
}
194-
} catch {
195-
// Kit detection is best-effort; never block startup
180+
// Deferred to avoid interfering with TUI initialization and test mocks.
181+
// Uses setTimeout + dynamic import so Kit module is not required at parse time.
182+
setTimeout(async () => {
183+
try {
184+
const { Kit } = await import("../../../kit")
185+
const activeKits = await Kit.active()
186+
if (activeKits.length > 0) return
187+
const detected = await Kit.detect()
188+
if (detected.length > 0) {
189+
const first = detected[0]
190+
process.stderr.write(
191+
`\x1b[2m\u{1F4A1} Kit available: ${first.kit.name} \u2014 run /kit activate ${first.kit.name}\x1b[0m` + EOL,
192+
)
196193
}
197-
},
198-
}).catch(() => {})
194+
} catch {
195+
// Kit detection is best-effort; never block startup
196+
}
197+
}, 100)
199198
// altimate_change end
200199

201200
const network = await resolveNetworkOptions(args)

0 commit comments

Comments
 (0)