opencode-onboard 0.3.3 → 0.4.2
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 +278 -214
- package/content/.agents/agents/basic-engineer.md +30 -0
- package/content/.agents/agents/devops-manager.md +38 -29
- package/content/.agents/session-log.json +41 -0
- package/content/.agents/skills/ob-default/SKILL.md +21 -0
- package/content/.agents/skills/ob-generic-guardrails/SKILL.md +32 -0
- package/content/.agents/skills/ob-global/SKILL.md +49 -0
- package/content/.agents/skills/ob-pullrequest-az/SKILL.md +11 -21
- package/content/.agents/skills/ob-pullrequest-gh/SKILL.md +14 -24
- package/content/.agents/skills/ob-userstory-az/SKILL.md +8 -14
- package/content/.agents/skills/ob-userstory-gh/SKILL.md +6 -14
- package/content/.opencode/commands/init.md +8 -0
- package/content/.opencode/commands/main.md +17 -0
- package/content/.opencode/commands/opsx-apply.md +50 -33
- package/content/.opencode/commands/plan.md +37 -0
- package/content/.opencode/plugins/session-log.js +1 -1
- package/content/.opencode/skills/openspec-apply-change/SKILL.md +50 -33
- package/content/AGENTS.md +94 -144
- package/content/skills-lock.json +4 -0
- package/package.json +6 -1
- package/src/commands/join.js +43 -0
- package/src/commands/shared.js +12 -0
- package/src/commands/shared.test.js +56 -0
- package/src/commands/single.js +64 -0
- package/src/commands/wizard.js +99 -0
- package/src/index.js +25 -202
- package/src/presets/browser.json +18 -0
- package/src/presets/clean.json +21 -0
- package/src/presets/models.json +33 -0
- package/src/presets/optimization.json +22 -0
- package/src/presets/platforms.json +29 -2
- package/src/presets/quota.json +14 -0
- package/src/presets/source.json +17 -0
- package/src/steps/browser/browser.test.js +81 -0
- package/src/steps/{install-browser.js → browser/index.js} +12 -15
- package/src/steps/{__tests__/clean-ai-files.test.js → clean/clean.test.js} +28 -13
- package/src/steps/{clean-ai-files.js → clean/index.js} +32 -30
- package/src/steps/copy/agents.js +106 -0
- package/src/steps/{__tests__/copy-content.test.js → copy/copy.test.js} +10 -1
- package/src/steps/copy/index.js +33 -0
- package/src/steps/copy/skills.js +55 -0
- package/src/steps/{write-onboard-config.js → metadata/index.js} +3 -3
- package/src/steps/metadata/metadata.test.js +99 -0
- package/src/steps/models/format.js +60 -0
- package/src/steps/models/format.test.js +75 -0
- package/src/steps/models/index.js +52 -0
- package/src/steps/models/write.js +54 -0
- package/src/steps/models/write.test.js +117 -0
- package/src/steps/{init-openspec.js → openspec/ensemble.js} +20 -57
- package/src/steps/openspec/ensemble.test.js +79 -0
- package/src/steps/openspec/index.js +32 -0
- package/src/steps/optimization/caveman-guidance.js +11 -0
- package/src/steps/{install-caveman.js → optimization/caveman.js} +5 -19
- package/src/steps/optimization/global.js +64 -0
- package/src/steps/optimization/index.js +101 -0
- package/src/steps/{__tests__/token-optimization.test.js → optimization/optimization.test.js} +37 -22
- package/src/steps/{install-quota.js → optimization/quota.js} +12 -10
- package/src/steps/platform/index.js +81 -0
- package/src/steps/platform/platform.test.js +129 -0
- package/src/steps/{choose-source-scope.js → source/index.js} +11 -17
- package/src/steps/source/source.test.js +91 -0
- package/src/utils/__tests__/copy.test.js +12 -5
- package/src/utils/copy.js +4 -24
- package/src/utils/exec-spinner.js +47 -0
- package/src/utils/exec.js +120 -162
- package/src/utils/models-cache.js +25 -68
- package/src/utils/models-pricing.js +42 -0
- package/src/utils/models-pricing.test.js +93 -0
- package/content/.agents/agents/back-engineer.md +0 -87
- package/content/.agents/agents/front-engineer.md +0 -86
- package/content/.agents/agents/infra-engineer.md +0 -85
- package/content/.agents/agents/quality-engineer.md +0 -86
- package/content/.agents/agents/security-auditor.md +0 -86
- package/src/steps/__tests__/check-env.test.js +0 -70
- package/src/steps/__tests__/check-platform.test.js +0 -104
- package/src/steps/__tests__/check-rtk.test.js +0 -38
- package/src/steps/__tests__/choose-platform.test.js +0 -38
- package/src/steps/check-env.js +0 -26
- package/src/steps/check-platform.js +0 -80
- package/src/steps/check-rtk.js +0 -38
- package/src/steps/choose-models.js +0 -165
- package/src/steps/choose-platform.js +0 -22
- package/src/steps/choose-skills-provider.js +0 -79
- package/src/steps/copy-content.js +0 -89
- package/src/steps/enable-caveman-guidance.js +0 -78
- package/src/steps/patch-agents-md.js +0 -153
- package/src/steps/token-optimization.js +0 -59
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import fse from 'fs-extra'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import { info, success } from '../utils/exec.js'
|
|
4
|
-
|
|
5
|
-
// Agent files that receive a Source Roots injection when parent folders are selected
|
|
6
|
-
const AGENT_FILES = [
|
|
7
|
-
'.agents/agents/front-engineer.md',
|
|
8
|
-
'.agents/agents/back-engineer.md',
|
|
9
|
-
'.agents/agents/infra-engineer.md',
|
|
10
|
-
'.agents/agents/quality-engineer.md',
|
|
11
|
-
'.agents/agents/security-auditor.md',
|
|
12
|
-
'.agents/agents/devops-manager.md',
|
|
13
|
-
]
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Build a markdown Source Roots block from an array of absolute paths.
|
|
17
|
-
*/
|
|
18
|
-
function buildSourceRootsBlock(sourceRoots, cwd) {
|
|
19
|
-
const bullets = sourceRoots.map(r => {
|
|
20
|
-
const rel = path.relative(cwd, r).replace(/\\/g, '/')
|
|
21
|
-
return `- \`${rel}\``
|
|
22
|
-
}).join('\n')
|
|
23
|
-
const multiRepoNote = sourceRoots.length > 1
|
|
24
|
-
? `\nEach root is an independent git repository. When branching, committing, or pushing, ALL repositories must be operated separately — create the feature branch in each repo, commit changes per repo, and push each repo independently. There is no single repo; \`rtk git\` commands must be run once per repository root.\n`
|
|
25
|
-
: ''
|
|
26
|
-
return `## Source Roots\n\nThe user selected these source repositories during onboarding.\nSearch and read code ONLY from these roots — do not assume code lives in the current folder.\n${multiRepoNote}\n${bullets}\n`
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Inject source roots into AGENTS.md (replaces the generic Source Scope section)
|
|
31
|
-
* and into every agent file (inserts after the ## Domain section).
|
|
32
|
-
*/
|
|
33
|
-
async function patchSourceRootsIntoAgents(cwd, sourceRoots) {
|
|
34
|
-
const block = buildSourceRootsBlock(sourceRoots, cwd)
|
|
35
|
-
|
|
36
|
-
// --- AGENTS.md: replace the ## Source Scope section ---
|
|
37
|
-
const agentsMdPath = path.join(cwd, 'AGENTS.md')
|
|
38
|
-
if (await fse.pathExists(agentsMdPath)) {
|
|
39
|
-
let content = await fse.readFile(agentsMdPath, 'utf-8')
|
|
40
|
-
// Replace the generic section between ## Source Scope and the next ## heading
|
|
41
|
-
content = content.replace(
|
|
42
|
-
/## Source Scope\n[\s\S]*?(?=\n## )/,
|
|
43
|
-
`## Source Roots\n\n${block.replace('## Source Roots\n\n', '')}\n`
|
|
44
|
-
)
|
|
45
|
-
await fse.writeFile(agentsMdPath, content, 'utf-8')
|
|
46
|
-
info('AGENTS.md: Source Roots section injected')
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// --- Agent files: insert ## Source Roots after ## Domain section ---
|
|
50
|
-
for (const relFile of AGENT_FILES) {
|
|
51
|
-
const agentPath = path.join(cwd, relFile)
|
|
52
|
-
if (!await fse.pathExists(agentPath)) continue
|
|
53
|
-
|
|
54
|
-
let content = await fse.readFile(agentPath, 'utf-8')
|
|
55
|
-
|
|
56
|
-
// Skip if already patched
|
|
57
|
-
if (content.includes('## Source Roots')) continue
|
|
58
|
-
|
|
59
|
-
// Insert after the ## Domain section (after its paragraph block, before next ##)
|
|
60
|
-
content = content.replace(
|
|
61
|
-
/(## Domain\n[\s\S]*?)(\n## )/,
|
|
62
|
-
`$1\n${block}\n## `
|
|
63
|
-
)
|
|
64
|
-
await fse.writeFile(agentPath, content, 'utf-8')
|
|
65
|
-
info(`${path.basename(agentPath)}: Source Roots section injected`)
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Each block is identified by its heading line. We remove from the heading up to (and including) the next `---` separator.
|
|
70
|
-
const STEP1_HEADING = '### Step 1, Archive project history into OpenSpec'
|
|
71
|
-
const STEP2_HEADING = '### Step 2, Generate DESIGN.md'
|
|
72
|
-
const STEP3_HEADING = '### Step 3, Generate ARCHITECTURE.md'
|
|
73
|
-
|
|
74
|
-
// Confirm message lines that reference each step, removed when the step is skipped
|
|
75
|
-
const STEP1_CONFIRM_LINE = '- Project history archived in openspec'
|
|
76
|
-
const STEP2_CONFIRM_LINE = '- DESIGN.md generated'
|
|
77
|
-
const STEP3_CONFIRM_LINE = '- ARCHITECTURE.md generated'
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Remove a bootstrap step block from AGENTS.md content.
|
|
81
|
-
* Removes from the step heading line up to and including the next `---` separator line.
|
|
82
|
-
*/
|
|
83
|
-
function removeStepBlock(content, heading) {
|
|
84
|
-
const lines = content.split('\n')
|
|
85
|
-
const start = lines.findIndex(l => l.trim() === heading.trim())
|
|
86
|
-
if (start === -1) return content
|
|
87
|
-
|
|
88
|
-
// Find the next `---` separator after the heading
|
|
89
|
-
let end = -1
|
|
90
|
-
for (let i = start + 1; i < lines.length; i++) {
|
|
91
|
-
if (lines[i].trim() === '---') { end = i; break }
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (end === -1) return content
|
|
95
|
-
|
|
96
|
-
// Remove the block including any blank line before the heading
|
|
97
|
-
const removeFrom = start > 0 && lines[start - 1].trim() === '' ? start - 1 : start
|
|
98
|
-
lines.splice(removeFrom, end - removeFrom + 1)
|
|
99
|
-
return lines.join('\n')
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Remove a specific line from the confirm message block in AGENTS.md.
|
|
104
|
-
*/
|
|
105
|
-
function removeConfirmLine(content, line) {
|
|
106
|
-
return content.split('\n').filter(l => l.trim() !== line.trim()).join('\n')
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Renumber remaining bootstrap steps sequentially (Step 1, Step 2, ...).
|
|
111
|
-
*/
|
|
112
|
-
function renumberSteps(content) {
|
|
113
|
-
let counter = 0
|
|
114
|
-
return content.replace(/^### Step \d+,/gm, () => `### Step ${++counter},`)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export async function patchAgentsMd(ctx) {
|
|
118
|
-
const agentsMdPath = path.join(process.cwd(), 'AGENTS.md')
|
|
119
|
-
if (!await fse.pathExists(agentsMdPath)) return
|
|
120
|
-
|
|
121
|
-
let content = await fse.readFile(agentsMdPath, 'utf-8')
|
|
122
|
-
const patches = []
|
|
123
|
-
|
|
124
|
-
if (ctx.hasOpenspec) {
|
|
125
|
-
content = removeStepBlock(content, STEP1_HEADING)
|
|
126
|
-
content = removeConfirmLine(content, STEP1_CONFIRM_LINE)
|
|
127
|
-
patches.push('Step 1 (openspec history) removed, openspec/ already exists')
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (ctx.hasDesign) {
|
|
131
|
-
content = removeStepBlock(content, STEP2_HEADING)
|
|
132
|
-
content = removeConfirmLine(content, STEP2_CONFIRM_LINE)
|
|
133
|
-
patches.push('Step 2 (DESIGN.md) removed, DESIGN.md already exists')
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (ctx.hasArchitecture) {
|
|
137
|
-
content = removeStepBlock(content, STEP3_HEADING)
|
|
138
|
-
content = removeConfirmLine(content, STEP3_CONFIRM_LINE)
|
|
139
|
-
patches.push('Step 3 (ARCHITECTURE.md) removed, ARCHITECTURE.md already exists')
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (patches.length > 0) {
|
|
143
|
-
content = renumberSteps(content)
|
|
144
|
-
await fse.writeFile(agentsMdPath, content, 'utf-8')
|
|
145
|
-
for (const msg of patches) info(msg)
|
|
146
|
-
success('AGENTS.md patched for existing project state')
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (ctx.sourceMode === 'parent-selected' && Array.isArray(ctx.sourceRoots) && ctx.sourceRoots.length > 0) {
|
|
150
|
-
await patchSourceRootsIntoAgents(process.cwd(), ctx.sourceRoots)
|
|
151
|
-
success('Source roots injected into AGENTS.md and agent files')
|
|
152
|
-
}
|
|
153
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { checkbox } from '@inquirer/prompts'
|
|
2
|
-
import { header, info, loading, success, warn } from '../utils/exec.js'
|
|
3
|
-
import { checkRtk } from './check-rtk.js'
|
|
4
|
-
import { installQuota } from './install-quota.js'
|
|
5
|
-
import { installCaveman } from './install-caveman.js'
|
|
6
|
-
import { enableCavemanGuidance } from './enable-caveman-guidance.js'
|
|
7
|
-
|
|
8
|
-
export async function tokenOptimizationStep(options = {}) {
|
|
9
|
-
header('Step 10, Token optimization tools')
|
|
10
|
-
|
|
11
|
-
const defaultSelected = ['rtk', 'quota', 'caveman']
|
|
12
|
-
let selected = defaultSelected
|
|
13
|
-
|
|
14
|
-
if (!options.skipPrompt && process.stdin.isTTY) {
|
|
15
|
-
info('Choose which optimization tools to enable (recommended: all).')
|
|
16
|
-
const timeoutMs = 30000
|
|
17
|
-
const choice = await Promise.race([
|
|
18
|
-
checkbox({
|
|
19
|
-
message: 'Enable tools:',
|
|
20
|
-
choices: [
|
|
21
|
-
{ name: 'RTK check (recommended)', value: 'rtk', checked: true },
|
|
22
|
-
{ name: 'opencode-quota plugin (recommended)', value: 'quota', checked: true },
|
|
23
|
-
{ name: 'caveman concise mode (recommended)', value: 'caveman', checked: true },
|
|
24
|
-
],
|
|
25
|
-
}),
|
|
26
|
-
new Promise(resolve => setTimeout(() => resolve(defaultSelected), timeoutMs)),
|
|
27
|
-
])
|
|
28
|
-
selected = Array.isArray(choice) ? choice : defaultSelected
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
loading('applying token optimization selections...')
|
|
32
|
-
|
|
33
|
-
const has = value => selected.includes(value)
|
|
34
|
-
|
|
35
|
-
const rtk = has('rtk')
|
|
36
|
-
? await checkRtk({ skipHeader: true, skipPrompt: true })
|
|
37
|
-
: { optedIn: false, checked: false, available: false }
|
|
38
|
-
|
|
39
|
-
const quota = has('quota')
|
|
40
|
-
? await installQuota({ skipHeader: true, skipPrompt: true })
|
|
41
|
-
: { optedIn: false, installed: false }
|
|
42
|
-
|
|
43
|
-
const caveman = has('caveman')
|
|
44
|
-
? await installCaveman({
|
|
45
|
-
skipHeader: true,
|
|
46
|
-
skipPrompt: true,
|
|
47
|
-
skillsProvider: options.skillsProvider,
|
|
48
|
-
})
|
|
49
|
-
: { optedIn: false, installed: false }
|
|
50
|
-
|
|
51
|
-
const cavemanGuidance = has('caveman')
|
|
52
|
-
? await enableCavemanGuidance(caveman)
|
|
53
|
-
: { enabled: false }
|
|
54
|
-
|
|
55
|
-
if (selected.length === 0) warn('No token optimization tools selected')
|
|
56
|
-
else success('Token optimization step completed')
|
|
57
|
-
|
|
58
|
-
return { rtk, quota, caveman, cavemanGuidance }
|
|
59
|
-
}
|