opencode-bonfire 0.9.6
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 +73 -0
- package/dist/cli.js +156 -0
- package/files/agent/codebase-explorer.md +115 -0
- package/files/agent/doc-writer.md +120 -0
- package/files/agent/spec-writer.md +142 -0
- package/files/agent/work-reviewer.md +130 -0
- package/files/command/bonfire-archive.md +128 -0
- package/files/command/bonfire-configure.md +96 -0
- package/files/command/bonfire-document.md +178 -0
- package/files/command/bonfire-end.md +62 -0
- package/files/command/bonfire-git-strategy.md +91 -0
- package/files/command/bonfire-review.md +158 -0
- package/files/command/bonfire-spec.md +272 -0
- package/files/command/bonfire-start.md +245 -0
- package/files/opencode.json +4 -0
- package/files/package.json +7 -0
- package/files/plugin/bonfire-hooks.ts +51 -0
- package/files/skill/bonfire-context/SKILL.md +56 -0
- package/files/tool/bonfire.ts +103 -0
- package/package.json +37 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bonfire Plugin for OpenCode
|
|
3
|
+
*
|
|
4
|
+
* Provides event hooks for:
|
|
5
|
+
* - Suggesting archive after PR merge
|
|
6
|
+
* - Preserving session context during compaction
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Plugin } from "@opencode-ai/plugin"
|
|
10
|
+
import { existsSync, readFileSync } from "fs"
|
|
11
|
+
import { join } from "path"
|
|
12
|
+
|
|
13
|
+
export const BonfirePlugin: Plugin = async ({ directory }) => {
|
|
14
|
+
const bonfirePath = join(directory, ".bonfire")
|
|
15
|
+
const indexPath = join(bonfirePath, "index.md")
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
/**
|
|
19
|
+
* After tool execution - detect PR merges and suggest archiving
|
|
20
|
+
*/
|
|
21
|
+
"tool.execute.after": async (input, output) => {
|
|
22
|
+
if (input.tool !== "bash") return
|
|
23
|
+
|
|
24
|
+
const command = input.args?.command as string | undefined
|
|
25
|
+
if (!command) return
|
|
26
|
+
|
|
27
|
+
const isPrMerge =
|
|
28
|
+
command.includes("gh pr merge") || command.includes("gh pr close")
|
|
29
|
+
|
|
30
|
+
const succeeded = !output.error && output.result
|
|
31
|
+
|
|
32
|
+
if (isPrMerge && succeeded && existsSync(indexPath)) {
|
|
33
|
+
return {
|
|
34
|
+
message: `PR merged! Run \`/bonfire-archive\` to archive this session.`,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Preserve bonfire context during session compaction
|
|
41
|
+
*/
|
|
42
|
+
"experimental.session.compacting": async (_input, output) => {
|
|
43
|
+
if (existsSync(indexPath)) {
|
|
44
|
+
const content = readFileSync(indexPath, "utf-8")
|
|
45
|
+
output.context.push(`## Bonfire Session Context\n\n${content}`)
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Plugin auto-discovered by filename - no default export needed
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bonfire-context
|
|
3
|
+
description: Load .bonfire/index.md context to understand ongoing work, previous decisions, blockers, and session history. Use when user references past work or asks about project status.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: opencode
|
|
6
|
+
metadata:
|
|
7
|
+
category: session-management
|
|
8
|
+
author: vieko
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Bonfire Context
|
|
12
|
+
|
|
13
|
+
This skill loads project session context from `.bonfire/index.md` to provide continuity across AI coding sessions.
|
|
14
|
+
|
|
15
|
+
## When to Use This Skill
|
|
16
|
+
|
|
17
|
+
Load this skill when the user:
|
|
18
|
+
- Asks about previous work or decisions
|
|
19
|
+
- References "last time", "previously", "before"
|
|
20
|
+
- Wants to know about blockers or pending issues
|
|
21
|
+
- Asks what the project status is
|
|
22
|
+
- Starts a significant task that might have prior context
|
|
23
|
+
|
|
24
|
+
## Instructions
|
|
25
|
+
|
|
26
|
+
1. Find the git root: `git rev-parse --show-toplevel`
|
|
27
|
+
|
|
28
|
+
2. Check if `.bonfire/index.md` exists at the git root
|
|
29
|
+
|
|
30
|
+
3. If it exists, read it to understand:
|
|
31
|
+
- Current project status and recent work
|
|
32
|
+
- Active decisions and their rationale
|
|
33
|
+
- Known blockers or pending issues
|
|
34
|
+
- Links to relevant specs or documentation
|
|
35
|
+
|
|
36
|
+
4. Check `.bonfire/specs/` if the user asks about implementation specs
|
|
37
|
+
|
|
38
|
+
5. Check `.bonfire/docs/` if the user asks about documented topics
|
|
39
|
+
|
|
40
|
+
## File Structure
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
.bonfire/
|
|
44
|
+
├── index.md # Main session context (read this first)
|
|
45
|
+
├── config.json # Project settings
|
|
46
|
+
├── archive/ # Completed work history
|
|
47
|
+
├── docs/ # Topic documentation
|
|
48
|
+
└── specs/ # Implementation specs
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Important
|
|
52
|
+
|
|
53
|
+
- This skill is for **reading** context, not updating it
|
|
54
|
+
- Session updates happen via `/bonfire-end` command
|
|
55
|
+
- Don't modify `.bonfire/index.md` unless explicitly asked
|
|
56
|
+
- If `.bonfire/` doesn't exist, the project may not use this pattern
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bonfire Status Tool
|
|
3
|
+
*
|
|
4
|
+
* Returns structured session context for programmatic access.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { tool } from "@opencode-ai/plugin"
|
|
8
|
+
import { existsSync, readFileSync } from "fs"
|
|
9
|
+
|
|
10
|
+
interface BonfireStatus {
|
|
11
|
+
exists: boolean
|
|
12
|
+
project?: string
|
|
13
|
+
status?: string
|
|
14
|
+
branch?: string
|
|
15
|
+
currentState?: string
|
|
16
|
+
priorities?: string[]
|
|
17
|
+
recentSession?: {
|
|
18
|
+
number: number
|
|
19
|
+
date: string
|
|
20
|
+
goal: string
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function extractSection(content: string, header: string): string | undefined {
|
|
25
|
+
const regex = new RegExp(`## ${header}\\n\\n([\\s\\S]*?)(?=\\n## |$)`, "i")
|
|
26
|
+
const match = content.match(regex)
|
|
27
|
+
return match ? match[1].trim() : undefined
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function extractPriorities(content: string): string[] {
|
|
31
|
+
const section = extractSection(content, "Next Session Priorities")
|
|
32
|
+
if (!section) return []
|
|
33
|
+
const lines = section.split("\n")
|
|
34
|
+
return lines
|
|
35
|
+
.filter((line) => line.match(/^\d+\./))
|
|
36
|
+
.map((line) =>
|
|
37
|
+
line
|
|
38
|
+
.replace(/^\d+\.\s*\*\*/, "")
|
|
39
|
+
.replace(/\*\*.*$/, "")
|
|
40
|
+
.trim()
|
|
41
|
+
)
|
|
42
|
+
.slice(0, 5)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function extractMetadata(content: string): {
|
|
46
|
+
project?: string
|
|
47
|
+
status?: string
|
|
48
|
+
branch?: string
|
|
49
|
+
} {
|
|
50
|
+
const projectMatch = content.match(/# Session Context: (.+)/)
|
|
51
|
+
const statusMatch = content.match(/\*\*Status\*\*: (.+)/)
|
|
52
|
+
const branchMatch = content.match(/\*\*Branch\*\*: `?([^`\n]+)`?/)
|
|
53
|
+
return {
|
|
54
|
+
project: projectMatch?.[1],
|
|
55
|
+
status: statusMatch?.[1],
|
|
56
|
+
branch: branchMatch?.[1],
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function extractRecentSession(
|
|
61
|
+
content: string
|
|
62
|
+
): { number: number; date: string; goal: string } | undefined {
|
|
63
|
+
const match = content.match(
|
|
64
|
+
/### Session (\d+) - ([\d-]+)[^\n]*\n\n\*\*Goal\*\*: (.+)/
|
|
65
|
+
)
|
|
66
|
+
if (!match) return undefined
|
|
67
|
+
return {
|
|
68
|
+
number: parseInt(match[1]),
|
|
69
|
+
date: match[2],
|
|
70
|
+
goal: match[3],
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export default tool({
|
|
75
|
+
description:
|
|
76
|
+
"Get bonfire session status with structured context summary. Returns project info, current state, priorities, and recent session details.",
|
|
77
|
+
args: {},
|
|
78
|
+
async execute() {
|
|
79
|
+
const indexPath = ".bonfire/index.md"
|
|
80
|
+
|
|
81
|
+
if (!existsSync(indexPath)) {
|
|
82
|
+
const result: BonfireStatus = {
|
|
83
|
+
exists: false,
|
|
84
|
+
}
|
|
85
|
+
return JSON.stringify(result, null, 2)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const content = readFileSync(indexPath, "utf-8")
|
|
89
|
+
const metadata = extractMetadata(content)
|
|
90
|
+
|
|
91
|
+
const result: BonfireStatus = {
|
|
92
|
+
exists: true,
|
|
93
|
+
project: metadata.project,
|
|
94
|
+
status: metadata.status,
|
|
95
|
+
branch: metadata.branch,
|
|
96
|
+
currentState: extractSection(content, "Current State"),
|
|
97
|
+
priorities: extractPriorities(content),
|
|
98
|
+
recentSession: extractRecentSession(content),
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return JSON.stringify(result, null, 2)
|
|
102
|
+
},
|
|
103
|
+
})
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencode-bonfire",
|
|
3
|
+
"version": "0.9.6",
|
|
4
|
+
"description": "A plugin that maintains a living context document—read at session start, updated at session end. Pick up exactly where you left off.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"opencode-bonfire": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"copy-files": "rm -rf files && mkdir -p files && cp -r ../opencode/agent ../opencode/command ../opencode/plugin ../opencode/skill ../opencode/tool ../opencode/opencode.json ../opencode/package.json files/",
|
|
11
|
+
"build": "bun run copy-files && bun build src/cli.ts --outdir dist --target node",
|
|
12
|
+
"prepublishOnly": "bun run build"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"files"
|
|
17
|
+
],
|
|
18
|
+
"keywords": [
|
|
19
|
+
"opencode",
|
|
20
|
+
"ai",
|
|
21
|
+
"coding",
|
|
22
|
+
"session",
|
|
23
|
+
"context",
|
|
24
|
+
"plugin"
|
|
25
|
+
],
|
|
26
|
+
"author": "vieko",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/vieko/bonfire"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/vieko/bonfire",
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^20.0.0",
|
|
35
|
+
"typescript": "^5.0.0"
|
|
36
|
+
}
|
|
37
|
+
}
|