@ikieaneh/opencode-kit 0.5.7 → 0.5.9

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "opencode-kit",
3
3
  "description": "Standardized orchestration framework — contract-based, rules-enforced, zero-touch agent workflow",
4
- "version": "0.4.0",
4
+ "version": "0.5.8",
5
5
  "author": {
6
6
  "name": "Rizki Rachman",
7
7
  "url": "https://github.com/RizkiRachman"
@@ -184,7 +184,6 @@ export const OpencodeKitPlugin = async ({ client, directory }) => {
184
184
 
185
185
  // Register user project skills FIRST (higher priority)
186
186
  const userSkillsDir = path.join(projectDir, '.opencode/skills');
187
- const userSkillsDir = path.join(projectDir, '.opencode/skills');
188
187
  if (fs.existsSync(userSkillsDir) && !config.skills.paths.includes(userSkillsDir)) {
189
188
  config.skills.paths.push(userSkillsDir);
190
189
  log('info', `Registered user skills: ${userSkillsDir}`);
package/README.md CHANGED
@@ -59,25 +59,67 @@
59
59
  <!-- ABOUT THE PROJECT -->
60
60
  ## About The Project
61
61
 
62
- `opencode-kit` is a portable orchestration framework for OpenCode-based AI agents. It solves one core problem:
62
+ `opencode-kit` is a **workflow enforcement framework** for AI coding agents. It ensures agents follow a structured process — plan, build, review, learn — instead of jumping straight to implementation.
63
63
 
64
- **Agents skip the workflow and jump straight to implementation.**
64
+ ### The Problem
65
65
 
66
- Traditional agent frameworks use conventions (".md files say to load state first") but agents routinely bypass them because there's no enforcement. `opencode-kit` makes the workflow **machine-enforced**, not convention-based.
66
+ AI agents (Claude, Copilot, etc.) are powerful but **unpredictable**. When given a task, they often:
67
67
 
68
- ### How it works (v0.4 Plugin Mode)
68
+ - Skip project conventions and jump directly to writing code
69
+ - Ignore shared state — each session starts from scratch
70
+ - Bypass quality gates — no review, no scoring, no learning
71
+ - Use different approaches on every run — inconsistent results
69
72
 
70
- With `opencode-kit` installed as an OpenCode plugin, enforcement is **global**. No per-project scaffolding needed.
73
+ Traditional frameworks try to fix this with **prose in .md files** ("load the contract before any tool call"). But agents routinely ignore prose because there's no enforcement — it's a suggestion, not a requirement.
71
74
 
72
- 1. **Plugin injects enforcement** — every session auto-loads the orchestration contract before any work
73
- 2. **`contract.json`** — shared state machine every agent MUST read/write (local or global)
74
- 3. **`rules.json`** — machine-readable rules with CRITICAL/HIGH severity
75
- 4. **3 auto-registered skills** — `orchestration-template`, `scoring-pipeline`, `adr-generator`
76
- 5. **Config resolution** — `.opencode/` → `~/.config/opencode-kit/` → plugin defaults
75
+ ### The Solution
77
76
 
78
- ### Built for macOS M-Series
77
+ `opencode-kit` replaces prose conventions with **machine-readable enforcement**:
79
78
 
80
- Developed and tested on Apple Silicon (M1/M2/M3/M4). All scripts use portable POSIX shell with zero Linux-specific dependencies.
79
+ | Instead of ... | opencode-kit uses ... |
80
+ |:---------------|:----------------------|
81
+ | "read the state file" | `contract.json` — a JSON state machine agents MUST read/write |
82
+ | "follow the rules" | `rules.json` — CRITICAL rules BLOCK agents, HIGH rules FLAG them |
83
+ | "check before editing" | `preflight.sh` — an enforcement gate that fails if rules aren't met |
84
+ | "review your work" | **Scoring pipeline** — every output is scored (≥70 PASS, <50 BLOCK) |
85
+ | "remember what you learned" | `postflight.sh` — auto-persists state + telemetry + lessons learned |
86
+
87
+ The result: **zero-touch agent workflow**. Set a goal, and the system self-executes through Plan → Build → Review → Learn, pausing only when BLOCKED.
88
+
89
+ ### How It Works
90
+
91
+ As an OpenCode **plugin**, `opencode-kit` injects enforcement into every session globally:
92
+
93
+ 1. **Plugin bootstrap** — every session auto-loads the orchestration contract before any work
94
+ 2. **Pre-flight gate** — validates branch, contract state, and rule compliance. BLOCKs on CRITICAL violations
95
+ 3. **Contract protocol** — shared state machine (`contract.json`) tracks phase, decisions, scores, telemetry
96
+ 4. **Scoring pipeline** — every subagent output scored. ≥70 PASS, 50-69 RETRY, <50 BLOCKED
97
+ 5. **ADR logging** — every architectural decision recorded in `decisions.adr_log[]`
98
+ 6. **Extension model** — project-specific skills in `.opencode/skills/` override plugin defaults
99
+
100
+ ### The 9 Built-in Skills
101
+
102
+ | Skill | Purpose |
103
+ |-------|---------|
104
+ | `orchestration-template` | Contract protocol, state machine, persistence rules |
105
+ | `scoring-pipeline` | Tier 1 rule checks + Tier 2 LLM judge + verdict |
106
+ | `adr-generator` | Architecture Decision Record format and auto-ID |
107
+ | `qa-expert` | Test standards, edge cases, coverage goals |
108
+ | `system-analyst` | Impact analysis, execution tracing, architecture checks |
109
+ | `token-optimize` | Efficient reading, batching, and delegation |
110
+ | `verification-before-completion` | Quality gates — formatting, compile, test, verify |
111
+ | `learner` | Post-execution learning, memory persistence |
112
+ | *(extensible)* | Create your own skills in `.opencode/skills/` |
113
+
114
+ ### Built for Cost-Efficient Models
115
+
116
+ `opencode-kit` was designed for teams using **cost-optimized models** (DeepSeek V4 Flash, Gemini Flash, GPT-4o Mini, etc.) who want to compete with premium models through **process rigor**, not raw intelligence. The scoring pipeline and pre-flight enforcement create a quality floor that cheap models can meet through architecture, not model power.
117
+
118
+ ### Platform Support
119
+
120
+ - **macOS M-Series** (Apple Silicon) — primary development target
121
+ - **Linux** (Ubuntu) — CI-verified via GitHub Actions
122
+ - **Any OpenCode-compatible environment** with `lean-ctx`, `gitnexus`, `graphify`
81
123
 
82
124
  <p align="right">(<a href="#readme-top">back to top</a>)</p>
83
125
 
@@ -122,6 +164,17 @@ node --version # ≥ 18
122
164
  git --version # any recent version
123
165
  ```
124
166
 
167
+ ### Documentation Guides
168
+
169
+ | Guide | Description |
170
+ |-------|-------------|
171
+ | [Contract Protocol](docs/guides/contract-protocol.md) | State machine, fields, resolution order |
172
+ | [Scoring Pipeline](docs/guides/scoring-pipeline.md) | Tier 1 + Tier 2 + verdict |
173
+ | [Troubleshooting](docs/guides/troubleshooting.md) | Common issues and solutions |
174
+ | [Quickstart](docs/examples/QUICKSTART.md) | 6-step setup from scratch |
175
+ | [Extension Skills](docs/examples/extension-skill-template.md) | Create project-specific skills |
176
+ | [Model Configs](docs/examples/model-configs.md) | Provider configuration examples |
177
+
125
178
  ### Installation
126
179
 
127
180
  #### Option 1: Install as plugin (recommended)
@@ -224,6 +277,25 @@ INIT → PLAN → PLAN_SCORED → EXECUTE → EXECUTE_SCORED → REVIEW → REVI
224
277
 
225
278
  Each phase transition requires a score ≥70 to proceed.
226
279
 
280
+ ### CLI Commands
281
+
282
+ Once installed, run these from the project root:
283
+
284
+ | Command | Purpose |
285
+ |---------|---------|
286
+ | `bash .opencode/src/status.sh` | Dashboard — contract state, telemetry, rules |
287
+ | `bash .opencode/src/doctor.sh` | Diagnostics — MCPs, contract, git, persistence |
288
+ | `bash .opencode/src/analytics.sh` | Telemetry aggregation — phase times, cost estimates |
289
+ | `bash .opencode/src/diff.sh` [branch1] [branch2] | Compare contract state between branches |
290
+ | `bash .opencode/src/adr.sh` | Record a new Architecture Decision Record |
291
+ | `bash .opencode/src/telemetry.sh` | View telemetry details |
292
+ | `bash .opencode/src/new-skill.sh` <name> | Scaffold a new skill SKILL.md |
293
+ | `bash .opencode/rules/validation.sh` | Validate rules compliance |
294
+ | `npx opencode-kit --version` | Print version |
295
+ | `npx opencode-kit --help` | Print help |
296
+
297
+
298
+
227
299
  <p align="right">(<a href="#readme-top">back to top</a>)</p>
228
300
 
229
301
  <!-- STRUCTURE -->
@@ -233,24 +305,42 @@ Each phase transition requires a score ≥70 to proceed.
233
305
  opencode-kit/
234
306
  ├── rules/
235
307
  │ ├── rules.json ← Machine-enforceable rules (CRITICAL/HIGH/state machine)
236
- │ └── validation.sh ← Validates agent actions against rules (future)
308
+ │ └── validation.sh ← Validates agent actions against rules
237
309
  ├── src/
238
310
  │ ├── init.sh ← Scaffold into target project
239
311
  │ ├── preflight.sh ← Envelope load gate (zero deps, fails if rules violated)
240
- │ ├── postflight.sh ← Auto-persist + scoring pipeline
241
- └── verify.sh ← Installation health check
312
+ │ ├── postflight.sh ← Auto-persist + scoring pipeline + contract migration
313
+ ├── doctor.sh ← Diagnostic command
314
+ │ ├── status.sh ← Dashboard view
315
+ │ ├── diff.sh ← Compare contract across branches
316
+ │ ├── analytics.sh ← Telemetry aggregation
317
+ │ ├── adr.sh ← ADR auto-generator
318
+ │ ├── telemetry.sh ← Phase telemetry viewer
319
+ │ ├── new-skill.sh ← Skill template generator
320
+ │ ├── update.sh ← Pull latest from GitHub
321
+ │ ├── verify.sh ← Installation health check
322
+ │ ├── platform.sh ← Cross-platform detection
323
+ │ ├── global-config.sh ← Config resolution chain
324
+ │ └── cli.js ← --version / --help
325
+ ├── skills/ ← 9 auto-registered skills
242
326
  ├── templates/
243
- │ ├── contract.json ← Shared state contract (renamed from "envelope")
244
- │ ├── superpowers-contract.json
245
- └── agents/
246
- ├── orchestrator.md
247
- ├── planner.md
248
- ├── task-manager.md
249
- ├── code-reviewer.md
250
- ├── learner.md
251
- │ └── fixer.md
252
- ├── package.json npm publish for `npx opencode-kit init`
253
- └── README.md You are here
327
+ │ ├── contract.json ← Shared state contract
328
+ │ ├── opencode-kit.schema.json ← Agent config schema
329
+ ├── judge-prompt.md ← LLM judge prompt template
330
+ └── agents/ ← 6 agent .md templates
331
+ ├── docs/
332
+ ├── guides/ ← Usage guides (contract, scoring, troubleshooting)
333
+ ├── examples/ ← Quickstart, model configs, extension skills
334
+ └── plans/ ← Implementation plans
335
+ ├── test/ ← Integration + E2E tests (16 total)
336
+ ├── .github/workflows/ CI (ShellCheck + scaffold + tests)
337
+ ├── .opencode/plugins/ Plugin entry point
338
+ ├── .claude-plugin/ ← Plugin metadata
339
+ ├── package.json ← npm publish
340
+ ├── CHANGELOG.md
341
+ ├── CONTRIBUTING.md
342
+ ├── RELEASE.md
343
+ └── ROADMAP.md
254
344
  ```
255
345
 
256
346
  <p align="right">(<a href="#readme-top">back to top</a>)</p>
@@ -0,0 +1,67 @@
1
+ # Contract Protocol
2
+
3
+ The orchestrator contract (`contract.json`) is the single source of truth for every agent session.
4
+
5
+ ## What it does
6
+
7
+ - Tracks **state** — what phase the workflow is in (INIT → PLAN → ... → COMPLETE)
8
+ - Stores **requirements** — the goal, acceptance criteria, and constraints
9
+ - Logs **decisions** — Architecture Decision Records (ADRs)
10
+ - Records **scores** — quality metrics from the scoring pipeline
11
+ - Captures **telemetry** — elapsed time, phases completed, agents used
12
+
13
+ ## State Machine
14
+
15
+ ```
16
+ INIT → PLAN → PLAN_SCORED → EXECUTE → EXECUTE_SCORED → REVIEW → REVIEW_SCORED → COMPLETE
17
+
18
+ BLOCKED (any phase) → user intervention → retry
19
+ ```
20
+
21
+ **Transition rules:**
22
+ - Each phase transition requires score ≥ 70
23
+ - Score < 50 → BLOCKED
24
+ - Max 3 retry attempts before escalation
25
+
26
+ ## Key Fields
27
+
28
+ ```json
29
+ {
30
+ "state": "INIT",
31
+ "contract_version": "0.5.8",
32
+ "requirements": {
33
+ "goal": "What we're building",
34
+ "acceptance_criteria": ["testable condition 1"],
35
+ "constraints": ["must not..."]
36
+ },
37
+ "governance": {
38
+ "active_agent": "orchestrator",
39
+ "current_guidance": "Instructions for this session",
40
+ "extension_skills": ["java-conventions"],
41
+ "permissions": { "do": [], "dont": ["push to main"] }
42
+ },
43
+ "decisions": {
44
+ "adr_log": [
45
+ { "id": "ADR-001", "date": "2026-06-11", "title": "Use contract protocol", ... }
46
+ ]
47
+ },
48
+ "score": {
49
+ "combined": 85,
50
+ "verdict": "PASS"
51
+ },
52
+ "metrics": {
53
+ "phases_completed": ["INIT", "PLAN", "PLAN_SCORED"]
54
+ }
55
+ }
56
+ ```
57
+
58
+ ## Resolution Order
59
+
60
+ 1. `.opencode/orchestration/contract.json` — project override
61
+ 2. `~/.config/opencode-kit/contract.json` — global defaults
62
+ 3. Plugin `templates/contract.json` — shipped defaults
63
+
64
+ ## CLI
65
+
66
+ View contract state: `bash .opencode/src/status.sh`
67
+ Compare across branches: `bash .opencode/src/diff.sh [branch1] [branch2]`
@@ -0,0 +1,60 @@
1
+ # Scoring Pipeline
2
+
3
+ Every subagent output is scored before the next phase begins.
4
+
5
+ ## Tier 1 — Rule Checks
6
+
7
+ Automatic checks run by the orchestrator. Start at 100, deduct per violation:
8
+
9
+ | Check | Deduction |
10
+ |-------|:---------:|
11
+ | Schema valid (required fields present) | -15 |
12
+ | Permissions violated | -40 |
13
+ | Blast radius HIGH/CRITICAL | -40 |
14
+ | Writing order wrong | -15 |
15
+ | Fields missing | -15 |
16
+
17
+ If subtotal < 70 → skip Tier 2, use subtotal as combined score.
18
+
19
+ ## Tier 2 — LLM Judge
20
+
21
+ If Tier 1 score ≥ 70, the orchestrator runs a judge via `subtask()`.
22
+
23
+ ```json
24
+ {
25
+ "score": 85,
26
+ "rationale": "All requirements met. Writing order correct.",
27
+ "missing_items": ["Test for null boundary case"]
28
+ }
29
+ ```
30
+
31
+ **Dimensions:**
32
+ | Dimension | Max | What it evaluates |
33
+ |-----------|:---:|-------------------|
34
+ | Requirements | 40 | Does output satisfy goal + acceptance criteria? |
35
+ | Governance | 30 | Follows rules.json + writing order? |
36
+ | Completeness | 20 | All files created? Edge cases documented? |
37
+ | Edge cases | 10 | Nulls, errors, boundaries covered? |
38
+
39
+ ## Tier 3 — Verdict
40
+
41
+ | Combined Score | Verdict | Action |
42
+ |:--------------:|:-------:|--------|
43
+ | ≥ 70 | **PASS** | Advance to next phase |
44
+ | 50–69 | **RETRY** | Increment retry count, re-delegate |
45
+ | < 50 | **BLOCKED** | Escalate to user |
46
+
47
+ ## Configuration
48
+
49
+ Thresholds and deductions are in `rules.json` → `scoring`:
50
+
51
+ ```json
52
+ {
53
+ "scoring": {
54
+ "tier1": { "schema_valid_deduction": 15, ... },
55
+ "thresholds": { "pass": 70, "retry": 50, "max_attempts": 3 }
56
+ }
57
+ }
58
+ ```
59
+
60
+ Projects can override rule severity via `contract.json` → `validation.rule_overrides`.
@@ -0,0 +1,78 @@
1
+ # Troubleshooting Guide
2
+
3
+ ## Common Issues
4
+
5
+ ### Plugin doesn't load
6
+
7
+ **Symptom**: Skills not available, contract not injected.
8
+
9
+ **Checks:**
10
+ 1. Is `@ikieaneh/opencode-kit` in `opencode.json` plugin array? Must be **first**.
11
+ 2. Is it installed? `ls node_modules/@ikieaneh/opencode-kit`
12
+ 3. Is the plugin array syntax correct? `"plugin": ["@ikieaneh/opencode-kit"]`
13
+
14
+ ### Agent jumps straight to implementation
15
+
16
+ **Symptom**: Agent starts working without loading contract.
17
+
18
+ **Fix:** The plugin's `messages.transform` hook injects the bootstrap. Make sure:
19
+ 1. Plugin is first in the array
20
+ 2. No other plugin overrides the same hook
21
+ 3. Run `bash .opencode/src/doctor.sh` to verify
22
+
23
+ ### Contract not found
24
+
25
+ **Symptom**: "Contract not found" error from preflight.
26
+
27
+ **Solution:**
28
+ ```sh
29
+ bash .opencode/src/doctor.sh
30
+ # Or manually:
31
+ mkdir -p .opencode/orchestration
32
+ cp node_modules/@ikieaneh/opencode-kit/templates/contract.json .opencode/orchestration/contract.json
33
+ ```
34
+
35
+ ### Score below threshold
36
+
37
+ **Symptom**: Workflow keeps retrying or gets blocked.
38
+
39
+ **Check:**
40
+ - Tier 1 violations (blast radius, permissions)
41
+ - Tier 2 judge feedback — read `judge.missing_items`
42
+ - Retry count — max 3 attempts before BLOCKED
43
+
44
+ ### ShellCheck fails in CI
45
+
46
+ **Symptom**: GitHub Actions ShellCheck job fails.
47
+
48
+ **Fix:** Run locally:
49
+ ```sh
50
+ shellcheck src/*.sh rules/*.sh
51
+ ```
52
+ Look for SC1091 (source path) or SC2001 (sed style) — most are info-level.
53
+
54
+ ### Scaffold test fails in CI
55
+
56
+ **Symptom**: init.sh exits with error.
57
+
58
+ **Check:**
59
+ - Are all `mkdir -p` paths created before `cp`?
60
+ - Run locally: `cd /tmp && git init && bash /path/to/init.sh`
61
+
62
+ ### Custom skill not loading
63
+
64
+ **Symptom**: Skill referenced in opencode.json not available.
65
+
66
+ **Solution:**
67
+ 1. Place skill at `.opencode/skills/<name>/SKILL.md`
68
+ 2. Verify frontmatter has `description:` field
69
+ 3. Verify SKILL.md starts with `---` (YAML frontmatter)
70
+ 4. Run `bash .opencode/src/doctor.sh` to verify
71
+
72
+ ## Diagnostics
73
+
74
+ ```sh
75
+ bash .opencode/src/doctor.sh # Full health check
76
+ bash .opencode/src/status.sh # Dashboard view
77
+ bash .opencode/src/analytics.sh # Telemetry analysis
78
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ikieaneh/opencode-kit",
3
- "version": "0.5.7",
3
+ "version": "0.5.9",
4
4
  "description": "Standardized OpenCode orchestration framework — contract-based, rules-enforced, zero-touch agent workflow. Install as plugin.",
5
5
  "license": "MIT",
6
6
  "author": "RizkiRachman",
package/rules/rules.json CHANGED
@@ -88,7 +88,7 @@
88
88
  },
89
89
  {
90
90
  "id": "WRITE_001",
91
- "severity": "CRITICAL",
91
+ "severity": "HIGH",
92
92
  "description": "Agent MUST follow writing order: Port → Service → Mapper → Adapter → Constants → Events → Tests",
93
93
  "condition": "writing_order_violation",
94
94
  "action": "FLAG",
package/src/adr.sh CHANGED
@@ -5,6 +5,7 @@
5
5
  set -euo pipefail
6
6
 
7
7
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
+ # shellcheck source=./platform.sh
8
9
  . "$SCRIPT_DIR/platform.sh"
9
10
 
10
11
  CONTRACT_FILE=".opencode/orchestration/contract.json"
@@ -85,30 +86,42 @@ if [ -n "$DUP" ]; then
85
86
  exit 0
86
87
  fi
87
88
 
88
- # --- Build ADR entry ---
89
- # --- Build ADR entry via heredoc to avoid nested quote issues ---
89
+ # --- Build ADR entry via temp JSON file (avoids shell injection) ---
90
+ # Write ADR fields to temp file to avoid shell interpolation into Python
91
+ ADR_DATA=$(mktemp /tmp/opencode-adr-data-XXXXX.json)
92
+ cat > "$ADR_DATA" << ADRDATA
93
+ {
94
+ "title": "$TITLE",
95
+ "context": "$CONTEXT",
96
+ "decision": "$DECISION",
97
+ "alternatives": "$ALTERNATIVES",
98
+ "consequences": "$CONSEQUENCES"
99
+ }
100
+ ADRDATA
101
+
90
102
  $PYTHON_CMD -c "
91
- import json, sys, os
103
+ import json
92
104
 
93
- title = '$TITLE'
94
- date_val = '$(date +%Y-%m-%d)'
95
- next_id = '$NEXT_ID'
105
+ with open('$ADR_DATA') as f:
106
+ data = json.load(f)
96
107
 
97
108
  entry = {
98
- 'id': next_id,
99
- 'date': date_val,
100
- 'title': title,
101
- 'context': '''$(echo "$CONTEXT" | sed "s/'/\\\\'/g")''',
102
- 'decision': '''$(echo "$DECISION" | sed "s/'/\\\\'/g")''',
103
- 'alternatives': '''$(echo "$ALTERNATIVES" | sed "s/'/\\\\'/g")''',
104
- 'consequences': '''$(echo "$CONSEQUENCES" | sed "s/'/\\\\'/g")'''
109
+ 'id': '$NEXT_ID',
110
+ 'date': '$(date +%Y-%m-%d)',
111
+ 'title': data['title'],
112
+ 'context': data['context'],
113
+ 'decision': data['decision'],
114
+ 'alternatives': data['alternatives'],
115
+ 'consequences': data['consequences']
105
116
  }
106
117
 
107
118
  with open('/tmp/opencode-adr-entry.json', 'w') as f:
108
- json.dump(entry, f, indent=2)
119
+ json.dump(entry, f, indent=2)
109
120
  print('Entry written')
110
121
  "
111
122
 
123
+ rm -f "$ADR_DATA"
124
+
112
125
  # --- Inject into contract.json ---
113
126
  $PYTHON_CMD -c "
114
127
  import json
package/src/analytics.sh CHANGED
@@ -4,6 +4,7 @@
4
4
  set -euo pipefail
5
5
 
6
6
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
7
+ # shellcheck source=./platform.sh
7
8
  . "$SCRIPT_DIR/platform.sh"
8
9
 
9
10
  TELEMETRY_DIR=".opencode/telemetry"
@@ -68,7 +69,7 @@ for p in phases:
68
69
  frm = p.get('from', '?')
69
70
  to = p.get('to', '?')
70
71
  ms = p.get('elapsed_ms', 0)
71
- bar = '' * max(1, int(ms / max(1, total_ms) * 30))
72
+ bar = '#' * max(1, int(ms / max(1, total_ms) * 30))
72
73
  print(f' {frm:16s} → {to:16s} {ms/1000:6.1f}s {bar}')
73
74
 
74
75
  # Cost estimate (rough: ~$0.15/1M tokens, ~1000 tok/s)
package/src/diff.sh ADDED
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env bash
2
+ # opencode-kit diff — compare contract state between branches
3
+ # Usage: bash src/diff.sh [branch1] [branch2]
4
+ # Default: compares current branch vs main
5
+ set -euo pipefail
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
+ # shellcheck source=./platform.sh
9
+ . "$SCRIPT_DIR/platform.sh"
10
+
11
+ CONTRACT_FILE=".opencode/orchestration/contract.json"
12
+ BRANCH_A="${1:-main}"
13
+ BRANCH_B="${2:-HEAD}"
14
+
15
+ RED='\033[0;31m'
16
+ GREEN='\033[0;32m'
17
+ YELLOW='\033[1;33m'
18
+ CYAN='\033[0;36m'
19
+ NC='\033[0m'
20
+
21
+ echo -e "${CYAN}📋 opencode-kit diff: $BRANCH_A ↔ $BRANCH_B${NC}"
22
+ echo ""
23
+
24
+ # Extract contract from a git ref
25
+ get_contract_state() {
26
+ local branch="$1"
27
+ local content
28
+ content=$(git show "$branch:$CONTRACT_FILE" 2>/dev/null || echo "")
29
+ if [ -z "$content" ]; then
30
+ echo ""
31
+ return 1
32
+ fi
33
+ echo "$content"
34
+ }
35
+
36
+ CONTRACT_A=$(get_contract_state "$BRANCH_A")
37
+ CONTRACT_B=$(get_contract_state "$BRANCH_B")
38
+
39
+ if [ -z "$CONTRACT_A" ] && [ -z "$CONTRACT_B" ]; then
40
+ echo -e "${YELLOW}No contract found in either branch.${NC}"
41
+ exit 0
42
+ fi
43
+
44
+ # Show state diff
45
+ if [ -n "$PYTHON_CMD" ]; then
46
+ $PYTHON_CMD -c "
47
+ import json, sys
48
+
49
+ def get_state(c):
50
+ try:
51
+ d = json.loads(c)
52
+ return {
53
+ 'state': d.get('state', '?'),
54
+ 'goal': (d.get('requirements', {}) or {}).get('goal', '?'),
55
+ 'score': (d.get('score', {}) or {}).get('combined', '?'),
56
+ 'phases': (d.get('metrics', {}) or {}).get('phases_completed', []),
57
+ 'adrs': len((d.get('decisions', {}) or {}).get('adr_log', [])),
58
+ 'version': d.get('contract_version', '?')
59
+ }
60
+ except:
61
+ return None
62
+
63
+ a = get_state('''$CONTRACT_A''') if '''$CONTRACT_A''' else None
64
+ b = get_state('''$CONTRACT_B''') if '''$CONTRACT_B''' else None
65
+
66
+ if a and b:
67
+ print(f' Field $BRANCH_A $BRANCH_B')
68
+ print(f' {"-"*50}')
69
+ for field in ['state', 'goal', 'score', 'version']:
70
+ va = str(a.get(field, '?'))[:20]
71
+ vb = str(b.get(field, '?'))[:20]
72
+ marker = ' ←→' if va != vb else ' '
73
+ print(f' {field:20s} {va:20s} {marker} {vb:20s}')
74
+ print(f' phases {len(a.get(\"phases\",[])):3d} completed {len(b.get(\"phases\",[])):3d} completed')
75
+ print(f' ADRs {a.get(\"adrs\",0):3d} recorded {b.get(\"adrs\",0):3d} recorded')
76
+ elif a and not b:
77
+ print(f' Contract exists in $BRANCH_A but NOT in $BRANCH_B')
78
+ print(f' State: {a.get(\"state\",\"?\")}')
79
+ elif b and not a:
80
+ print(f' Contract exists in $BRANCH_B but NOT in $BRANCH_A')
81
+ print(f' State: {b.get(\"state\",\"?\")}')
82
+ " 2>/dev/null || echo -e "${YELLOW}Could not parse contract JSON${NC}"
83
+ fi
84
+
85
+ # Raw git diff
86
+ echo ""
87
+ echo -e "${CYAN}Raw diff:${NC}"
88
+ if git diff "$BRANCH_A" "$BRANCH_B" -- "$CONTRACT_FILE" 2>/dev/null | head -40; then
89
+ if ! git diff --exit-code "$BRANCH_A" "$BRANCH_B" -- "$CONTRACT_FILE" &>/dev/null; then
90
+ :
91
+ fi
92
+ fi
93
+ echo ""
94
+ echo -e "Run: ${GREEN}bash .opencode/src/diff.sh${NC} (default: main vs HEAD)"
95
+ echo -e " ${GREEN}bash .opencode/src/diff.sh staging feature-x${NC} (custom branches)"
package/src/doctor.sh CHANGED
@@ -5,6 +5,7 @@
5
5
  set -euo pipefail
6
6
 
7
7
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
+ # shellcheck source=./platform.sh
8
9
  . "$SCRIPT_DIR/platform.sh"
9
10
  . "$SCRIPT_DIR/global-config.sh"
10
11
 
@@ -4,6 +4,7 @@
4
4
  set -euo pipefail
5
5
 
6
6
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
7
+ # shellcheck source=./platform.sh
7
8
  . "$SCRIPT_DIR/platform.sh"
8
9
 
9
10
  PLUGIN_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
package/src/init.sh CHANGED
@@ -6,6 +6,7 @@
6
6
  set -euo pipefail
7
7
 
8
8
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
9
+ # shellcheck source=./platform.sh
9
10
  . "$SCRIPT_DIR/platform.sh"
10
11
  . "$SCRIPT_DIR/global-config.sh"
11
12
  KIT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
@@ -88,7 +89,7 @@ if [ -d ".opencode" ]; then
88
89
  fi
89
90
 
90
91
  # --- Scaffold directories ---
91
- mkdir -p .opencode/orchestration .opencode/rules .opencode/agents .opencode/src
92
+ mkdir -p .opencode/orchestration .opencode/rules .opencode/agents .opencode/src .opencode/templates
92
93
 
93
94
  # --- Copy templates ---
94
95
  echo ""
@@ -154,6 +155,10 @@ if [ "$PLUGIN_MODE" = false ]; then
154
155
  chmod +x .opencode/src/analytics.sh
155
156
  echo " ✅ analytics.sh (executable)"
156
157
 
158
+ cp "$KIT_DIR/src/diff.sh" .opencode/src/diff.sh
159
+ chmod +x .opencode/src/diff.sh
160
+ echo " ✅ diff.sh (executable)"
161
+
157
162
  # --- Copy agent templates (pre-flight gates) ---
158
163
  for agent in orchestrator planner task-manager code-reviewer learner fixer; do
159
164
  if [ -f "$KIT_DIR/templates/agents/$agent.md" ]; then
@@ -175,9 +180,9 @@ echo ""
175
180
  echo "[opencode-kit] Running verification..."
176
181
  if "$KIT_DIR/src/verify.sh"; then
177
182
  echo ""
178
- echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
179
- echo -e "${GREEN} ✅ opencode-kit v0.5.0 initialized${NC}"
180
- echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
183
+ echo -e "${GREEN}========================================${NC}"
184
+ echo -e "${GREEN} ✅ opencode-kit initialized (version: $(cat "$KIT_DIR/package.json" | grep '"version"' | head -1 | cut -d'"' -f4))${NC}"
185
+ echo -e "${GREEN}========================================${NC}"
181
186
  echo ""
182
187
  echo " Next steps:"
183
188
  echo " 1. Set GOAL & SCOPE in .opencode/orchestration/contract.json"
package/src/postflight.sh CHANGED
@@ -4,6 +4,7 @@
4
4
  set -euo pipefail
5
5
 
6
6
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
7
+ # shellcheck source=./platform.sh
7
8
  . "$SCRIPT_DIR/platform.sh"
8
9
 
9
10
  CONTRACT_KEY="orchestration-contract"
@@ -12,6 +13,7 @@ STATE_FILE="STATE.md"
12
13
  TELEMETRY_DIR=".opencode/telemetry"
13
14
  START_TIME_FILE=".opencode/telemetry/.phase_start"
14
15
  STATE_BACKUP_DIR=".opencode/state"
16
+ TEMPLATE_FILE=".opencode/templates/contract.json"
15
17
 
16
18
  mkdir -p "$TELEMETRY_DIR" "$STATE_BACKUP_DIR"
17
19
 
@@ -46,6 +48,46 @@ if [ -z "$CURRENT_CONTRACT" ]; then
46
48
  fi
47
49
  fi
48
50
 
51
+ # --- Step 1b: Contract migration (auto-upgrade old schema) ---
52
+ if [ -n "$CURRENT_CONTRACT" ] && [ -f "$TEMPLATE_FILE" ] && [ -n "$PYTHON_CMD" ]; then
53
+ MIGRATED=$($PYTHON_CMD -c "
54
+ import json
55
+
56
+ try:
57
+ contract = json.loads('''$CURRENT_CONTRACT''')
58
+ with open('$TEMPLATE_FILE') as f:
59
+ template = json.load(f)
60
+
61
+ # Check version
62
+ old_ver = contract.get('contract_version', '0.0.0')
63
+ new_ver = template.get('contract_version', '0.5.2')
64
+
65
+ if old_ver == new_ver and all(k in contract for k in ['state','requirements','governance','score']):
66
+ print('NO_MIGRATION')
67
+ else:
68
+ # Merge missing top-level fields from template
69
+ for key in template:
70
+ if key not in contract:
71
+ contract[key] = template[key]
72
+ # Merge governance.extension_skills if missing
73
+ if 'extension_skills' not in contract.get('governance', {}):
74
+ if 'governance' not in contract:
75
+ contract['governance'] = {}
76
+ contract['governance']['extension_skills'] = []
77
+ # Update version
78
+ contract['contract_version'] = new_ver
79
+ print(json.dumps(contract))
80
+ except Exception as e:
81
+ print('MIGRATE_ERROR:'+str(e))
82
+ " 2>/dev/null || echo "MIGRATE_ERROR")
83
+
84
+ if [ -n "$MIGRATED" ] && [ "$MIGRATED" != "NO_MIGRATION" ] && [ "$MIGRATED" != "MIGRATE_ERROR" ]; then
85
+ CURRENT_CONTRACT="$MIGRATED"
86
+ echo "$MIGRATED" > "$CONTRACT_FILE"
87
+ echo " 🔄 Contract migrated to v$(echo "$MIGRATED" | $PYTHON_CMD -c "import sys,json; print(json.load(sys.stdin).get('contract_version','?'))" 2>/dev/null)"
88
+ fi
89
+ fi
90
+
49
91
  # --- Step 2: Persist (try lean-ctx first, fall back to file) ---
50
92
  PERSISTED=false
51
93
  if lean-ctx ctx_knowledge remember \
package/src/preflight.sh CHANGED
@@ -4,6 +4,7 @@
4
4
  set -euo pipefail
5
5
 
6
6
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
7
+ # shellcheck source=./platform.sh
7
8
  . "$SCRIPT_DIR/platform.sh"
8
9
 
9
10
  CONTRACT_KEY="orchestration-contract"
package/src/status.sh CHANGED
@@ -4,6 +4,7 @@
4
4
  set -euo pipefail
5
5
 
6
6
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
7
+ # shellcheck source=./platform.sh
7
8
  . "$SCRIPT_DIR/platform.sh"
8
9
 
9
10
  CONTRACT_FILE=".opencode/orchestration/contract.json"
@@ -18,9 +19,9 @@ BOLD='\033[1m'
18
19
  NC='\033[0m'
19
20
 
20
21
  echo ""
21
- echo -e "${CYAN}${BOLD}╔══════════════════════════════════════════╗${NC}"
22
- echo -e "${CYAN}${BOLD} opencode-kit Dashboard ║${NC}"
23
- echo -e "${CYAN}${BOLD}╚══════════════════════════════════════════╝${NC}"
22
+ echo -e "${CYAN}${BOLD}##══════════════════════════════════════════╗${NC}"
23
+ echo -e "${CYAN}${BOLD}# opencode-kit Dashboard #${NC}"
24
+ echo -e "${CYAN}${BOLD}##══════════════════════════════════════════╝${NC}"
24
25
  echo ""
25
26
 
26
27
  # === Contract State ===
@@ -93,10 +94,8 @@ with open('$RULES_FILE') as f:
93
94
  rules = r.get('rules', [])
94
95
  critical = [x for x in rules if x.get('severity') == 'CRITICAL']
95
96
  high = [x for x in rules if x.get('severity') == 'HIGH']
96
- required_mcps = list(r.get('required_mcps', {}).keys())
97
- required_mcps = [m for m in required_mcps if m != 'description']
98
- mcps = list(r.get('required_mcps', {}).keys())
99
- mcps = [m for m in mcps if m != 'description']
97
+ mcps = list(r.get('required_mcps', {}).keys())
98
+ mcps = [m for m in mcps if m != 'description']
100
99
  print(f' {len(critical)} CRITICAL rules, {len(high)} HIGH rules')
101
100
  if mcps:
102
101
  print(f' Required MCPs: {\", \".join(mcps)}')
package/src/telemetry.sh CHANGED
@@ -4,6 +4,7 @@
4
4
  set -euo pipefail
5
5
 
6
6
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
7
+ # shellcheck source=./platform.sh
7
8
  . "$SCRIPT_DIR/platform.sh"
8
9
 
9
10
  TELEMETRY_DIR=".opencode/telemetry"
@@ -36,7 +37,7 @@ case "$MODE" in
36
37
  FROM=$(echo "$line" | $PYTHON_CMD -c "import sys,json; d=json.load(sys.stdin); print(d.get('from','?'))" 2>/dev/null)
37
38
  TO=$(echo "$line" | $PYTHON_CMD -c "import sys,json; d=json.load(sys.stdin); print(d.get('to','?'))" 2>/dev/null)
38
39
  MS=$(echo "$line" | $PYTHON_CMD -c "import sys,json; d=json.load(sys.stdin); print(d.get('elapsed_ms',0))" 2>/dev/null)
39
- printf " %-20s → %-20s %5.1fs\n" "$FROM" "$TO" "$(echo "scale=1; $MS/1000" | bc 2>/dev/null || echo "$((MS/1000)).$((MS%1000/100))")"
40
+ printf " %-20s → %-20s %5.1fs\n" "$FROM" "$TO" "$($PYTHON_CMD -c "print($MS/1000)" 2>/dev/null || echo "0.0")"
40
41
  done
41
42
  else
42
43
  echo -e "${YELLOW}No phase data yet.${NC}"
package/src/update.sh CHANGED
@@ -5,6 +5,7 @@
5
5
  set -euo pipefail
6
6
 
7
7
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
+ # shellcheck source=./platform.sh
8
9
  . "$SCRIPT_DIR/platform.sh"
9
10
 
10
11
  RED='\033[0;31m'
@@ -68,7 +68,7 @@
68
68
  "rules": { "pass": 0, "fail": 0, "deduction": 0, "subtotal": 0 },
69
69
  "judge": { "score": 0, "rationale": "", "missing_items": [] },
70
70
  "combined": 0,
71
- "verdict": "PENDING"
71
+ "verdict": "INIT"
72
72
  },
73
73
  "retry": {
74
74
  "current_phase": null,