pantheon-opencode 1.5.0-beta.15 → 1.5.0-beta.16

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,300 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * generate-preset-docs.mjs — Generate markdown tables from src/routing.yml
4
- *
5
- * Reads routing.yml + presets.mjs + model-picker.mjs and prints:
6
- * 1) Presets summary table (perfil | provider/baseURL | key env | pricing 2026 | vision | papéis)
7
- * 2) 14 agents × 4 presets matrix (model + effort + vision)
8
- * 3) Capability table (model prefix → maxEffort, vision)
9
- *
10
- * No secrets are hardcoded — only env var NAMES and baseURLs from routing.yml
11
- * are emitted. Pricing labels come from model-picker PRESET_PRICE.
12
- *
13
- * Usage:
14
- * node scripts/generate-preset-docs.mjs # print all
15
- * node scripts/generate-preset-docs.mjs --summary # only summary
16
- * node scripts/generate-preset-docs.mjs --matrix # only matrix
17
- * node scripts/generate-preset-docs.mjs --json # JSON for tooling
18
- */
19
-
20
- import { readFileSync } from 'node:fs'
21
- import { fileURLToPath } from 'node:url'
22
- import yaml from 'js-yaml'
23
- import { CAPABILITY_TABLE, hasVision, normalizeCapability } from '../src/pantheon/presets.mjs'
24
- import { PRESET_PRICE } from './install/model-picker.mjs'
25
-
26
- const routingPath = fileURLToPath(new URL('../src/routing.yml', import.meta.url))
27
- const raw = readFileSync(routingPath, 'utf8')
28
- const routing = yaml.load(raw)
29
- const presets = routing?.presets ?? {}
30
-
31
- const KNOWN_AGENTS_ORDER = [
32
- 'zeus',
33
- 'athena',
34
- 'themis',
35
- 'hermes',
36
- 'aphrodite',
37
- 'demeter',
38
- 'prometheus',
39
- 'hephaestus',
40
- 'apollo',
41
- 'nyx',
42
- 'gaia',
43
- 'iris',
44
- 'mnemosyne',
45
- 'talos',
46
- ]
47
-
48
- function agentSort(a, b) {
49
- const ia = KNOWN_AGENTS_ORDER.indexOf(a)
50
- const ib = KNOWN_AGENTS_ORDER.indexOf(b)
51
- if (ia === -1 && ib === -1) return a.localeCompare(b)
52
- if (ia === -1) return 1
53
- if (ib === -1) return -1
54
- return ia - ib
55
- }
56
-
57
- function safeEnvLabel(_apiKeyEnv) {
58
- return '`[redacted]`'
59
- }
60
-
61
- function providerLabel(def) {
62
- const entries = Object.entries(def.providers ?? {})
63
- if (entries.length === 0) return '—'
64
- return entries
65
- .map(([id, p]) => `\`${id}\` \`${p.baseURL ?? ''}\` (env: ${safeEnvLabel(p.apiKeyEnv)})`)
66
- .join('<br>')
67
- }
68
-
69
- function pricingLabel(name) {
70
- const p = PRESET_PRICE[name]
71
- if (!p) return '—'
72
- return `${p.label} — ${p.detail}`
73
- }
74
-
75
- function visionLabel(def) {
76
- if (!def.vision) return '—'
77
- const m = def.vision.model
78
- let visionFlag = '—'
79
- try {
80
- visionFlag = hasVision(m) ? '👁️ vision' : 'text-only'
81
- } catch {
82
- visionFlag = 'unknown'
83
- }
84
- return `\`${m}\` [${def.vision.reasoning_effort ?? ''}] ${visionFlag}`
85
- }
86
-
87
- function capabilityBadge(model) {
88
- try {
89
- const v = hasVision(model)
90
- const cap = normalizeCapability(model, 'high')
91
- // cap.variant is clamped effort for 'high'
92
- // also get maxEffort via capabilityEntry
93
- const entry = CAPABILITY_TABLE.find(
94
- (e) =>
95
- model.startsWith(e.prefix) ||
96
- model.slice(model.lastIndexOf('/') + 1).startsWith(e.prefix) ||
97
- model.slice(model.lastIndexOf('/') + 1) === e.prefix,
98
- )
99
- // But use direct lookup via prefix matching like capabilityEntry does
100
- return { vision: v, maxEffort: entry?.maxEffort ?? 'unknown', clamped: cap.variant }
101
- } catch {
102
- return { vision: undefined, maxEffort: 'unknown', clamped: undefined }
103
- }
104
- }
105
-
106
- function buildSummaryTable() {
107
- const lines = []
108
- lines.push(
109
- '| Preset | Provider / BaseURL | Key env (nome) | Pricing 2026 | Vision (fallback) | Papéis / Modelos |',
110
- )
111
- lines.push('|---|---|---|---|---|---|')
112
- for (const name of Object.keys(presets)) {
113
- const def = presets[name]
114
- const prov = providerLabel(def)
115
- // env names redacted to avoid exposing credential-related metadata
116
- const envs =
117
- Object.values(def.providers ?? {})
118
- .map((p) => safeEnvLabel(p.apiKeyEnv))
119
- .join(', ') || '—'
120
- // Actually use providerLabel already includes env, but separate column for key env
121
- const pricing = pricingLabel(name)
122
- const vision = visionLabel(def)
123
- // Papéis grouped: planners/high, implementers/medium, scouts/low
124
- const agents = def.agents ?? {}
125
- const groups = {}
126
- for (const [agent, spec] of Object.entries(agents)) {
127
- const key = `\`${spec.model}\` [${spec.reasoning_effort ?? ''}]`
128
- if (!groups[key]) groups[key] = []
129
- groups[key].push(agent)
130
- }
131
- const papelSummary = Object.entries(groups)
132
- .map(([model, list]) => `${list.join(',')}: ${model}`)
133
- .join('<br>')
134
- lines.push(`| \`${name}\` | ${prov} | ${envs} | ${pricing} | ${vision} | ${papelSummary} |`)
135
- }
136
- return lines.join('\n')
137
- }
138
-
139
- function buildMatrixTable() {
140
- const presetNames = Object.keys(presets)
141
- const lines = []
142
- // header
143
- lines.push(
144
- `| Agente | ${presetNames.map((n) => `\`${n}\``).join(' | ')} | Capability (vision / maxEffort) |`,
145
- )
146
- lines.push(`|---|${presetNames.map(() => '---').join('|')}|---|`)
147
- // collect all agents
148
- const allAgents = new Set()
149
- for (const def of Object.values(presets))
150
- for (const a of Object.keys(def.agents ?? {})) allAgents.add(a)
151
- const sorted = [...allAgents].sort(agentSort)
152
- for (const agent of sorted) {
153
- const cells = presetNames.map((presetName) => {
154
- const spec = presets[presetName]?.agents?.[agent]
155
- if (!spec) return '—'
156
- const badge = capabilityBadge(spec.model)
157
- const visionIcon = badge.vision ? '👁️' : '—'
158
- // don't expose raw key, just model and effort
159
- return `\`${spec.model}\`<br>[${spec.reasoning_effort}] ${visionIcon}`
160
- })
161
- // capability column: pick first preset's model for reference, but show per-agent vision across presets is same family
162
- const sampleModel = presets[presetNames[0]]?.agents?.[agent]?.model ?? ''
163
- let capStr = '—'
164
- if (sampleModel) {
165
- try {
166
- const v = hasVision(sampleModel)
167
- capStr = v ? 'vision' : 'text-only'
168
- } catch {
169
- capStr = 'unknown'
170
- }
171
- }
172
- // Show effort clamp per preset? Instead show generic
173
- lines.push(`| \`${agent}\` | ${cells.join(' | ')} | ${capStr} |`)
174
- }
175
- return lines.join('\n')
176
- }
177
-
178
- function buildDetailedMatrixWithEffort() {
179
- const presetNames = Object.keys(presets)
180
- const lines = []
181
- lines.push(`| Agente | ${presetNames.map((n) => `\`${n}\``).join(' | ')} |`)
182
- lines.push(`|---|${presetNames.map(() => '---').join('|')}|`)
183
- const allAgents = new Set()
184
- for (const def of Object.values(presets))
185
- for (const a of Object.keys(def.agents ?? {})) allAgents.add(a)
186
- const sorted = [...allAgents].sort(agentSort)
187
- for (const agent of sorted) {
188
- const cells = presetNames.map((presetName) => {
189
- const spec = presets[presetName]?.agents?.[agent]
190
- if (!spec) return '—'
191
- let vision = '—'
192
- try {
193
- vision = hasVision(spec.model) ? '👁️' : '·'
194
- } catch {
195
- vision = '?'
196
- }
197
- return `\`${spec.model}\` [${spec.reasoning_effort}] ${vision}`
198
- })
199
- lines.push(`| \`${agent}\` | ${cells.join(' | ')} |`)
200
- }
201
- return lines.join('\n')
202
- }
203
-
204
- function buildProviderTable() {
205
- const lines = []
206
- lines.push('| Preset | Provider | BaseURL | Key env |')
207
- lines.push('|---|---|---|---|')
208
- for (const [name, def] of Object.entries(presets)) {
209
- for (const [pid, prov] of Object.entries(def.providers ?? {})) {
210
- const keyEnvStatus = prov.apiKeyEnv ? 'configured' : 'none'
211
- lines.push(`| \`${name}\` | \`${pid}\` | \`${prov.baseURL ?? ''}\` | \`${keyEnvStatus}\` |`)
212
- }
213
- }
214
- return lines.join('\n')
215
- }
216
-
217
- function buildPricingTable() {
218
- const lines = []
219
- lines.push('| Preset | Pricing 2026 | Detalhe | Gateway / Custo |')
220
- lines.push('|---|---|---|---|')
221
- for (const name of Object.keys(presets)) {
222
- const p = PRESET_PRICE[name] ?? { label: '—', detail: '—' }
223
- const def = presets[name]
224
- const prov = Object.keys(def.providers ?? {}).join(', ')
225
- const costHint =
226
- name === 'go-free'
227
- ? '$0 (free-tier Zen, quota limitada)'
228
- : name === 'go-fast'
229
- ? 'Baixo custo (Go gateway, baixa latência)'
230
- : name === 'go-premium'
231
- ? 'Premium (Go gateway, melhor qualidade)'
232
- : 'Pago por uso (OpenAI direto)'
233
- lines.push(`| \`${name}\` | ${p.label} | ${p.detail} | ${prov} — ${costHint} |`)
234
- }
235
- return lines.join('\n')
236
- }
237
-
238
- function buildCapabilityTable() {
239
- const lines = []
240
- lines.push('| Prefix | Max Effort | Vision | Strip Effort |')
241
- lines.push('|---|---|---|---|')
242
- for (const e of CAPABILITY_TABLE) {
243
- lines.push(
244
- `| \`${e.prefix}\` | ${e.maxEffort ?? '—'} | ${e.vision ? '👁️' : '—'} | ${e.stripEffort ? 'yes' : 'no'} |`,
245
- )
246
- }
247
- return lines.join('\n')
248
- }
249
-
250
- const args = process.argv.slice(2)
251
- if (args.includes('--json')) {
252
- const out = { presets, PRESET_PRICE, CAPABILITY_TABLE }
253
- console.log(JSON.stringify(out, null, 2))
254
- process.exit(0)
255
- }
256
- if (args.includes('--summary')) {
257
- console.log(buildSummaryTable())
258
- process.exit(0)
259
- }
260
- if (args.includes('--matrix')) {
261
- console.log(buildMatrixTable())
262
- process.exit(0)
263
- }
264
- if (args.includes('--provider')) {
265
- console.log(buildProviderTable())
266
- process.exit(0)
267
- }
268
- if (args.includes('--pricing')) {
269
- console.log(buildPricingTable())
270
- process.exit(0)
271
- }
272
- if (args.includes('--capability')) {
273
- console.log(buildCapabilityTable())
274
- process.exit(0)
275
- }
276
-
277
- // default: print all
278
- console.log(
279
- '<!-- Generated from src/routing.yml + src/pantheon/presets.mjs + scripts/install/model-picker.mjs — do not edit manually. Run: node scripts/generate-preset-docs.mjs -->',
280
- )
281
- console.log('')
282
- console.log('### Presets — resumo (provider / baseURL / key / pricing / vision)')
283
- console.log('')
284
- console.log(buildSummaryTable())
285
- console.log('')
286
- console.log('### Provider / BaseURL / Key env')
287
- console.log('')
288
- console.log(buildProviderTable())
289
- console.log('')
290
- console.log('### Pricing 2026')
291
- console.log('')
292
- console.log(buildPricingTable())
293
- console.log('')
294
- console.log('### 14 agentes × 4 presets — modelo + effort + vision')
295
- console.log('')
296
- console.log(buildDetailedMatrixWithEffort())
297
- console.log('')
298
- console.log('### Capability table (prefix → maxEffort, vision)')
299
- console.log('')
300
- console.log(buildCapabilityTable())
@@ -1,222 +0,0 @@
1
- #!/usr/bin/env bash
2
- # generate-prompts.sh — Generate dynamic prompt templates for Pantheon
3
- set -euo pipefail
4
-
5
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
- PANTHEON_DIR="$(dirname "$SCRIPT_DIR")"
7
-
8
- # ── Read active plan ─────────────────────────────────────────────────────────
9
- PLAN_FILE="$PANTHEON_DIR/.pantheon/active-preset.json"
10
- if [[ -f "$PLAN_FILE" ]]; then
11
- PLAN=$(jq -r '.plan // "unknown"' "$PLAN_FILE")
12
- SERVICE=$(jq -r '.service // "unknown"' "$PLAN_FILE")
13
- TIER=$(jq -r '.tier // "unknown"' "$PLAN_FILE")
14
- PRICE=$(jq -r '.price // "unknown"' "$PLAN_FILE")
15
- MONTHLY_REQUESTS=$(jq -r '.limits.monthlyRequests // "unlimited"' "$PLAN_FILE")
16
-
17
- # Build tier-to-model map
18
- TIER_MAP=$(jq -r '
19
- to_entries[]
20
- | select(.key | IN("free","fast","default","premium"))
21
- | " \(.key): \(.value)"
22
- ' "$PLAN_FILE" 2>/dev/null || echo " (unable to parse tiers)")
23
-
24
- # Build agent overrides map
25
- AGENT_OVERRIDES=$(jq -r '
26
- .agent_overrides // {}
27
- | to_entries[]
28
- | " \(.key): \(.value)"
29
- ' "$PLAN_FILE" 2>/dev/null || true)
30
- else
31
- PLAN="default"
32
- SERVICE="opencode"
33
- TIER="default"
34
- PRICE="unknown"
35
- MONTHLY_REQUESTS="unlimited"
36
- TIER_MAP=" default: unknown"
37
- AGENT_OVERRIDES=""
38
- fi
39
-
40
- # ── List agents ──────────────────────────────────────────────────────────────
41
- AGENTS_DIR="$PANTHEON_DIR/src/agents"
42
- AGENTS_LIST=""
43
- if [[ -d "$AGENTS_DIR" ]]; then
44
- AGENTS_LIST=$(ls "$AGENTS_DIR"/*.md 2>/dev/null | xargs -n1 basename | sed 's/\.md$//' | sort | paste -sd ', ' -)
45
- fi
46
-
47
- # ── Create dynamic prompts directory ─────────────────────────────────────────
48
- DYNAMIC_DIR="$PANTHEON_DIR/prompts/dynamic"
49
- mkdir -p "$DYNAMIC_DIR"
50
-
51
- # ── Helper: extract description from agent frontmatter ───────────────────────
52
- extract_description() {
53
- local file="$1"
54
- # Grab the first 'description:' line inside the first YAML frontmatter block
55
- sed -n '/^---$/,/^---$/p' "$file" 2>/dev/null \
56
- | grep -m1 '^description:' \
57
- | sed 's/^description:[[:space:]]*//; s/^"//; s/"$//; s/^'"'"'//; s/'"'"'$//' \
58
- || echo "No description available"
59
- }
60
-
61
- # ── Generate Agora Prompt ─────────────────────────────────────────────────────
62
- AGORA_FILE="$DYNAMIC_DIR/agora-generated.txt"
63
- cat > "$AGORA_FILE" << EOF
64
- # =============================================================================
65
- # Dynamic Agora Prompt
66
- # Generated: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
67
- # Plan: $PLAN
68
- # Service: $SERVICE
69
- # Tier: $TIER
70
- # Price: $PRICE
71
- # Monthly Requests: $MONTHLY_REQUESTS
72
- # =============================================================================
73
-
74
- You are convening an agora with access to these specialists: $AGENTS_LIST
75
-
76
- ## Platform Capabilities
77
- EOF
78
-
79
- if [[ -n "$TIER_MAP" ]]; then
80
- echo "Model Tiers:" >> "$AGORA_FILE"
81
- echo "$TIER_MAP" >> "$AGORA_FILE"
82
- echo "" >> "$AGORA_FILE"
83
- fi
84
-
85
- if [[ -n "$AGENT_OVERRIDES" ]]; then
86
- echo "Agent Overrides:" >> "$AGORA_FILE"
87
- echo "$AGENT_OVERRIDES" >> "$AGORA_FILE"
88
- echo "" >> "$AGORA_FILE"
89
- fi
90
-
91
- cat >> "$AGORA_FILE" << EOF
92
- ## Instructions
93
- 1. Select 3-5 relevant agents based on the question domain
94
- 2. Dispatch them in parallel with the same question
95
- 3. Synthesize their perspectives into a single recommendation
96
- 4. Include confidence level and next steps
97
-
98
- ## Available Specialists
99
- EOF
100
-
101
- for agent_file in "$AGENTS_DIR"/*.md; do
102
- [[ -f "$agent_file" ]] || continue
103
- agent_name=$(basename "$agent_file" .md)
104
- description=$(extract_description "$agent_file")
105
- printf -- "- @%s: %s\n" "$agent_name" "$description" >> "$AGORA_FILE"
106
- done
107
-
108
- # ── Generate Orchestration Prompt ────────────────────────────────────────────
109
- ORCH_FILE="$DYNAMIC_DIR/orchestrate-generated.txt"
110
- cat > "$ORCH_FILE" << EOF
111
- # =============================================================================
112
- # Dynamic Orchestration Prompt
113
- # Generated: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
114
- # Plan: $PLAN
115
- # Service: $SERVICE
116
- # Tier: $TIER
117
- # Price: $PRICE
118
- # Monthly Requests: $MONTHLY_REQUESTS
119
- # =============================================================================
120
-
121
- You are Zeus, the central orchestrator for the Pantheon multi-agent system.
122
-
123
- ## Active Configuration
124
- - Plan: $PLAN
125
- - Service: $SERVICE
126
- - Tier: $TIER
127
- - Price: $PRICE
128
- - Monthly Request Limit: $MONTHLY_REQUESTS
129
-
130
- ## Model Tiers
131
- EOF
132
-
133
- if [[ -n "$TIER_MAP" ]]; then
134
- echo "$TIER_MAP" >> "$ORCH_FILE"
135
- fi
136
-
137
- cat >> "$ORCH_FILE" << EOF
138
-
139
- ## Available Agents
140
- EOF
141
-
142
- for agent_file in "$AGENTS_DIR"/*.md; do
143
- [[ -f "$agent_file" ]] || continue
144
- agent_name=$(basename "$agent_file" .md)
145
- description=$(extract_description "$agent_file")
146
- printf -- "- @%s: %s\n" "$agent_name" "$description" >> "$ORCH_FILE"
147
- done
148
-
149
- cat >> "$ORCH_FILE" << EOF
150
-
151
- ## Orchestration Rules
152
- 1. **Planning**: Delegate to @athena for architecture decisions
153
- 2. **Discovery**: Delegate to @apollo for codebase investigation
154
- 3. **Implementation**: Dispatch @hermes (backend), @aphrodite (frontend), @demeter (database) in parallel when scopes are independent
155
- 4. **Review**: Always route completed work to @themis before merge
156
- 5. **Deploy**: Route infrastructure changes to @prometheus
157
- 6. **Document**: Route memory tasks to @mnemosyne
158
- 7. **Hotfix**: Route small fixes to @talos (bypass orchestration)
159
-
160
- ## Cost-Conscious Routing
161
- - Use \`fast\` tier agents for discovery, documentation, and simple queries
162
- - Use \`default\` tier agents for standard implementation work
163
- - Use \`premium\` tier agents for planning, review, and complex orchestration
164
- - Respect monthly request limits: $MONTHLY_REQUESTS
165
- EOF
166
-
167
- # ── Generate Agent Handoff Prompt ────────────────────────────────────────────
168
- HANDOFF_FILE="$DYNAMIC_DIR/handoff-generated.txt"
169
- cat > "$HANDOFF_FILE" << EOF
170
- # =============================================================================
171
- # Dynamic Agent Handoff Prompt
172
- # Generated: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
173
- # Plan: $PLAN
174
- # Service: $SERVICE
175
- # Tier: $TIER
176
- # =============================================================================
177
-
178
- ## Handoff Tier Assignments
179
- EOF
180
-
181
- if [[ -n "$TIER_MAP" ]]; then
182
- echo "$TIER_MAP" >> "$HANDOFF_FILE"
183
- echo "" >> "$HANDOFF_FILE"
184
- fi
185
-
186
- cat >> "$HANDOFF_FILE" << EOF
187
- ## Agent Directory
188
- EOF
189
-
190
- for agent_file in "$AGENTS_DIR"/*.md; do
191
- [[ -f "$agent_file" ]] || continue
192
- agent_name=$(basename "$agent_file" .md)
193
- description=$(extract_description "$agent_file")
194
- printf -- "- @%s: %s\n" "$agent_name" "$description" >> "$HANDOFF_FILE"
195
- done
196
-
197
- cat >> "$HANDOFF_FILE" << EOF
198
-
199
- ## Handoff Rules
200
- | Direction | Tier | Reason |
201
- |---|---|---|
202
- | Any → Themis | premium | Critical quality + security gate |
203
- | Any → Zeus | premium | Complex orchestration decisions |
204
- | Athena → Zeus | premium | Plan handoff needs careful execution |
205
- | Any → Mnemosyne | fast | Simple documentation writes |
206
- | Hephaestus → Prometheus | default | Infrastructure config generation |
207
- | Hephaestus | fast | Conversational AI dispatch |
208
-
209
- ## Cost Cap Rule
210
- The requested model tier cannot exceed the cost tier of the main conversation model.
211
- EOF
212
-
213
- # ── Summary ────────────────────────────────────────────────────────────────────
214
- echo "✅ Generated dynamic prompts for plan '$PLAN'"
215
- echo " Service: $SERVICE"
216
- echo " Tier: $TIER"
217
- echo " Agents: $AGENTS_LIST"
218
- echo ""
219
- echo " Output files:"
220
- echo " - $AGORA_FILE"
221
- echo " - $ORCH_FILE"
222
- echo " - $HANDOFF_FILE"
@@ -1,24 +0,0 @@
1
- /**
2
- * component.mjs — Component resolution utilities for the OpenCode installer
3
- */
4
-
5
- /** Available component identifiers */
6
- export const COMPONENT_NAMES = [
7
- 'agents',
8
- 'skills',
9
- 'instructions',
10
- 'prompts',
11
- 'commands',
12
- 'plugins',
13
- 'runtime',
14
- ]
15
-
16
- /**
17
- * Parse --components flag into a Set.
18
- * @param {string|string[]} spec - Comma-separated string or array of component names
19
- * @returns {Set<string>}
20
- */
21
- export function resolveComponents(spec) {
22
- if (Array.isArray(spec)) return new Set(spec)
23
- return new Set(spec.split(',').map((s) => s.trim()))
24
- }