opencode-swarm 7.63.0 → 7.65.0
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/.opencode/skills/swarm-pr-review/SKILL.md +124 -0
- package/README.md +57 -0
- package/dist/agents/architect.d.ts +1 -1
- package/dist/cli/index.js +192 -23
- package/dist/config/constants.d.ts +2 -0
- package/dist/config/evidence-schema.d.ts +44 -44
- package/dist/config/schema.d.ts +187 -0
- package/dist/hooks/knowledge-store.d.ts +2 -1
- package/dist/hooks/knowledge-validator.d.ts +5 -0
- package/dist/index.js +2561 -613
- package/dist/memory/schema.d.ts +2 -2
- package/dist/services/external-skill-store.d.ts +96 -0
- package/dist/services/external-skill-validator.d.ts +160 -0
- package/dist/summaries/schema.d.ts +15 -0
- package/dist/summaries/store.d.ts +5 -0
- package/dist/tools/external-skill-delete.d.ts +16 -0
- package/dist/tools/external-skill-discover.d.ts +21 -0
- package/dist/tools/external-skill-inspect.d.ts +15 -0
- package/dist/tools/external-skill-list.d.ts +15 -0
- package/dist/tools/external-skill-promote.d.ts +20 -0
- package/dist/tools/external-skill-reject.d.ts +15 -0
- package/dist/tools/external-skill-revoke.d.ts +17 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/manifest.d.ts +7 -0
- package/dist/tools/plugin-registration.d.ts +4 -1
- package/dist/tools/submit-phase-council-verdicts.d.ts +2 -0
- package/dist/tools/tool-metadata.d.ts +28 -0
- package/dist/tools/write-drift-evidence.d.ts +4 -0
- package/package.json +1 -1
|
@@ -114,6 +114,130 @@ Before launching explorers (Phase 3), confirm the PR branch refs are available:
|
|
|
114
114
|
|
|
115
115
|
If refs cannot be fetched or checked out, state the limitation in the context pack.
|
|
116
116
|
|
|
117
|
+
## Phase 0A: Existing PR Comment Ingestion
|
|
118
|
+
|
|
119
|
+
When reviewing a PR that already has comments, reviews, or bot findings,
|
|
120
|
+
ingest and triage them BEFORE starting Phase 0. These are pre-existing signals
|
|
121
|
+
that must be validated, not ignored.
|
|
122
|
+
|
|
123
|
+
### Step 1 — Fetch all PR feedback surfaces
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Issue comments (general PR thread)
|
|
127
|
+
gh pr view <PR_NUMBER> --json comments
|
|
128
|
+
|
|
129
|
+
# Review comments (inline code comments)
|
|
130
|
+
gh api repos/{owner}/{repo}/pulls/{PR_NUMBER}/comments
|
|
131
|
+
|
|
132
|
+
# Review summaries (approve/request-changes/comment events)
|
|
133
|
+
gh pr view <PR_NUMBER> --json reviews
|
|
134
|
+
|
|
135
|
+
# Bot/automated reviews (Copilot, Codex, CodeRabbit, etc.)
|
|
136
|
+
# Inline review comments — use REST API for reliable bot detection via user.type
|
|
137
|
+
gh api repos/{owner}/{repo}/pulls/{PR_NUMBER}/comments --jq '.[] | select((.user.type // "") == "Bot" or (.user.login // "" | test("bot|copilot|coderabbit|codex"; "i")))'
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
For general PR comments (not inline), use the issue comments endpoint:
|
|
141
|
+
```bash
|
|
142
|
+
gh api repos/{owner}/{repo}/issues/{PR_NUMBER}/comments --jq '.[] | select((.user.type // "") == "Bot" or (.user.login // "" | test("bot|copilot|coderabbit|codex"; "i")))'
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Step 2 — Classify each comment
|
|
146
|
+
|
|
147
|
+
| Category | Action |
|
|
148
|
+
|----------|--------|
|
|
149
|
+
| **Human review with file:line evidence** | Add as candidate finding with `source: existing-review` — still needs reviewer validation |
|
|
150
|
+
| **Bot/automated finding with specific code reference** | Add as candidate finding with `source: bot-review` — high false-positive rate, treat as unverified |
|
|
151
|
+
| **General feedback / style preference** | Add as advisory obligation |
|
|
152
|
+
| **Resolved/outdated comment** | Skip — note in report under "Ingested Resolved Comments" |
|
|
153
|
+
| **Requested changes not yet addressed** | Add as HIGH-priority obligation |
|
|
154
|
+
|
|
155
|
+
### Step 3 — Merge into review pipeline
|
|
156
|
+
|
|
157
|
+
All ingested comments become candidate findings or obligations. They follow the
|
|
158
|
+
same Phase 3-8 pipeline as freshly discovered findings. Ingested findings are
|
|
159
|
+
NOT pre-confirmed — they still require independent reviewer validation per the
|
|
160
|
+
Anti-Self-Review Rule.
|
|
161
|
+
|
|
162
|
+
**Comment-ledger output:**
|
|
163
|
+
```
|
|
164
|
+
[INGESTED] | source | category | file:line (if applicable) | original_author | status: PENDING_VALIDATION / SKIPPED_OUTDATED / ADVISORY
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Anti-patterns
|
|
168
|
+
- ✗ Ignoring bot reviews because "bots produce false positives" — they also catch real issues
|
|
169
|
+
- ✗ Pre-confirming human review comments without independent validation — even senior reviewers make mistakes
|
|
170
|
+
- ✗ Skipping inline review comments and only reading the summary — inline comments contain the evidence
|
|
171
|
+
|
|
172
|
+
## Phase 0B: Merge Conflict Detection and Resolution
|
|
173
|
+
|
|
174
|
+
Before investing effort in review lanes, verify the PR is mergeable. A
|
|
175
|
+
conflicted PR cannot merge regardless of review quality.
|
|
176
|
+
|
|
177
|
+
### Step 1 — Check merge state
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
gh pr view <PR_NUMBER> --json mergeable,mergeStateStatus
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
The response has two independent fields. Handle each:
|
|
184
|
+
|
|
185
|
+
**`mergeable` field** — whether GitHub can compute mergeability:
|
|
186
|
+
| Value | Meaning | Action |
|
|
187
|
+
|-------|---------|--------|
|
|
188
|
+
| `MERGEABLE` | No conflicts detected | Proceed — check `mergeStateStatus` below |
|
|
189
|
+
| `CONFLICTING` | Merge conflicts exist | Resolve before reviewing |
|
|
190
|
+
| `UNKNOWN` | GitHub still computing | Wait 30s, re-check |
|
|
191
|
+
|
|
192
|
+
**`mergeStateStatus` field** — overall branch state:
|
|
193
|
+
| Value | Action |
|
|
194
|
+
|-------|--------|
|
|
195
|
+
| `CLEAN` | All checks pass, no conflicts — proceed to Phase 0 |
|
|
196
|
+
| `BEHIND` | Branch behind base — note in report; non-blocking if merge queue handles it |
|
|
197
|
+
| `DIRTY` | Merge conflicts exist — resolve before reviewing |
|
|
198
|
+
| `BLOCKED` | External blocker (branch protection, failing required check) — investigate |
|
|
199
|
+
|
|
200
|
+
### Step 2 — Resolve conflicts (when CONFLICTING or DIRTY)
|
|
201
|
+
|
|
202
|
+
When the PR has merge conflicts:
|
|
203
|
+
|
|
204
|
+
1. **Determine the PR's base branch and fetch:**
|
|
205
|
+
```bash
|
|
206
|
+
BASE_REF=$(gh pr view <PR_NUMBER> --json baseRefName --jq '.baseRefName')
|
|
207
|
+
git fetch origin $BASE_REF
|
|
208
|
+
git checkout <pr-branch>
|
|
209
|
+
git merge origin/$BASE_REF --no-commit --no-ff
|
|
210
|
+
git diff --name-only --diff-filter=U # list conflicted files
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
2. **Assess conflict complexity:**
|
|
214
|
+
- **1-3 simple conflicts** (lockfile version bumps, whitespace): Resolve directly, commit, push.
|
|
215
|
+
- **4+ conflicts or semantic conflicts** (logic changes in same function): Route to coder for resolution. Do NOT guess at semantic merge resolutions.
|
|
216
|
+
|
|
217
|
+
3. **Resolve and push:**
|
|
218
|
+
```bash
|
|
219
|
+
# For simple conflicts (after resolving markers):
|
|
220
|
+
git add -A
|
|
221
|
+
git commit -m "merge: resolve conflicts with main"
|
|
222
|
+
git push origin <pr-branch>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
4. **Post-resolution verification:**
|
|
226
|
+
```bash
|
|
227
|
+
# Verify clean state
|
|
228
|
+
gh pr view <PR_NUMBER> --json mergeable,mergeStateStatus
|
|
229
|
+
# Run affected tests
|
|
230
|
+
bun test tests/unit/path/to/conflicted.test.ts --timeout 30000
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
5. **Document in report:** List all conflicted files, resolution approach, and whether semantic judgment was required.
|
|
234
|
+
|
|
235
|
+
### Conflict resolution anti-patterns
|
|
236
|
+
- ✗ Accepting "ours" or "theirs" for all conflicts without reading them
|
|
237
|
+
- ✗ Resolving semantic conflicts without understanding both sides
|
|
238
|
+
- ✗ Pushing resolution without running tests on the merged result
|
|
239
|
+
- ✗ Reviewing a conflicted PR without resolving first — review effort is wasted if the merge changes the code
|
|
240
|
+
|
|
117
241
|
---
|
|
118
242
|
|
|
119
243
|
# Default Review Workflow
|
package/README.md
CHANGED
|
@@ -35,6 +35,7 @@ Most AI coding tools let one model write code and ask that same model whether th
|
|
|
35
35
|
- 🏗️ **Specialized core, optional, and conditional agents** — architect, coder, reviewer, test_engineer, critic, explorer, sme, docs, designer, critic_oversight, critic_sounding_board, critic_drift_verifier, critic_hallucination_verifier, curator_init, curator_phase, council_generalist, council_skeptic, council_domain_expert. Run `/swarm agents` for the live roster — that is the source of truth, not this list.
|
|
36
36
|
- 🔒 **Gated pipeline** — code never ships without reviewer + test engineer approval
|
|
37
37
|
- 🔍 **DEEP_DIVE Protocol** — High-rigor, on-demand read-only codebase audit via specialized skills
|
|
38
|
+
- 🔬 **External Skill Curation Pipeline** — Opt-in discovery, quarantine, evaluation, and promotion of external skill candidates from configured sources (disabled by default; enable via `external_skills.curation_enabled: true` in config). Includes 7 tools: `external_skill_discover`, `external_skill_list`, `external_skill_inspect`, `external_skill_promote`, `external_skill_reject`, `external_skill_delete`, `external_skill_revoke`. Candidates pass through a 3-gate validation pipeline before evaluation: **prompt injection scan** (12 regex patterns), **unsafe instruction scan** (25 patterns), and **provenance integrity check** (SHA-256, timestamp, URL, publisher, and hash verification).
|
|
38
39
|
- 🔄 **Phase completion gates** — completion-verify and drift verifier gates enforced before phase completion
|
|
39
40
|
- 🔁 **Resumable sessions** — all state saved to `.swarm/`; pick up any project any day
|
|
40
41
|
- 🌐 **20 languages** — TypeScript, Python, Go, Rust, Java, Kotlin, C/C++, C#, Ruby, Swift, Dart, PHP, JavaScript, CSS, Bash, PowerShell, INI, Regex (extending: see [docs/adding-a-language.md](docs/adding-a-language.md))
|
|
@@ -624,6 +625,62 @@ Swarm provides tools for managing generated skill lifecycles:
|
|
|
624
625
|
|
|
625
626
|
- **Proposal cleanup** — When a draft skill proposal is activated via `skill_apply`, the source proposal file is deleted as part of the activation process (best-effort; permission errors are logged but do not block activation).
|
|
626
627
|
|
|
628
|
+
### External Skill Curation
|
|
629
|
+
|
|
630
|
+
Swarm provides an opt-in, quarantine-first pipeline for discovering, validating, and promoting external skills. Disabled by default — no network calls are made until explicitly enabled.
|
|
631
|
+
|
|
632
|
+
#### Enabling
|
|
633
|
+
|
|
634
|
+
```yaml
|
|
635
|
+
external_skills:
|
|
636
|
+
curation_enabled: true
|
|
637
|
+
sources:
|
|
638
|
+
- type: url
|
|
639
|
+
location: https://example.com/skills/
|
|
640
|
+
trust_level: medium
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
#### Validation Pipeline
|
|
644
|
+
|
|
645
|
+
Every candidate passes a 3-gate pipeline before entering quarantine:
|
|
646
|
+
|
|
647
|
+
| Gate | Name | Description |
|
|
648
|
+
|------|------|-------------|
|
|
649
|
+
| 1 | Prompt Injection Scan | 12 regex patterns plus oversized field, invisible character, and suspicious formatting checks detect system instruction injection, role hijacking, and instruction override attempts |
|
|
650
|
+
| 2 | Unsafe Instruction Scan | 25 patterns detect shell commands, file system attacks, network exfiltration, and privilege escalation |
|
|
651
|
+
| 3 | Provenance Integrity | SHA-256 content hash, timestamp validation, URL format checks, and publisher presence validation |
|
|
652
|
+
|
|
653
|
+
**Trust level modulation**: `low` trust promotes warning-severity findings to errors (stricter); `medium` and `high` trust levels keep warnings advisory. Error-severity findings always block regardless of trust level.
|
|
654
|
+
|
|
655
|
+
#### Tool Reference
|
|
656
|
+
|
|
657
|
+
| Tool | Description |
|
|
658
|
+
|------|-------------|
|
|
659
|
+
| `external_skill_discover` | Fetch and validate a skill from a configured source |
|
|
660
|
+
| `external_skill_list` | List candidates with status filters |
|
|
661
|
+
| `external_skill_inspect` | View full candidate details |
|
|
662
|
+
| `external_skill_promote` | Promote validated candidate to active skill (user approval required) |
|
|
663
|
+
| `external_skill_reject` | Reject candidate with reason |
|
|
664
|
+
| `external_skill_delete` | Remove candidate from quarantine store |
|
|
665
|
+
| `external_skill_revoke` | Retire a previously promoted skill |
|
|
666
|
+
|
|
667
|
+
#### Security Guarantees
|
|
668
|
+
|
|
669
|
+
- Disabled by default — no network calls until explicitly enabled
|
|
670
|
+
- All candidates quarantined until human review and promotion
|
|
671
|
+
- TOCTOU re-validation at promotion time
|
|
672
|
+
- Content hash verification prevents tampering
|
|
673
|
+
- Bounded concurrent fetches (5 simultaneous) and discovery limits (50 candidates per invocation)
|
|
674
|
+
- Max candidate size and count bounds
|
|
675
|
+
- Source origin validation (URLs must match configured sources)
|
|
676
|
+
|
|
677
|
+
#### Limitations
|
|
678
|
+
|
|
679
|
+
- Static regex patterns only (no LLM-based detection)
|
|
680
|
+
- No cryptographic signing (deferred)
|
|
681
|
+
- No batch import (deferred)
|
|
682
|
+
- No auto-promotion (human approval always required)
|
|
683
|
+
|
|
627
684
|
### Configuration Reference
|
|
628
685
|
|
|
629
686
|
| Key | Type | Default | Description |
|
|
@@ -70,4 +70,4 @@ export declare function buildCouncilWorkflow(council?: CouncilWorkflowConfig): s
|
|
|
70
70
|
* BRAINSTORM, and PLAN inline paths stay in lockstep.
|
|
71
71
|
*/
|
|
72
72
|
export declare function buildQaGateSelectionDialogue(modeLabel: 'BRAINSTORM' | 'SPECIFY' | 'PLAN'): string;
|
|
73
|
-
export declare function createArchitectAgent(model: string, customPrompt?: string, customAppendPrompt?: string, adversarialTesting?: AdversarialTestingConfig, council?: CouncilWorkflowConfig, uiReview?: UIReviewConfig, memoryEnabled?: boolean, architecturalSupervision?: ArchitectureSupervisionWorkflowConfig, designDocsEnabled?: boolean): AgentDefinition;
|
|
73
|
+
export declare function createArchitectAgent(model: string, customPrompt?: string, customAppendPrompt?: string, adversarialTesting?: AdversarialTestingConfig, council?: CouncilWorkflowConfig, uiReview?: UIReviewConfig, memoryEnabled?: boolean, architecturalSupervision?: ArchitectureSupervisionWorkflowConfig, designDocsEnabled?: boolean, externalSkillsEnabled?: boolean): AgentDefinition;
|
package/dist/cli/index.js
CHANGED
|
@@ -52,7 +52,7 @@ var package_default;
|
|
|
52
52
|
var init_package = __esm(() => {
|
|
53
53
|
package_default = {
|
|
54
54
|
name: "opencode-swarm",
|
|
55
|
-
version: "7.
|
|
55
|
+
version: "7.65.0",
|
|
56
56
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
57
57
|
main: "dist/index.js",
|
|
58
58
|
types: "dist/index.d.ts",
|
|
@@ -17629,6 +17629,34 @@ var init_tool_metadata = __esm(() => {
|
|
|
17629
17629
|
apply_patch: {
|
|
17630
17630
|
description: "Apply a unified diff patch to workspace files with exact context matching, atomic writes, and path validation",
|
|
17631
17631
|
agents: ["coder"]
|
|
17632
|
+
},
|
|
17633
|
+
external_skill_discover: {
|
|
17634
|
+
description: "Discover external skill candidates from configured sources. Returns a disabled message when external_skills.curation_enabled is false.",
|
|
17635
|
+
agents: []
|
|
17636
|
+
},
|
|
17637
|
+
external_skill_list: {
|
|
17638
|
+
description: "List external skill candidates in the quarantine store. Returns a disabled message when external_skills.curation_enabled is false.",
|
|
17639
|
+
agents: []
|
|
17640
|
+
},
|
|
17641
|
+
external_skill_inspect: {
|
|
17642
|
+
description: "Inspect a specific external skill candidate by ID. Returns a disabled message when external_skills.curation_enabled is false.",
|
|
17643
|
+
agents: []
|
|
17644
|
+
},
|
|
17645
|
+
external_skill_promote: {
|
|
17646
|
+
description: "Promote a validated external skill candidate to an active generated skill. Returns a disabled message when external_skills.curation_enabled is false.",
|
|
17647
|
+
agents: []
|
|
17648
|
+
},
|
|
17649
|
+
external_skill_reject: {
|
|
17650
|
+
description: "Reject an external skill candidate after evaluation. Returns a disabled message when external_skills.curation_enabled is false.",
|
|
17651
|
+
agents: []
|
|
17652
|
+
},
|
|
17653
|
+
external_skill_delete: {
|
|
17654
|
+
description: "Delete an external skill candidate from the quarantine store. Returns a disabled message when external_skills.curation_enabled is false.",
|
|
17655
|
+
agents: []
|
|
17656
|
+
},
|
|
17657
|
+
external_skill_revoke: {
|
|
17658
|
+
description: "Revoke a previously promoted external skill. Returns a disabled message when external_skills.curation_enabled is false.",
|
|
17659
|
+
agents: []
|
|
17632
17660
|
}
|
|
17633
17661
|
};
|
|
17634
17662
|
TOOL_NAMES = Object.keys(TOOL_METADATA);
|
|
@@ -17682,7 +17710,7 @@ function freezeSet(items) {
|
|
|
17682
17710
|
});
|
|
17683
17711
|
return proxy;
|
|
17684
17712
|
}
|
|
17685
|
-
var OPENCODE_NATIVE_AGENTS, CLAUDE_CODE_NATIVE_COMMANDS, DEFAULT_AGENT_CONFIGS;
|
|
17713
|
+
var OPENCODE_NATIVE_AGENTS, CLAUDE_CODE_NATIVE_COMMANDS, EXTERNAL_SKILL_TOOL_NAMES, EXTERNAL_SKILL_AGENT_TOOL_MAP, DEFAULT_AGENT_CONFIGS;
|
|
17686
17714
|
var init_constants = __esm(() => {
|
|
17687
17715
|
init_agent_names();
|
|
17688
17716
|
init_tool_metadata();
|
|
@@ -17803,6 +17831,18 @@ var init_constants = __esm(() => {
|
|
|
17803
17831
|
"team-onboarding",
|
|
17804
17832
|
"bashes"
|
|
17805
17833
|
]);
|
|
17834
|
+
EXTERNAL_SKILL_TOOL_NAMES = [
|
|
17835
|
+
"external_skill_discover",
|
|
17836
|
+
"external_skill_list",
|
|
17837
|
+
"external_skill_inspect",
|
|
17838
|
+
"external_skill_promote",
|
|
17839
|
+
"external_skill_reject",
|
|
17840
|
+
"external_skill_delete",
|
|
17841
|
+
"external_skill_revoke"
|
|
17842
|
+
];
|
|
17843
|
+
EXTERNAL_SKILL_AGENT_TOOL_MAP = {
|
|
17844
|
+
architect: [...EXTERNAL_SKILL_TOOL_NAMES]
|
|
17845
|
+
};
|
|
17806
17846
|
DEFAULT_AGENT_CONFIGS = {
|
|
17807
17847
|
coder: {
|
|
17808
17848
|
model: "opencode/minimax-m2.5-free",
|
|
@@ -17908,7 +17948,26 @@ function getCanonicalAgentRole(agentName, generatedAgentNames) {
|
|
|
17908
17948
|
function stripKnownSwarmPrefix(agentName) {
|
|
17909
17949
|
return getCanonicalAgentRole(agentName);
|
|
17910
17950
|
}
|
|
17911
|
-
|
|
17951
|
+
function resolveExternalSkillsConfig(input) {
|
|
17952
|
+
if (input === undefined || input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
17953
|
+
return { ...DEFAULT_EXTERNAL_SKILLS_CONFIG };
|
|
17954
|
+
}
|
|
17955
|
+
const config2 = input;
|
|
17956
|
+
const merged = {
|
|
17957
|
+
curation_enabled: config2.curation_enabled ?? DEFAULT_EXTERNAL_SKILLS_CONFIG.curation_enabled,
|
|
17958
|
+
max_candidates: config2.max_candidates ?? DEFAULT_EXTERNAL_SKILLS_CONFIG.max_candidates,
|
|
17959
|
+
max_bytes_per_candidate: config2.max_bytes_per_candidate ?? DEFAULT_EXTERNAL_SKILLS_CONFIG.max_bytes_per_candidate,
|
|
17960
|
+
eviction_policy: config2.eviction_policy ?? DEFAULT_EXTERNAL_SKILLS_CONFIG.eviction_policy,
|
|
17961
|
+
ttl_days: config2.ttl_days ?? DEFAULT_EXTERNAL_SKILLS_CONFIG.ttl_days,
|
|
17962
|
+
evaluation_enabled: config2.evaluation_enabled ?? DEFAULT_EXTERNAL_SKILLS_CONFIG.evaluation_enabled,
|
|
17963
|
+
sources: Array.isArray(config2.sources) ? config2.sources : [],
|
|
17964
|
+
max_candidates_per_discovery: config2.max_candidates_per_discovery ?? DEFAULT_EXTERNAL_SKILLS_CONFIG.max_candidates_per_discovery,
|
|
17965
|
+
max_concurrent_fetches: config2.max_concurrent_fetches ?? DEFAULT_EXTERNAL_SKILLS_CONFIG.max_concurrent_fetches,
|
|
17966
|
+
fetch_timeout_ms: config2.fetch_timeout_ms ?? DEFAULT_EXTERNAL_SKILLS_CONFIG.fetch_timeout_ms
|
|
17967
|
+
};
|
|
17968
|
+
return merged;
|
|
17969
|
+
}
|
|
17970
|
+
var SEPARATORS, CANONICAL_ROLES_LONGEST_FIRST, CANONICAL_ROLES_SET, AgentOverrideConfigSchema, SwarmConfigSchema, HooksConfigSchema, ScoringWeightsSchema, DecisionDecaySchema, TokenRatiosSchema, ScoringConfigSchema, ContextBudgetConfigSchema, EvidenceConfigSchema, GateFeatureSchema, PlaceholderScanConfigSchema, QualityBudgetConfigSchema, GateConfigSchema, PipelineConfigSchema, PhaseCompleteConfigSchema, SummaryConfigSchema, ReviewPassesConfigSchema, AdversarialDetectionConfigSchema, AdversarialTestingConfigSchemaBase, AdversarialTestingConfigSchema, IntegrationAnalysisConfigSchema, DocsConfigSchema, DesignDocsConfigSchema, UIReviewConfigSchema, CompactionAdvisoryConfigSchema, LintConfigSchema, SecretscanConfigSchema, GuardrailsProfileSchema, DEFAULT_AGENT_PROFILES, DEFAULT_ARCHITECT_PROFILE, GuardrailsConfigSchema, WatchdogConfigSchema, SelfReviewConfigSchema, ToolFilterConfigSchema, PlanCursorConfigSchema, ContextMapConfigSchema, CheckpointConfigSchema, AutomationModeSchema, AutomationCapabilitiesSchema, AutomationConfigSchemaBase, AutomationConfigSchema, KnowledgeConfigSchema, MemoryConfigSchema, CuratorConfigSchema, ArchitecturalSupervisionConfigSchema, KnowledgeApplicationConfigSchema, SkillPropagationConfigSchema, SkillImproverConfigSchema, SpecWriterConfigSchema, SlopDetectorConfigSchema, IncrementalVerifyConfigSchema, CompactionConfigSchema, PrmConfigSchema, AgentAuthorityRuleSchema, AuthorityConfigSchema, GeneralCouncilMemberConfigSchema, GeneralCouncilConfigSchema, CouncilConfigSchema, ParallelizationConfigSchema, WorktreeIsolationConfigSchema, LeanTurboConfigSchema, StandardTurboConfigSchema, LeanTurboStrategyConfigSchema, TurboConfigSchema, ExternalSkillCandidateSourceTypeSchema, ExternalSkillCandidateEvaluationVerdictSchema, DiscoverySourceSchema, ExternalSkillCandidateSchema, ExternalSkillsConfigSchema, DEFAULT_EXTERNAL_SKILLS_CONFIG, PluginConfigSchema;
|
|
17912
17971
|
var init_schema = __esm(() => {
|
|
17913
17972
|
init_zod();
|
|
17914
17973
|
init_constants();
|
|
@@ -18459,7 +18518,8 @@ var init_schema = __esm(() => {
|
|
|
18459
18518
|
max_agent_summary_words: exports_external.number().int().min(20).max(500).default(100),
|
|
18460
18519
|
max_phase_summary_words: exports_external.number().int().min(50).max(1000).default(250),
|
|
18461
18520
|
allow_concerns_to_complete: exports_external.boolean().default(true),
|
|
18462
|
-
persist_knowledge_recommendations: exports_external.boolean().default(false)
|
|
18521
|
+
persist_knowledge_recommendations: exports_external.boolean().default(false),
|
|
18522
|
+
provenance_verify: exports_external.boolean().default(false)
|
|
18463
18523
|
});
|
|
18464
18524
|
KnowledgeApplicationConfigSchema = exports_external.object({
|
|
18465
18525
|
enabled: exports_external.boolean().default(true),
|
|
@@ -18624,6 +18684,93 @@ var init_schema = __esm(() => {
|
|
|
18624
18684
|
StandardTurboConfigSchema,
|
|
18625
18685
|
LeanTurboStrategyConfigSchema
|
|
18626
18686
|
]);
|
|
18687
|
+
ExternalSkillCandidateSourceTypeSchema = exports_external.enum([
|
|
18688
|
+
"github",
|
|
18689
|
+
"url",
|
|
18690
|
+
"collection",
|
|
18691
|
+
"manual_import"
|
|
18692
|
+
]);
|
|
18693
|
+
ExternalSkillCandidateEvaluationVerdictSchema = exports_external.enum([
|
|
18694
|
+
"pending",
|
|
18695
|
+
"in_review",
|
|
18696
|
+
"quarantined",
|
|
18697
|
+
"passed",
|
|
18698
|
+
"rejected",
|
|
18699
|
+
"promoted",
|
|
18700
|
+
"revoked"
|
|
18701
|
+
]);
|
|
18702
|
+
DiscoverySourceSchema = exports_external.object({
|
|
18703
|
+
type: ExternalSkillCandidateSourceTypeSchema,
|
|
18704
|
+
location: exports_external.string().min(1),
|
|
18705
|
+
enabled: exports_external.boolean().default(true),
|
|
18706
|
+
trust_level: exports_external.enum(["low", "medium", "high"]).default("low").optional()
|
|
18707
|
+
});
|
|
18708
|
+
ExternalSkillCandidateSchema = exports_external.object({
|
|
18709
|
+
id: exports_external.string().uuid(),
|
|
18710
|
+
source_url: exports_external.string().url(),
|
|
18711
|
+
source_type: ExternalSkillCandidateSourceTypeSchema,
|
|
18712
|
+
publisher: exports_external.string().min(1),
|
|
18713
|
+
sha256: exports_external.string().regex(/^[a-f0-9]{64}$/),
|
|
18714
|
+
fetched_at: exports_external.string().datetime(),
|
|
18715
|
+
skill_name: exports_external.string().optional(),
|
|
18716
|
+
skill_description: exports_external.string().optional(),
|
|
18717
|
+
skill_body: exports_external.string(),
|
|
18718
|
+
risk_flags: exports_external.array(exports_external.string()).default([]),
|
|
18719
|
+
evaluation_verdict: ExternalSkillCandidateEvaluationVerdictSchema.default("pending"),
|
|
18720
|
+
evaluation_history: exports_external.array(exports_external.object({
|
|
18721
|
+
verdict: ExternalSkillCandidateEvaluationVerdictSchema,
|
|
18722
|
+
timestamp: exports_external.string().datetime(),
|
|
18723
|
+
actor: exports_external.string(),
|
|
18724
|
+
reason: exports_external.string().optional(),
|
|
18725
|
+
candidate_id: exports_external.string().optional(),
|
|
18726
|
+
original_verdict: ExternalSkillCandidateEvaluationVerdictSchema.optional(),
|
|
18727
|
+
gate_results: exports_external.array(exports_external.object({
|
|
18728
|
+
gate: exports_external.string(),
|
|
18729
|
+
verdict: exports_external.string()
|
|
18730
|
+
})).optional(),
|
|
18731
|
+
risk_assessment: exports_external.object({
|
|
18732
|
+
total_flags: exports_external.number().int().nonnegative(),
|
|
18733
|
+
findings: exports_external.array(exports_external.object({
|
|
18734
|
+
severity: exports_external.enum(["error", "warning"]),
|
|
18735
|
+
category: exports_external.string()
|
|
18736
|
+
}))
|
|
18737
|
+
}).optional(),
|
|
18738
|
+
risk_flags_count: exports_external.number().int().nonnegative().optional(),
|
|
18739
|
+
provenance_snapshot: exports_external.object({
|
|
18740
|
+
sha256: exports_external.string(),
|
|
18741
|
+
source_url: exports_external.string(),
|
|
18742
|
+
publisher: exports_external.string(),
|
|
18743
|
+
fetched_at: exports_external.string().datetime().optional()
|
|
18744
|
+
}).optional(),
|
|
18745
|
+
target_path: exports_external.string().optional(),
|
|
18746
|
+
promoted_content_hash: exports_external.string().regex(/^[a-f0-9]{64}$/).optional(),
|
|
18747
|
+
original_evaluation: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
18748
|
+
})).default([])
|
|
18749
|
+
});
|
|
18750
|
+
ExternalSkillsConfigSchema = exports_external.object({
|
|
18751
|
+
curation_enabled: exports_external.boolean().default(false),
|
|
18752
|
+
max_candidates: exports_external.number().int().min(1).max(1e4).default(500),
|
|
18753
|
+
max_bytes_per_candidate: exports_external.number().int().min(1024).max(10485760).default(1048576),
|
|
18754
|
+
eviction_policy: exports_external.enum(["fifo"]).default("fifo"),
|
|
18755
|
+
ttl_days: exports_external.number().int().min(1).max(3650).default(90),
|
|
18756
|
+
evaluation_enabled: exports_external.boolean().default(false),
|
|
18757
|
+
sources: exports_external.array(DiscoverySourceSchema).default([]),
|
|
18758
|
+
max_candidates_per_discovery: exports_external.number().int().min(1).max(1000).default(50),
|
|
18759
|
+
max_concurrent_fetches: exports_external.number().int().min(1).max(20).default(5),
|
|
18760
|
+
fetch_timeout_ms: exports_external.number().int().min(1000).max(300000).default(30000)
|
|
18761
|
+
});
|
|
18762
|
+
DEFAULT_EXTERNAL_SKILLS_CONFIG = {
|
|
18763
|
+
curation_enabled: false,
|
|
18764
|
+
max_candidates: 500,
|
|
18765
|
+
max_bytes_per_candidate: 1048576,
|
|
18766
|
+
eviction_policy: "fifo",
|
|
18767
|
+
ttl_days: 90,
|
|
18768
|
+
evaluation_enabled: false,
|
|
18769
|
+
sources: [],
|
|
18770
|
+
max_candidates_per_discovery: 50,
|
|
18771
|
+
max_concurrent_fetches: 5,
|
|
18772
|
+
fetch_timeout_ms: 30000
|
|
18773
|
+
};
|
|
18627
18774
|
PluginConfigSchema = exports_external.object({
|
|
18628
18775
|
agents: exports_external.record(exports_external.string(), AgentOverrideConfigSchema).optional(),
|
|
18629
18776
|
default_agent: exports_external.string().optional().transform((v) => {
|
|
@@ -18842,7 +18989,8 @@ var init_schema = __esm(() => {
|
|
|
18842
18989
|
every_architect_turns: 5,
|
|
18843
18990
|
every_minutes: 20
|
|
18844
18991
|
}
|
|
18845
|
-
}))
|
|
18992
|
+
})),
|
|
18993
|
+
external_skills: ExternalSkillsConfigSchema.optional()
|
|
18846
18994
|
});
|
|
18847
18995
|
});
|
|
18848
18996
|
|
|
@@ -18981,6 +19129,24 @@ function migratePresetsConfig(raw) {
|
|
|
18981
19129
|
}
|
|
18982
19130
|
return raw;
|
|
18983
19131
|
}
|
|
19132
|
+
function sanitizeExternalSkillsConfig(raw) {
|
|
19133
|
+
if (!("external_skills" in raw) || raw.external_skills === undefined) {
|
|
19134
|
+
return raw;
|
|
19135
|
+
}
|
|
19136
|
+
const esResult = ExternalSkillsConfigSchema.safeParse(raw.external_skills);
|
|
19137
|
+
if (esResult.success) {
|
|
19138
|
+
return {
|
|
19139
|
+
...raw,
|
|
19140
|
+
external_skills: resolveExternalSkillsConfig(esResult.data)
|
|
19141
|
+
};
|
|
19142
|
+
}
|
|
19143
|
+
console.warn("[opencode-swarm] external_skills config validation failed:");
|
|
19144
|
+
console.warn(esResult.error.format());
|
|
19145
|
+
console.warn("[opencode-swarm] External skills curation disabled due to invalid config. Fix the external_skills section to enable it.");
|
|
19146
|
+
const cleaned = { ...raw };
|
|
19147
|
+
delete cleaned.external_skills;
|
|
19148
|
+
return cleaned;
|
|
19149
|
+
}
|
|
18984
19150
|
function loadPluginConfig(directory) {
|
|
18985
19151
|
const userConfigPath = path7.join(getUserConfigDir(), "opencode", CONFIG_FILENAME);
|
|
18986
19152
|
const projectConfigPath = path7.join(directory, ".opencode", CONFIG_FILENAME);
|
|
@@ -18995,10 +19161,11 @@ function loadPluginConfig(directory) {
|
|
|
18995
19161
|
mergedRaw = deepMerge(mergedRaw, rawProjectConfig);
|
|
18996
19162
|
}
|
|
18997
19163
|
mergedRaw = migratePresetsConfig(mergedRaw);
|
|
19164
|
+
mergedRaw = sanitizeExternalSkillsConfig(mergedRaw);
|
|
18998
19165
|
const result = PluginConfigSchema.safeParse(mergedRaw);
|
|
18999
19166
|
if (!result.success) {
|
|
19000
19167
|
if (rawUserConfig) {
|
|
19001
|
-
const userParseResult = PluginConfigSchema.safeParse(rawUserConfig);
|
|
19168
|
+
const userParseResult = PluginConfigSchema.safeParse(sanitizeExternalSkillsConfig(rawUserConfig ?? {}));
|
|
19002
19169
|
if (userParseResult.success) {
|
|
19003
19170
|
console.warn("[opencode-swarm] Project config ignored due to validation errors. Using user config.");
|
|
19004
19171
|
return userParseResult.data;
|
|
@@ -36960,13 +37127,12 @@ async function enforceKnowledgeCap(filePath, maxEntries) {
|
|
|
36960
37127
|
return entries.slice(entries.length - maxEntries);
|
|
36961
37128
|
});
|
|
36962
37129
|
}
|
|
36963
|
-
async function appendRejectedLesson(directory, lesson) {
|
|
37130
|
+
async function appendRejectedLesson(directory, lesson, maxEntries = 20) {
|
|
36964
37131
|
const filePath = resolveSwarmRejectedPath(directory);
|
|
36965
|
-
const MAX = 20;
|
|
36966
37132
|
await transactKnowledge(filePath, (existing) => {
|
|
36967
37133
|
const updated = [...existing, lesson];
|
|
36968
|
-
if (updated.length >
|
|
36969
|
-
return updated.slice(updated.length -
|
|
37134
|
+
if (updated.length > maxEntries) {
|
|
37135
|
+
return updated.slice(updated.length - maxEntries);
|
|
36970
37136
|
}
|
|
36971
37137
|
return updated;
|
|
36972
37138
|
});
|
|
@@ -37648,7 +37814,8 @@ var init_knowledge_validator = __esm(() => {
|
|
|
37648
37814
|
SOURCE_REF_FORBIDDEN = /(\.\.\/|\.\.\\|\0|[\x00-\x1f\x7f])/;
|
|
37649
37815
|
ALLOWED_SKILL_PATH_PREFIXES = [
|
|
37650
37816
|
".opencode/skills/generated/",
|
|
37651
|
-
".swarm/skills/proposals/"
|
|
37817
|
+
".swarm/skills/proposals/",
|
|
37818
|
+
".swarm/skills/candidates/"
|
|
37652
37819
|
];
|
|
37653
37820
|
VALID_DIRECTIVE_PRIORITIES = new Set([
|
|
37654
37821
|
"low",
|
|
@@ -40530,18 +40697,20 @@ async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, c
|
|
|
40530
40697
|
scope: "global",
|
|
40531
40698
|
confidence: computeConfidence(0, true)
|
|
40532
40699
|
};
|
|
40533
|
-
|
|
40534
|
-
|
|
40535
|
-
|
|
40536
|
-
|
|
40537
|
-
|
|
40538
|
-
|
|
40539
|
-
|
|
40540
|
-
|
|
40541
|
-
|
|
40542
|
-
|
|
40543
|
-
|
|
40544
|
-
|
|
40700
|
+
if (config3.validation_enabled !== false) {
|
|
40701
|
+
const result = validateLesson(lesson, snapshotPlusNew.map((e) => e.lesson), meta3);
|
|
40702
|
+
if (result.valid === false || result.severity === "error") {
|
|
40703
|
+
const rejectedLesson = {
|
|
40704
|
+
id: crypto.randomUUID(),
|
|
40705
|
+
lesson,
|
|
40706
|
+
rejection_reason: result.reason ?? "unknown",
|
|
40707
|
+
rejected_at: new Date().toISOString(),
|
|
40708
|
+
rejection_layer: result.layer ?? 1
|
|
40709
|
+
};
|
|
40710
|
+
await appendRejectedLesson(directory, rejectedLesson, config3.rejected_max_entries);
|
|
40711
|
+
rejected++;
|
|
40712
|
+
continue;
|
|
40713
|
+
}
|
|
40545
40714
|
}
|
|
40546
40715
|
const duplicate = findNearDuplicate(lesson, snapshotPlusNew, config3.dedup_threshold);
|
|
40547
40716
|
if (duplicate) {
|
|
@@ -7,6 +7,8 @@ export declare const OPENCODE_NATIVE_AGENTS: Set<"compaction" | "title" | "build
|
|
|
7
7
|
export declare const CLAUDE_CODE_NATIVE_COMMANDS: ReadonlySet<string>;
|
|
8
8
|
export declare const MEMORY_TOOL_NAMES: readonly ["swarm_memory_recall", "swarm_memory_propose"];
|
|
9
9
|
export declare const MEMORY_AGENT_TOOL_MAP: Partial<Record<AgentName, ToolName[]>>;
|
|
10
|
+
export declare const EXTERNAL_SKILL_TOOL_NAMES: readonly ["external_skill_discover", "external_skill_list", "external_skill_inspect", "external_skill_promote", "external_skill_reject", "external_skill_delete", "external_skill_revoke"];
|
|
11
|
+
export declare const EXTERNAL_SKILL_AGENT_TOOL_MAP: Partial<Record<AgentName, ToolName[]>>;
|
|
10
12
|
/**
|
|
11
13
|
* Human-readable descriptions for tools shown in the architect Available Tools block.
|
|
12
14
|
* Used to generate the Available Tools section of the architect prompt at construction time.
|