@soleur/opencode 0.0.0-stage → 1.0.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/.claude-plugin/agents.manifest.json +476 -0
- package/.claude-plugin/plugin.json +42 -0
- package/README.md +44 -2
- package/agents/community/.gitkeep +0 -0
- package/agents/engineering/cto.md +87 -0
- package/agents/engineering/design/ddd-architect.md +95 -0
- package/agents/engineering/discovery/agent-finder.md +214 -0
- package/agents/engineering/discovery/functional-discovery.md +182 -0
- package/agents/engineering/infra/infra-security.md +151 -0
- package/agents/engineering/infra/platform-strategist.md +109 -0
- package/agents/engineering/infra/terraform-architect.md +171 -0
- package/agents/engineering/prompt-engineer.md +37 -0
- package/agents/engineering/research/best-practices-researcher.md +115 -0
- package/agents/engineering/research/framework-docs-researcher.md +93 -0
- package/agents/engineering/research/git-history-analyzer.md +53 -0
- package/agents/engineering/research/learnings-researcher.md +285 -0
- package/agents/engineering/research/repo-research-analyst.md +118 -0
- package/agents/engineering/review/agent-native-reviewer.md +279 -0
- package/agents/engineering/review/architecture-strategist.md +61 -0
- package/agents/engineering/review/code-quality-analyst.md +92 -0
- package/agents/engineering/review/code-simplicity-reviewer.md +109 -0
- package/agents/engineering/review/data-integrity-guardian.md +82 -0
- package/agents/engineering/review/data-migration-expert.md +98 -0
- package/agents/engineering/review/deployment-verification-agent.md +183 -0
- package/agents/engineering/review/dhh-rails-reviewer.md +46 -0
- package/agents/engineering/review/kieran-rails-reviewer.md +87 -0
- package/agents/engineering/review/legacy-code-expert.md +55 -0
- package/agents/engineering/review/observability-coverage-reviewer.md +147 -0
- package/agents/engineering/review/pattern-recognition-specialist.md +59 -0
- package/agents/engineering/review/performance-oracle.md +130 -0
- package/agents/engineering/review/security-sentinel.md +167 -0
- package/agents/engineering/review/semgrep-sast.md +36 -0
- package/agents/engineering/review/test-design-reviewer.md +150 -0
- package/agents/engineering/review/user-impact-reviewer.md +70 -0
- package/agents/engineering/workflow/pr-comment-resolver.md +69 -0
- package/agents/finance/budget-analyst.md +29 -0
- package/agents/finance/cfo.md +44 -0
- package/agents/finance/financial-reporter.md +30 -0
- package/agents/finance/revenue-analyst.md +30 -0
- package/agents/legal/clo.md +115 -0
- package/agents/legal/legal-compliance-auditor.md +110 -0
- package/agents/legal/legal-document-generator.md +134 -0
- package/agents/marketing/analytics-analyst.md +25 -0
- package/agents/marketing/brand-architect.md +181 -0
- package/agents/marketing/cmo.md +76 -0
- package/agents/marketing/conversion-optimizer.md +19 -0
- package/agents/marketing/copywriter.md +20 -0
- package/agents/marketing/fact-checker.md +70 -0
- package/agents/marketing/growth-strategist.md +145 -0
- package/agents/marketing/paid-media-strategist.md +28 -0
- package/agents/marketing/pricing-strategist.md +17 -0
- package/agents/marketing/programmatic-seo-specialist.md +25 -0
- package/agents/marketing/retention-strategist.md +23 -0
- package/agents/marketing/seo-aeo-analyst.md +164 -0
- package/agents/operations/coo.md +50 -0
- package/agents/operations/ops-advisor.md +78 -0
- package/agents/operations/ops-provisioner.md +101 -0
- package/agents/operations/ops-research.md +52 -0
- package/agents/operations/service-automator.md +278 -0
- package/agents/product/business-validator.md +206 -0
- package/agents/product/competitive-intelligence.md +89 -0
- package/agents/product/cpo.md +63 -0
- package/agents/product/design/ux-design-lead.md +209 -0
- package/agents/product/spec-flow-analyzer.md +122 -0
- package/agents/sales/cro.md +44 -0
- package/agents/sales/deal-architect.md +29 -0
- package/agents/sales/outbound-strategist.md +29 -0
- package/agents/sales/pipeline-analyst.md +29 -0
- package/agents/support/cco.md +48 -0
- package/agents/support/community-manager.md +570 -0
- package/agents/support/ticket-triage.md +70 -0
- package/bin/soleur-opencode.js +29 -0
- package/commands/go.md +659 -0
- package/commands/help.md +273 -0
- package/commands/sync.md +977 -0
- package/commands/version.md +103 -0
- package/hooks/antigravity-hooks.json +84 -0
- package/hooks/antigravity-session-start.sh +15 -0
- package/hooks/bare-root-cwd-guard.sh +131 -0
- package/hooks/browser-snapshot-credential-guard.sh +200 -0
- package/hooks/codex-session-start.sh +9 -0
- package/hooks/compaction-state.sh +525 -0
- package/hooks/destructive-command-guard.sh +1387 -0
- package/hooks/devin-session-start.sh +90 -0
- package/hooks/ext-filter-detect.sh +171 -0
- package/hooks/hooks.json +133 -0
- package/hooks/lib/hook-tool-kind.sh +24 -0
- package/hooks/lib/log-rotation.sh +176 -0
- package/hooks/lib/shell-argv.pl +576 -0
- package/hooks/memory-backstop.sh +1114 -0
- package/hooks/operator-stage-approval.sh +391 -0
- package/hooks/stop-hook.sh +367 -0
- package/hooks/unkept-promise-hook.sh +383 -0
- package/hooks/version-banner.sh +127 -0
- package/hooks/welcome-hook.sh +50 -0
- package/install.js +108 -0
- package/lib/agent-registry.ts +154 -0
- package/lib/c4-canonical-cli.mjs +34 -0
- package/lib/c4-canonical.mjs +46 -0
- package/lib/c4-from-components.ts +554 -0
- package/lib/go-routing.ts +81 -0
- package/lib/grok-inspect-contract.ts +311 -0
- package/lib/harness-model-map.ts +101 -0
- package/lib/harness-parity.ts +726 -0
- package/lib/harness-tool-map.ts +180 -0
- package/lib/harness.ts +716 -0
- package/lib/heartbeat-live-reconcile.ts +1153 -0
- package/lib/heartbeat-manifest.ts +342 -0
- package/lib/kb-coverage.ts +252 -0
- package/lib/pr-merge-poll.ts +103 -0
- package/lib/workflow-fidelity.ts +388 -0
- package/opencode/INSTRUCTIONS.md +152 -0
- package/opencode/agents/engineering/cto.md +10 -0
- package/opencode/agents/engineering/design/ddd-architect.md +10 -0
- package/opencode/agents/engineering/discovery/agent-finder.md +10 -0
- package/opencode/agents/engineering/discovery/functional-discovery.md +10 -0
- package/opencode/agents/engineering/infra/infra-security.md +10 -0
- package/opencode/agents/engineering/infra/platform-strategist.md +10 -0
- package/opencode/agents/engineering/infra/terraform-architect.md +10 -0
- package/opencode/agents/engineering/prompt-engineer.md +10 -0
- package/opencode/agents/engineering/research/best-practices-researcher.md +10 -0
- package/opencode/agents/engineering/research/framework-docs-researcher.md +10 -0
- package/opencode/agents/engineering/research/git-history-analyzer.md +10 -0
- package/opencode/agents/engineering/research/learnings-researcher.md +10 -0
- package/opencode/agents/engineering/research/repo-research-analyst.md +10 -0
- package/opencode/agents/engineering/review/agent-native-reviewer.md +10 -0
- package/opencode/agents/engineering/review/architecture-strategist.md +10 -0
- package/opencode/agents/engineering/review/code-quality-analyst.md +10 -0
- package/opencode/agents/engineering/review/code-simplicity-reviewer.md +10 -0
- package/opencode/agents/engineering/review/data-integrity-guardian.md +10 -0
- package/opencode/agents/engineering/review/data-migration-expert.md +10 -0
- package/opencode/agents/engineering/review/deployment-verification-agent.md +10 -0
- package/opencode/agents/engineering/review/dhh-rails-reviewer.md +10 -0
- package/opencode/agents/engineering/review/kieran-rails-reviewer.md +10 -0
- package/opencode/agents/engineering/review/legacy-code-expert.md +10 -0
- package/opencode/agents/engineering/review/observability-coverage-reviewer.md +10 -0
- package/opencode/agents/engineering/review/pattern-recognition-specialist.md +10 -0
- package/opencode/agents/engineering/review/performance-oracle.md +10 -0
- package/opencode/agents/engineering/review/security-sentinel.md +10 -0
- package/opencode/agents/engineering/review/semgrep-sast.md +10 -0
- package/opencode/agents/engineering/review/test-design-reviewer.md +10 -0
- package/opencode/agents/engineering/review/user-impact-reviewer.md +10 -0
- package/opencode/agents/engineering/workflow/pr-comment-resolver.md +10 -0
- package/opencode/agents/finance/budget-analyst.md +10 -0
- package/opencode/agents/finance/cfo.md +10 -0
- package/opencode/agents/finance/financial-reporter.md +10 -0
- package/opencode/agents/finance/revenue-analyst.md +10 -0
- package/opencode/agents/legal/clo.md +10 -0
- package/opencode/agents/legal/legal-compliance-auditor.md +10 -0
- package/opencode/agents/legal/legal-document-generator.md +10 -0
- package/opencode/agents/marketing/analytics-analyst.md +10 -0
- package/opencode/agents/marketing/brand-architect.md +10 -0
- package/opencode/agents/marketing/cmo.md +10 -0
- package/opencode/agents/marketing/conversion-optimizer.md +10 -0
- package/opencode/agents/marketing/copywriter.md +10 -0
- package/opencode/agents/marketing/fact-checker.md +10 -0
- package/opencode/agents/marketing/growth-strategist.md +10 -0
- package/opencode/agents/marketing/paid-media-strategist.md +10 -0
- package/opencode/agents/marketing/pricing-strategist.md +10 -0
- package/opencode/agents/marketing/programmatic-seo-specialist.md +10 -0
- package/opencode/agents/marketing/retention-strategist.md +10 -0
- package/opencode/agents/marketing/seo-aeo-analyst.md +10 -0
- package/opencode/agents/operations/coo.md +10 -0
- package/opencode/agents/operations/ops-advisor.md +10 -0
- package/opencode/agents/operations/ops-provisioner.md +10 -0
- package/opencode/agents/operations/ops-research.md +10 -0
- package/opencode/agents/operations/service-automator.md +10 -0
- package/opencode/agents/product/business-validator.md +10 -0
- package/opencode/agents/product/competitive-intelligence.md +10 -0
- package/opencode/agents/product/cpo.md +10 -0
- package/opencode/agents/product/design/ux-design-lead.md +10 -0
- package/opencode/agents/product/spec-flow-analyzer.md +10 -0
- package/opencode/agents/sales/cro.md +10 -0
- package/opencode/agents/sales/deal-architect.md +10 -0
- package/opencode/agents/sales/outbound-strategist.md +10 -0
- package/opencode/agents/sales/pipeline-analyst.md +10 -0
- package/opencode/agents/support/cco.md +10 -0
- package/opencode/agents/support/community-manager.md +10 -0
- package/opencode/agents/support/ticket-triage.md +10 -0
- package/opencode/commands/go.md +10 -0
- package/opencode/commands/help.md +10 -0
- package/opencode/commands/sync.md +10 -0
- package/opencode/commands/version.md +11 -0
- package/opencode/opencode.json +8 -0
- package/opencode/plugin.ts +493 -0
- package/package.json +36 -4
- package/scripts/admin-merge-ready.sh +545 -0
- package/scripts/admin-merge-ready.test.sh +753 -0
- package/scripts/affected-tests.sh +908 -0
- package/scripts/affected-tests.test.sh +1797 -0
- package/scripts/alpha-metrics.sh +78 -0
- package/scripts/alpha-metrics.test.sh +115 -0
- package/scripts/ancestor-signal-helpers.baseline.txt +16 -0
- package/scripts/audit-flag-flip.sh +107 -0
- package/scripts/check-red-on-main.sh +316 -0
- package/scripts/ci-head-verdict.sh +363 -0
- package/scripts/cloud-detect.sh +193 -0
- package/scripts/delegation-verify.sh +657 -0
- package/scripts/delegation-verify.test.sh +1424 -0
- package/scripts/deploy-arm.sh +475 -0
- package/scripts/domain-model-drift.sh +419 -0
- package/scripts/emit-decision.sh +144 -0
- package/scripts/emit-decision.test.sh +144 -0
- package/scripts/ext-filter-divergence-corpus.txt +15 -0
- package/scripts/ext-filter-divergence.sh +189 -0
- package/scripts/generate-c4-from-components.ts +442 -0
- package/scripts/grok-fidelity-gate.sh +68 -0
- package/scripts/grok-pre-push-gate.sh +232 -0
- package/scripts/harness-discovery-smoke.ts +906 -0
- package/scripts/harness-parity-census.ts +92 -0
- package/scripts/inngest-luks-alert-armed-probe.ts +29 -0
- package/scripts/install-opencode-adapter.ts +520 -0
- package/scripts/lib/affected-tests/common.sh +365 -0
- package/scripts/lib/affected-tests/go.sh +157 -0
- package/scripts/lib/affected-tests/js.sh +188 -0
- package/scripts/lib/affected-tests/nx-turbo.sh +98 -0
- package/scripts/lib/affected-tests/python.sh +185 -0
- package/scripts/lib/context-sanitize.sh +49 -0
- package/scripts/lib/domain-model-lib.sh +180 -0
- package/scripts/lib/ext-filter-grammar.tsv +34 -0
- package/scripts/lib/operator-script.sh +1236 -0
- package/scripts/lib/proc.sh +580 -0
- package/scripts/lib/session-state.sh +748 -0
- package/scripts/lib/tmp-classify.sh +843 -0
- package/scripts/lib/wrapper-boundary.sh +47 -0
- package/scripts/lint-ratchet.py +1547 -0
- package/scripts/monitor-pr-checks.sh +441 -0
- package/scripts/pipeline-tally.sh +756 -0
- package/scripts/pipeline-tally.test.sh +740 -0
- package/scripts/plugin-version.sh +528 -0
- package/scripts/precommit-guard.sh +113 -0
- package/scripts/precommit-guard.test.sh +254 -0
- package/scripts/reconcile-live-heartbeats.ts +705 -0
- package/scripts/render-c4-model.sh +217 -0
- package/scripts/resolve-git-root.sh +55 -0
- package/scripts/resolve-regenerable-conflicts.sh +363 -0
- package/scripts/resolve-regenerable-conflicts.test.sh +780 -0
- package/scripts/ruff-requirements.txt +22 -0
- package/scripts/run-in-pid-namespace.sh +98 -0
- package/scripts/run-in-pid-namespace.test.sh +290 -0
- package/scripts/scan-ancestor-signal-helpers.py +556 -0
- package/scripts/scan-ancestor-signal-helpers.test.sh +670 -0
- package/scripts/setup-ralph-loop.sh +238 -0
- package/scripts/sync-cursor-name-map.ts +316 -0
- package/scripts/sync-grok-agent-compat.ts +188 -0
- package/scripts/sync-npm-package.ts +178 -0
- package/scripts/sync-opencode-adapter.ts +479 -0
- package/scripts/sync-pr-behind.sh +534 -0
- package/scripts/sync-pr-behind.test.sh +252 -0
- package/scripts/taste-profile-update.sh +180 -0
- package/scripts/taste-profile-update.test.sh +167 -0
- package/scripts/write-budget-marker.sh +23 -0
- package/scripts/write-kb-coverage.ts +113 -0
- package/skills/admin-ip-refresh/SKILL.md +81 -0
- package/skills/admin-ip-refresh/references/admin-ip-refresh-procedure.md +201 -0
- package/skills/agent-browser/SKILL.md +698 -0
- package/skills/agent-browser/scripts/playwright-mcp-profile-slot.sh +304 -0
- package/skills/agent-browser/scripts/playwright-mcp-redact-proxy.py +964 -0
- package/skills/agent-browser/scripts/redact-a11y-snapshot.py +443 -0
- package/skills/agent-browser/test/fixtures/capture-playwright-mcp-fixtures.py +217 -0
- package/skills/agent-browser/test/fixtures/fake-passthrough-proxy.py +24 -0
- package/skills/agent-browser/test/fixtures/fake-playwright-mcp.py +131 -0
- package/skills/agent-browser/test/fixtures/make-proxy-mutant.py +48 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/dialog-link-injection.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/empty-content.json +5 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-and-result.json +4 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-code-bool.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-code-string.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-message-tree.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-no-data.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-string.json +4 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-with-data.json +9 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/evaluate-escaped-object.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/invalid-utf8.json +4 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/link-result.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/list-two-results.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/meta-in-result.json +13 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/no-content.json +5 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/quoted-key.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/resource-block.json +18 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/result-and-method.json +11 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/result-string.json +3 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/run-code-escaped-one-row.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/run-code-escaped.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/structured-content.json +13 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/tools-list-no-tools.json +5 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/tree-no-credential.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/two-text-blocks.json +14 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/unparsable-line.json +3 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/value-contains-brace.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/value-contains-link-substring.json +10 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/close.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/evaluate.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/find.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/framing.json +6 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/initialize.json +14 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/navigate-link.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/navigate.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/roots-list-request.json +5 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/screenshot.json +17 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-filename.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-meta-json.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-meta-raw.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/tools-list.json +827 -0
- package/skills/agent-browser/test/fixtures/proxy-session-driver.py +138 -0
- package/skills/agent-browser/test/fixtures/session-facts.py +102 -0
- package/skills/agent-browser/test/playwright-mcp-lifetime.test.sh +1620 -0
- package/skills/agent-browser/test/playwright-mcp-redact-proxy.test.sh +1599 -0
- package/skills/agent-browser/test/redact-a11y-snapshot.test.sh +527 -0
- package/skills/agent-native-architecture/SKILL.md +479 -0
- package/skills/agent-native-architecture/references/action-parity-discipline.md +430 -0
- package/skills/agent-native-architecture/references/agent-execution-patterns.md +483 -0
- package/skills/agent-native-architecture/references/agent-native-testing.md +605 -0
- package/skills/agent-native-architecture/references/architecture-patterns.md +493 -0
- package/skills/agent-native-architecture/references/dynamic-context-injection.md +358 -0
- package/skills/agent-native-architecture/references/files-universal-interface.md +314 -0
- package/skills/agent-native-architecture/references/from-primitives-to-domain-tools.md +381 -0
- package/skills/agent-native-architecture/references/mcp-tool-design.md +524 -0
- package/skills/agent-native-architecture/references/mobile-patterns.md +897 -0
- package/skills/agent-native-architecture/references/product-implications.md +478 -0
- package/skills/agent-native-architecture/references/refactoring-to-prompt-native.md +342 -0
- package/skills/agent-native-architecture/references/self-modification.md +294 -0
- package/skills/agent-native-architecture/references/shared-workspace-architecture.md +700 -0
- package/skills/agent-native-architecture/references/system-prompt-design.md +263 -0
- package/skills/agent-native-audit/SKILL.md +300 -0
- package/skills/agent-native-audit/workflows/agent-native-audit.workflow.js +423 -0
- package/skills/andrew-kane-gem-writer/SKILL.md +189 -0
- package/skills/andrew-kane-gem-writer/references/database-adapters.md +231 -0
- package/skills/andrew-kane-gem-writer/references/module-organization.md +121 -0
- package/skills/andrew-kane-gem-writer/references/rails-integration.md +183 -0
- package/skills/andrew-kane-gem-writer/references/resources.md +126 -0
- package/skills/andrew-kane-gem-writer/references/testing-patterns.md +261 -0
- package/skills/architecture/SKILL.md +436 -0
- package/skills/architecture/references/adr-template.md +154 -0
- package/skills/architecture/references/likec4-reference.md +136 -0
- package/skills/architecture/references/nfr-reference.md +126 -0
- package/skills/archive-kb/SKILL.md +86 -0
- package/skills/archive-kb/scripts/archive-kb.sh +300 -0
- package/skills/archive-kb/test/archive-kb-partial-run.test.sh +276 -0
- package/skills/atdd-developer/SKILL.md +65 -0
- package/skills/brainstorm/SKILL.md +701 -0
- package/skills/brainstorm/references/brainstorm-brand-workshop.md +153 -0
- package/skills/brainstorm/references/brainstorm-domain-config.md +63 -0
- package/skills/brainstorm/references/brainstorm-validation-workshop.md +65 -0
- package/skills/brainstorm/references/ui-surface-terms.md +42 -0
- package/skills/brainstorm-techniques/SKILL.md +231 -0
- package/skills/brainstorm-techniques/references/decision-principles.md +150 -0
- package/skills/brainstorm-techniques/references/phase-boundaries.md +103 -0
- package/skills/brainstorm-techniques/references/standing-delegation.md +407 -0
- package/skills/brainstorm-techniques/references/technical-ruling-delegation.md +174 -0
- package/skills/campaign-calendar/SKILL.md +145 -0
- package/skills/cf-token-scope/SKILL.md +164 -0
- package/skills/cf-token-scope/references/widen-playbook.md +114 -0
- package/skills/cf-token-scope/scripts/cf-token-scope.sh +253 -0
- package/skills/changelog/SKILL.md +142 -0
- package/skills/code-to-prd/SKILL.md +66 -0
- package/skills/code-to-prd/references/banner-template.md +12 -0
- package/skills/code-to-prd/references/prd-template.md +41 -0
- package/skills/code-to-prd/scripts/code-to-prd.sh +634 -0
- package/skills/code-to-prd/test/code-to-prd.test.sh +447 -0
- package/skills/code-to-prd/test/fixture/.env.example +7 -0
- package/skills/code-to-prd/test/fixture/app/about/page.tsx +11 -0
- package/skills/code-to-prd/test/fixture/app/api/health/route.ts +10 -0
- package/skills/code-to-prd/test/fixture/app/page.tsx +14 -0
- package/skills/code-to-prd/test/fixture/next.config.mjs +3 -0
- package/skills/code-to-prd/test/fixture/package.json +6 -0
- package/skills/cohort-status/SKILL.md +62 -0
- package/skills/community/SKILL.md +210 -0
- package/skills/community/scripts/bsky-community.sh +644 -0
- package/skills/community/scripts/bsky-setup.sh +631 -0
- package/skills/community/scripts/community-router.sh +93 -0
- package/skills/community/scripts/discord-community.sh +487 -0
- package/skills/community/scripts/discord-setup.sh +784 -0
- package/skills/community/scripts/github-community.sh +706 -0
- package/skills/community/scripts/hn-community.sh +233 -0
- package/skills/community/scripts/lib/hmac-sha1-b64.sh +126 -0
- package/skills/community/scripts/linkedin-community.sh +750 -0
- package/skills/community/scripts/linkedin-setup.sh +758 -0
- package/skills/community/scripts/x-community.sh +890 -0
- package/skills/community/scripts/x-setup.sh +713 -0
- package/skills/community/test/community-argv.test.sh +2922 -0
- package/skills/community/test/github-community.test.sh +981 -0
- package/skills/competitive-analysis/SKILL.md +69 -0
- package/skills/competitive-analysis/references/peer-plugin-audit.md +218 -0
- package/skills/compound/SKILL.md +673 -0
- package/skills/compound/scripts/token-efficiency-report.sh +334 -0
- package/skills/compound/test/phase-16.test.sh +379 -0
- package/skills/compound-capture/SKILL.md +791 -0
- package/skills/compound-capture/assets/critical-pattern-template.md +37 -0
- package/skills/compound-capture/assets/resolution-template.md +116 -0
- package/skills/compound-capture/references/yaml-schema.md +67 -0
- package/skills/compound-capture/schema.yaml +181 -0
- package/skills/constraint-scaffold/SKILL.md +175 -0
- package/skills/constraint-scaffold/references/boundary-readme.template +35 -0
- package/skills/constraint-scaffold/references/constraint-gates-workflow.template +69 -0
- package/skills/constraint-scaffold/references/depcruise-config.template +230 -0
- package/skills/constraint-scaffold/references/fix-constraints-stage-a.template +240 -0
- package/skills/constraint-scaffold/references/fix-constraints-stage-b.template +313 -0
- package/skills/constraint-scaffold/references/shared-runner.template +135 -0
- package/skills/constraint-scaffold/scripts/constraint-scaffold.sh +589 -0
- package/skills/constraint-scaffold/test/bite-proof.test.sh +1338 -0
- package/skills/constraint-scaffold/test/boundary.test.sh +734 -0
- package/skills/constraint-scaffold/test/emit-fix-constraints.test.sh +193 -0
- package/skills/constraint-scaffold/test/generator.test.sh +93 -0
- package/skills/constraint-scaffold/test/parity.test.sh +285 -0
- package/skills/content-writer/SKILL.md +242 -0
- package/skills/content-writer/scripts/blog-jargon-scan.sh +42 -0
- package/skills/cron-delete/SKILL.md +56 -0
- package/skills/cron-list/SKILL.md +54 -0
- package/skills/deepen-plan/SKILL.md +937 -0
- package/skills/deepen-plan/workflows/deepen-plan.workflow.js +488 -0
- package/skills/deploy/SKILL.md +115 -0
- package/skills/deploy/references/hetzner-setup.md +65 -0
- package/skills/deploy/scripts/deploy.sh +37 -0
- package/skills/deploy-docs/SKILL.md +95 -0
- package/skills/dhh-rails-style/SKILL.md +203 -0
- package/skills/dhh-rails-style/references/architecture.md +717 -0
- package/skills/dhh-rails-style/references/controllers.md +323 -0
- package/skills/dhh-rails-style/references/frontend.md +556 -0
- package/skills/dhh-rails-style/references/gems.md +316 -0
- package/skills/dhh-rails-style/references/models.md +388 -0
- package/skills/dhh-rails-style/references/testing.md +354 -0
- package/skills/discord-content/SKILL.md +126 -0
- package/skills/docs-site/SKILL.md +214 -0
- package/skills/drain-labeled-backlog/SKILL.md +203 -0
- package/skills/drain-labeled-backlog/scripts/group-by-area.sh +208 -0
- package/skills/drain-labeled-backlog/workflows/drain-labeled-backlog.workflow.js +433 -0
- package/skills/drain-prs/SKILL.md +142 -0
- package/skills/drain-prs/scripts/triage-prs.sh +192 -0
- package/skills/drain-prs/test/argv-ceiling.test.sh +183 -0
- package/skills/dspy-ruby/SKILL.md +634 -0
- package/skills/dspy-ruby/assets/config-template.rb +359 -0
- package/skills/dspy-ruby/assets/module-template.rb +326 -0
- package/skills/dspy-ruby/assets/signature-template.rb +143 -0
- package/skills/dspy-ruby/references/core-concepts.md +268 -0
- package/skills/dspy-ruby/references/optimization.md +623 -0
- package/skills/dspy-ruby/references/providers.md +335 -0
- package/skills/eval-harness/README.md +194 -0
- package/skills/eval-harness/SKILL.md +157 -0
- package/skills/eval-harness/enums/go-routes.json +13 -0
- package/skills/eval-harness/enums/incident-threshold.json +5 -0
- package/skills/eval-harness/enums/lane.json +5 -0
- package/skills/eval-harness/enums/tool-selection.json +20 -0
- package/skills/eval-harness/enums/triage-levels.json +5 -0
- package/skills/eval-harness/gated-skills.json +34 -0
- package/skills/eval-harness/models.generated.json +5 -0
- package/skills/eval-harness/promptfooconfig-go-routing.yaml +35 -0
- package/skills/eval-harness/promptfooconfig-incident-threshold.yaml +32 -0
- package/skills/eval-harness/promptfooconfig-lane-inference.yaml +33 -0
- package/skills/eval-harness/promptfooconfig-ticket-triage.yaml +34 -0
- package/skills/eval-harness/promptfooconfig-tool-selection.yaml +33 -0
- package/skills/eval-harness/prompts/go-baseline.txt +6 -0
- package/skills/eval-harness/prompts/go-skill.txt +21 -0
- package/skills/eval-harness/prompts/incident-threshold-baseline.txt +6 -0
- package/skills/eval-harness/prompts/incident-threshold-skill.txt +12 -0
- package/skills/eval-harness/prompts/lane-inference-baseline.txt +6 -0
- package/skills/eval-harness/prompts/lane-inference-skill.txt +15 -0
- package/skills/eval-harness/prompts/tool-selection-baseline.txt +19 -0
- package/skills/eval-harness/prompts/tool-selection-skill.txt +22 -0
- package/skills/eval-harness/prompts/triage-baseline.txt +7 -0
- package/skills/eval-harness/prompts/triage-skill.txt +10 -0
- package/skills/eval-harness/scripts/eval-gate.cjs +318 -0
- package/skills/eval-harness/scripts/extract-block.cjs +87 -0
- package/skills/eval-harness/scripts/gate-classification.cjs +28 -0
- package/skills/eval-harness/scripts/gen-models.sh +41 -0
- package/skills/eval-harness/scripts/gen-skill-prompt.cjs +177 -0
- package/skills/eval-harness/scripts/measure-classification.cjs +30 -0
- package/skills/eval-harness/scripts/parse-label.cjs +93 -0
- package/skills/eval-harness/scripts/verdict.cjs +132 -0
- package/skills/eval-harness/tasks/go-routing.jsonl +8 -0
- package/skills/eval-harness/tasks/incident-threshold.jsonl +7 -0
- package/skills/eval-harness/tasks/lane-inference.jsonl +7 -0
- package/skills/eval-harness/tasks/ticket-triage.jsonl +6 -0
- package/skills/eval-harness/tasks/tool-selection.jsonl +15 -0
- package/skills/eval-harness/test/eval-gate.test.sh +132 -0
- package/skills/eval-harness/test/extract-block.test.sh +87 -0
- package/skills/eval-harness/test/gate-classification.test.sh +77 -0
- package/skills/eval-harness/test/gen-models.test.sh +75 -0
- package/skills/eval-harness/test/measure-classification.test.sh +74 -0
- package/skills/eval-harness/test/parse-label.test.sh +129 -0
- package/skills/eval-harness/test/registry-completeness.test.sh +109 -0
- package/skills/eval-harness/test/verdict.test.sh +123 -0
- package/skills/every-style-editor/SKILL.md +142 -0
- package/skills/every-style-editor/references/EVERY_WRITE_STYLE.md +529 -0
- package/skills/feature-tweet/SKILL.md +199 -0
- package/skills/feature-video/SKILL.md +412 -0
- package/skills/feature-video/scripts/check_deps.sh +281 -0
- package/skills/file-todos/SKILL.md +267 -0
- package/skills/file-todos/assets/todo-template.md +166 -0
- package/skills/fix-issue/SKILL.md +278 -0
- package/skills/fix-issue/references/agent-authored-exclusion.md +118 -0
- package/skills/fix-issue/references/exclude-label-jq-snippet.md +96 -0
- package/skills/flag-bootstrap/SETUP.md +142 -0
- package/skills/flag-create/SKILL.md +145 -0
- package/skills/flag-create/scripts/create.sh +273 -0
- package/skills/flag-delete/SKILL.md +167 -0
- package/skills/flag-delete/scripts/delete.sh +288 -0
- package/skills/flag-list/SKILL.md +99 -0
- package/skills/flag-list/scripts/list.sh +275 -0
- package/skills/flag-set-role/SKILL.md +229 -0
- package/skills/flag-set-role/scripts/flip.sh +774 -0
- package/skills/frontend-anti-slop/SKILL.md +106 -0
- package/skills/frontend-anti-slop/references/anti-patterns.md +199 -0
- package/skills/frontend-anti-slop/references/slop-rules.md +65 -0
- package/skills/frontend-anti-slop/scripts/tier1-scan.ts +525 -0
- package/skills/frontend-design/SKILL.md +77 -0
- package/skills/gdpr-gate/NOTICE +136 -0
- package/skills/gdpr-gate/SKILL.md +341 -0
- package/skills/gdpr-gate/references/fields.md +160 -0
- package/skills/gdpr-gate/references/layers/api-layer.md +355 -0
- package/skills/gdpr-gate/references/layers/auth-sessions.md +290 -0
- package/skills/gdpr-gate/references/layers/data-in-transit.md +331 -0
- package/skills/gdpr-gate/references/layers/data-lifecycle.md +341 -0
- package/skills/gdpr-gate/references/layers/frontend.md +249 -0
- package/skills/gdpr-gate/references/layers/testing-seeding.md +256 -0
- package/skills/gdpr-gate/references/leakage-vectors.md +248 -0
- package/skills/gdpr-gate/references/legacy/legal-consent-v1-prose.md +48 -0
- package/skills/gdpr-gate/references/legal-consent.md +140 -0
- package/skills/gdpr-gate/references/non-negotiables.md +60 -0
- package/skills/gdpr-gate/scripts/gdpr-gate.sh +271 -0
- package/skills/gdpr-gate/scripts/notice-frontmatter.sh +337 -0
- package/skills/gdpr-gate/scripts/path-denylist.txt +39 -0
- package/skills/gdpr-gate/scripts/repo-scan.sh +158 -0
- package/skills/gdpr-gate/scripts/vendor-drift-classify.sh +120 -0
- package/skills/gdpr-gate/scripts/vendor-pin-integrity.sh +237 -0
- package/skills/gemini-imagegen/SKILL.md +283 -0
- package/skills/gemini-imagegen/requirements.txt +5 -0
- package/skills/gemini-imagegen/scripts/_error_handling.py +146 -0
- package/skills/gemini-imagegen/scripts/compose_images.py +150 -0
- package/skills/gemini-imagegen/scripts/edit_image.py +137 -0
- package/skills/gemini-imagegen/scripts/gemini_images.py +256 -0
- package/skills/gemini-imagegen/scripts/generate_image.py +147 -0
- package/skills/gemini-imagegen/scripts/multi_turn_chat.py +223 -0
- package/skills/gemini-imagegen/scripts/test_error_handling.py +179 -0
- package/skills/git-worktree/SKILL.md +534 -0
- package/skills/git-worktree/scripts/git-repo-readiness-diag.sh +98 -0
- package/skills/git-worktree/scripts/worktree-manager.sh +4773 -0
- package/skills/git-worktree/test/create-from-origin-main.test.sh +116 -0
- package/skills/git-worktree/test/lease-protects-active.test.sh +1056 -0
- package/skills/git-worktree/test/no-repo-fail-loud.test.sh +88 -0
- package/skills/git-worktree/test/orphan-reaper-honest-count.test.sh +379 -0
- package/skills/git-worktree/test/reap-archive-persistence.test.sh +725 -0
- package/skills/git-worktree/test/stale-lock-sweep.test.sh +176 -0
- package/skills/go/SKILL.md +54 -0
- package/skills/growth/SKILL.md +164 -0
- package/skills/harvest-debt/SKILL.md +78 -0
- package/skills/harvest-debt/scripts/harvest-debt.sh +114 -0
- package/skills/heal-skill/SKILL.md +173 -0
- package/skills/help/SKILL.md +46 -0
- package/skills/incident/NOTICE +39 -0
- package/skills/incident/SKILL.md +395 -0
- package/skills/incident/scripts/dry-run.sh +448 -0
- package/skills/incident/scripts/redact-engine.py +412 -0
- package/skills/incident/scripts/redact-sentinel.sh +44 -0
- package/skills/incident/templates/pir.md +139 -0
- package/skills/incident/test/fixtures/dry-run-incident.json +26 -0
- package/skills/incident/test/fixtures/dry-run-secret-leak.json +26 -0
- package/skills/incident/test/fixtures/legacy-bash-scanner.sh +82 -0
- package/skills/incident/test/fixtures/positive-corpus.md +87 -0
- package/skills/incident/test/redact-sentinel.test.sh +1420 -0
- package/skills/invoice/SKILL.md +206 -0
- package/skills/kb-glossary/SKILL.md +71 -0
- package/skills/kb-glossary/references/glossary-format.md +111 -0
- package/skills/kb-glossary/references/rejected-request-register.md +115 -0
- package/skills/kb-search/SKILL.md +276 -0
- package/skills/kb-search/scripts/kb-search-cache.sh +123 -0
- package/skills/legal-audit/SKILL.md +161 -0
- package/skills/legal-generate/NOTICE +242 -0
- package/skills/legal-generate/SKILL.md +244 -0
- package/skills/legal-generate/references/templates/advisor-agreement/template.md +12 -0
- package/skills/legal-generate/references/templates/business-associate-agreement/template.md +112 -0
- package/skills/legal-generate/references/templates/cookie-notice/template.md +82 -0
- package/skills/legal-generate/references/templates/dpa-global/template.md +439 -0
- package/skills/legal-generate/references/templates/dpa-us/template.md +222 -0
- package/skills/legal-generate/references/templates/employee-offer-letter/template.md +75 -0
- package/skills/legal-generate/references/templates/master-services-agreement/template.md +252 -0
- package/skills/legal-generate/references/templates/mutual-nda/template.md +66 -0
- package/skills/legal-generate/references/templates/one-way-nda/template.md +38 -0
- package/skills/legal-generate/references/templates/privacy-policy-gdpr/template.md +427 -0
- package/skills/legal-generate/references/templates/privacy-policy-us/template.md +313 -0
- package/skills/legal-generate/references/templates/terms-of-use/template.md +75 -0
- package/skills/legal-generate/scripts/strip-vendor-credit.sh +96 -0
- package/skills/linear-fetch/SKILL.md +247 -0
- package/skills/linear-fetch/scripts/assert-no-linear-telemetry.sh +66 -0
- package/skills/linear-fetch/scripts/redact-linear-urls.sh +51 -0
- package/skills/linear-fetch/scripts/render-caller-template.sh +36 -0
- package/skills/linear-fetch/test/assert-no-linear-telemetry.test.sh +113 -0
- package/skills/linear-fetch/test/parity.test.sh +112 -0
- package/skills/linear-fetch/test/persist-safe-integration.test.sh +191 -0
- package/skills/linear-fetch/test/redact-linear-urls.test.sh +226 -0
- package/skills/merge-pr/SKILL.md +668 -0
- package/skills/model-launch-review/SKILL.md +255 -0
- package/skills/model-launch-review/scripts/audit-models.sh +501 -0
- package/skills/one-shot/SKILL.md +316 -0
- package/skills/one-shot/references/token-discipline.md +74 -0
- package/skills/operator-bootstrap/SKILL.md +412 -0
- package/skills/operator-bootstrap/template.sh +439 -0
- package/skills/operator-digest/SKILL.md +287 -0
- package/skills/operator-digest/assets/operator-digest.workflow.yml +175 -0
- package/skills/operator-digest/scripts/digest-scrub.sh +119 -0
- package/skills/operator-digest/scripts/provision-operator-digest-repo.sh +147 -0
- package/skills/operator-rephrase/SKILL.md +98 -0
- package/skills/pencil-setup/SKILL.md +201 -0
- package/skills/pencil-setup/scripts/check_deps.sh +556 -0
- package/skills/pencil-setup/scripts/copy_adapter.sh +80 -0
- package/skills/pencil-setup/scripts/package-lock.json +1172 -0
- package/skills/pencil-setup/scripts/package.json +14 -0
- package/skills/pencil-setup/scripts/pencil-error-enrichment.mjs +21 -0
- package/skills/pencil-setup/scripts/pencil-mcp-adapter.mjs +733 -0
- package/skills/pencil-setup/scripts/pencil-response-classify.mjs +38 -0
- package/skills/pencil-setup/scripts/pencil-save-gate.mjs +26 -0
- package/skills/pencil-setup/scripts/sanitize-filename.mjs +25 -0
- package/skills/plan/SKILL.md +1140 -0
- package/skills/plan/references/differential-migration-testing.md +185 -0
- package/skills/plan/references/plan-community-discovery.md +42 -0
- package/skills/plan/references/plan-founder-check.md +137 -0
- package/skills/plan/references/plan-functional-overlap.md +25 -0
- package/skills/plan/references/plan-host-fanout.md +51 -0
- package/skills/plan/references/plan-issue-templates.md +779 -0
- package/skills/plan/references/plan-network-outage-checklist.md +131 -0
- package/skills/plan/references/plan-scope-check.md +126 -0
- package/skills/plan/references/plan-sharp-edges.md +325 -0
- package/skills/plan/references/plan-signoff-lifecycle.md +12 -0
- package/skills/plan/references/webapp-cwv-observability.md +143 -0
- package/skills/plan-review/SKILL.md +91 -0
- package/skills/plan-review/lib/named-panel.mjs +58 -0
- package/skills/plan-review/workflows/plan-review.workflow.js +477 -0
- package/skills/postmerge/SKILL.md +642 -0
- package/skills/postmerge/references/deploy-status-debugging.md +138 -0
- package/skills/postmerge/references/graceful-degradation.md +20 -0
- package/skills/postmerge/references/sentry-error-count-delta.md +137 -0
- package/skills/preflight/SKILL.md +1553 -0
- package/skills/preflight/references/check-13-founder-check.md +286 -0
- package/skills/preflight/scripts/founder-check.py +1640 -0
- package/skills/preflight/scripts/parse-form-a.awk +107 -0
- package/skills/preflight/scripts/probe-verb-gate.sh +108 -0
- package/skills/product-roadmap/SKILL.md +357 -0
- package/skills/product-roadmap/scripts/roadmap-reconcile.sh +327 -0
- package/skills/provision-cloudflare/SKILL.md +67 -0
- package/skills/provision-cloudflare/scripts/provision-cloudflare.sh +271 -0
- package/skills/provision-doppler/SKILL.md +58 -0
- package/skills/provision-doppler/scripts/provision-doppler.sh +358 -0
- package/skills/provision-github/SKILL.md +59 -0
- package/skills/provision-github/scripts/provision-github.sh +300 -0
- package/skills/provision-hetzner/SKILL.md +76 -0
- package/skills/provision-hetzner/scripts/provision-hetzner.sh +262 -0
- package/skills/provision-hetzner/test/fixture/knowledge-base/legal/tenant-dpa-register.md +26 -0
- package/skills/provision-hetzner/test/fixture/provision-hetzner-dry-run.golden +34 -0
- package/skills/provision-hetzner/test/provision-hetzner-characterization.test.sh +227 -0
- package/skills/qa/SKILL.md +263 -0
- package/skills/qa/references/browser-preflight.md +22 -0
- package/skills/questionnaire-generate/SKILL.md +328 -0
- package/skills/questionnaire-generate/references/questionnaire.template +60 -0
- package/skills/rclone/SKILL.md +162 -0
- package/skills/rclone/scripts/check_setup.sh +63 -0
- package/skills/release-announce/SKILL.md +65 -0
- package/skills/release-docs/SKILL.md +92 -0
- package/skills/reproduce-bug/SKILL.md +358 -0
- package/skills/resolve-debt/SKILL.md +85 -0
- package/skills/resolve-debt/scripts/resolve-debt.py +584 -0
- package/skills/resolve-parallel/SKILL.md +45 -0
- package/skills/resolve-parallel/workflows/resolve-parallel.workflow.js +415 -0
- package/skills/resolve-pr-parallel/SKILL.md +68 -0
- package/skills/resolve-pr-parallel/workflows/resolve-pr-parallel.workflow.js +419 -0
- package/skills/resolve-todo-parallel/SKILL.md +57 -0
- package/skills/resolve-todo-parallel/workflows/resolve-todo-parallel.workflow.js +398 -0
- package/skills/review/SKILL.md +1621 -0
- package/skills/review/references/anti-slop-scanner-hook.md +40 -0
- package/skills/review/references/defect-classes-migrations.md +9 -0
- package/skills/review/references/generated-input-oracle-surfaces.md +15 -0
- package/skills/review/references/review-e2e-testing.md +116 -0
- package/skills/review/references/review-todo-structure.md +165 -0
- package/skills/review/references/risk-tier-and-fix-rounds.md +95 -0
- package/skills/review/references/semgrep-custom-rules.yaml +174 -0
- package/skills/review/references/ultrathink-phases.md +98 -0
- package/skills/review/references/wfs.md +6 -0
- package/skills/review/scripts/emit-review-trailer.sh +499 -0
- package/skills/review/scripts/ensure-semgrep.sh +99 -0
- package/skills/review/scripts/fix-round-seats.sh +197 -0
- package/skills/review/test/emit-review-trailer.test.sh +387 -0
- package/skills/review/test/ensure-semgrep.test.sh +111 -0
- package/skills/review/test/fix-round-seats.test.sh +237 -0
- package/skills/review/workflows/README.md +147 -0
- package/skills/review/workflows/review.workflow.js +667 -0
- package/skills/schedule/SKILL.md +796 -0
- package/skills/seo-aeo/SKILL.md +139 -0
- package/skills/seo-aeo/scripts/validate-csp.sh +233 -0
- package/skills/seo-aeo/scripts/validate-seo.sh +262 -0
- package/skills/ship/SKILL.md +3022 -0
- package/skills/ship/references/adr-ordinal-collision.md +47 -0
- package/skills/ship/references/affected-gate-contract.md +115 -0
- package/skills/ship/references/ci-run-diagnosis.md +29 -0
- package/skills/ship/references/ci-workflow-authoring.md +68 -0
- package/skills/ship/references/counsel-review-clo-attestation.md +38 -0
- package/skills/ship/references/cto-ruling-armed-push.md +5 -0
- package/skills/ship/references/decision-challenges-render.md +71 -0
- package/skills/ship/references/detached-battery-verdict.md +13 -0
- package/skills/ship/references/feature-tweet-draft.md +42 -0
- package/skills/ship/references/followthrough-issue-body-template.md +47 -0
- package/skills/ship/references/followthrough-stub-template.sh +92 -0
- package/skills/ship/references/merge-queue-dequeue.md +39 -0
- package/skills/ship/references/operator-holds.md +149 -0
- package/skills/ship/references/pipeline-tally-render.md +43 -0
- package/skills/ship/references/pr-overlap.md +153 -0
- package/skills/ship/references/queue-mode.md +7 -0
- package/skills/ship/references/ready-run-wait.md +36 -0
- package/skills/ship/references/red-on-main-quarantine.md +110 -0
- package/skills/ship/references/register-update-pr-pattern.md +88 -0
- package/skills/ship/references/settle-then-admin-merge.md +130 -0
- package/skills/ship/references/supabase-column-probe.md +13 -0
- package/skills/ship/scripts/auto-close-scan.sh +76 -0
- package/skills/ship/scripts/battery-owed.sh +403 -0
- package/skills/ship/scripts/hold-gate-eval.sh +410 -0
- package/skills/ship/scripts/net-issue-flow.sh +665 -0
- package/skills/ship/scripts/pr-overlap-preflight.sh +483 -0
- package/skills/ship/scripts/ship-pir-action-items-gate.sh +246 -0
- package/skills/ship/scripts/technical-ruling-gate.sh +444 -0
- package/skills/skill-creator/SKILL.md +299 -0
- package/skills/skill-creator/references/api-security.md +248 -0
- package/skills/skill-creator/references/authoring-levers.md +110 -0
- package/skills/skill-creator/references/be-clear-and-direct.md +587 -0
- package/skills/skill-creator/references/best-practices.md +431 -0
- package/skills/skill-creator/references/common-patterns.md +639 -0
- package/skills/skill-creator/references/core-principles.md +193 -0
- package/skills/skill-creator/references/executable-code.md +188 -0
- package/skills/skill-creator/references/iteration-and-testing.md +509 -0
- package/skills/skill-creator/references/official-spec.md +193 -0
- package/skills/skill-creator/references/recommended-structure.md +180 -0
- package/skills/skill-creator/references/skill-structure.md +396 -0
- package/skills/skill-creator/references/using-scripts.md +122 -0
- package/skills/skill-creator/references/using-templates.md +120 -0
- package/skills/skill-creator/references/workflows-and-validation.md +541 -0
- package/skills/skill-creator/scripts/init_skill.py +322 -0
- package/skills/skill-creator/scripts/package_skill.py +110 -0
- package/skills/skill-creator/scripts/quick_validate.py +64 -0
- package/skills/skill-creator/templates/router-skill.md +73 -0
- package/skills/skill-creator/templates/simple-skill.md +34 -0
- package/skills/skill-creator/workflows/add-reference.md +96 -0
- package/skills/skill-creator/workflows/add-script.md +104 -0
- package/skills/skill-creator/workflows/add-template.md +83 -0
- package/skills/skill-creator/workflows/add-workflow.md +128 -0
- package/skills/skill-creator/workflows/audit-skill.md +159 -0
- package/skills/skill-creator/workflows/create-domain-expertise-skill.md +623 -0
- package/skills/skill-creator/workflows/create-new-skill.md +207 -0
- package/skills/skill-creator/workflows/get-guidance.md +134 -0
- package/skills/skill-creator/workflows/upgrade-to-router.md +170 -0
- package/skills/skill-creator/workflows/verify-skill.md +226 -0
- package/skills/skill-security-scan/SKILL.md +145 -0
- package/skills/skill-security-scan/references/disclaimer.md +21 -0
- package/skills/skill-security-scan/references/first-party-allowlist.yaml +38 -0
- package/skills/skill-security-scan/references/override-artifact-schema.json +68 -0
- package/skills/skill-security-scan/references/override-mechanism.md +171 -0
- package/skills/skill-security-scan/references/redirect-domains.yaml +27 -0
- package/skills/skill-security-scan/references/regex-patterns.md +136 -0
- package/skills/skill-security-scan/references/rules/code-exec.yaml +70 -0
- package/skills/skill-security-scan/references/rules/filesystem-boundary.yaml +29 -0
- package/skills/skill-security-scan/references/rules/manifest.yaml +44 -0
- package/skills/skill-security-scan/references/rules/supply-chain.yaml +36 -0
- package/skills/skill-security-scan/references/scan-meta-schema.json +63 -0
- package/skills/skill-security-scan/references/test-fixtures/clean-soleur-style.skill.md +23 -0
- package/skills/skill-security-scan/references/test-fixtures/clean-third-party.skill.md +26 -0
- package/skills/skill-security-scan/references/test-fixtures/malicious-codeexec.skill.md +23 -0
- package/skills/skill-security-scan/references/test-fixtures/malicious-curl-pipe-bash.skill.md +69 -0
- package/skills/skill-security-scan/references/test-fixtures/malicious-prompt-injection.skill.md +17 -0
- package/skills/skill-security-scan/references/test-fixtures/malicious-telemetry-beacon.skill.md +23 -0
- package/skills/skill-security-scan/references/typosquat-targets.yaml +65 -0
- package/skills/skill-security-scan/scripts/check-codeexec.sh +41 -0
- package/skills/skill-security-scan/scripts/check-filesystem-boundary.sh +19 -0
- package/skills/skill-security-scan/scripts/check-prompt-injection.sh +95 -0
- package/skills/skill-security-scan/scripts/check-supply-chain.sh +219 -0
- package/skills/skill-security-scan/scripts/check-telemetry-surface.sh +126 -0
- package/skills/skill-security-scan/scripts/lib.sh +197 -0
- package/skills/skill-security-scan/scripts/parse-override.sh +231 -0
- package/skills/skill-security-scan/scripts/run-scan.sh +342 -0
- package/skills/skill-security-scan/scripts/run-self-test.sh +95 -0
- package/skills/skill-security-scan/test/argv-ceiling.test.sh +180 -0
- package/skills/skill-security-scan/test/meta-dir-reap.test.sh +411 -0
- package/skills/skill-security-scan/test/parse-override.test.sh +607 -0
- package/skills/skill-security-scan/test/redact-pii-ghs-shape.test.sh +251 -0
- package/skills/social-distribute/SKILL.md +485 -0
- package/skills/spec-templates/SKILL.md +274 -0
- package/skills/sync/SKILL.md +49 -0
- package/skills/test-browser/SKILL.md +464 -0
- package/skills/test-browser/references/feature-map.md +161 -0
- package/skills/test-fix-loop/SKILL.md +159 -0
- package/skills/test-fix-loop/references/determinism-checklist.md +154 -0
- package/skills/triage/SKILL.md +402 -0
- package/skills/trigger-cron/SKILL.md +136 -0
- package/skills/trigger-cron/scripts/trigger.sh +198 -0
- package/skills/user-set-role/SKILL.md +147 -0
- package/skills/user-set-role/scripts/set-role.sh +218 -0
- package/skills/user-story-writer/SKILL.md +77 -0
- package/skills/ux-audit/SKILL.md +251 -0
- package/skills/ux-audit/references/finding.schema.json +62 -0
- package/skills/ux-audit/references/route-list.yaml +95 -0
- package/skills/ux-audit/scripts/bot-fixture.ts +270 -0
- package/skills/ux-audit/scripts/bot-signin.ts +135 -0
- package/skills/ux-audit/scripts/dedup-hash.ts +46 -0
- package/skills/work/SKILL.md +1479 -0
- package/skills/work/references/end-of-work-resume.md +7 -0
- package/skills/work/references/hook-test-main-cwd.md +24 -0
- package/skills/work/references/key-principles.md +83 -0
- package/skills/work/references/property-testing.md +122 -0
- package/skills/work/references/sql-security-definer-rpc-scaffold.sql +78 -0
- package/skills/work/references/work-agent-teams.md +97 -0
- package/skills/work/references/work-lifecycle-parallel.md +147 -0
- package/skills/work/references/work-lockfile-bumps.md +97 -0
- package/skills/work/references/work-scratch-sandboxes.md +212 -0
- package/skills/work/references/work-subagent-fanout.md +61 -0
- package/skills/work/references/work-test-harness-sharp-edges.md +73 -0
- package/skills/xcode-test/SKILL.md +360 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Harness-parity census over the plugin doc population (ADR-226, #8299).
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* bun plugins/soleur/scripts/harness-parity-census.ts --report # print every non-canonical site; exit 1 if any
|
|
7
|
+
* bun plugins/soleur/scripts/harness-parity-census.ts --fix # rewrite the mechanical shapes in place (idempotent)
|
|
8
|
+
*
|
|
9
|
+
* The gate is `plugins/soleur/test/harness-parity-tree.test.ts`; this CLI is the author's
|
|
10
|
+
* inner loop and the remediation tool. `--fix` inverts only `/soleur:x`, `$soleur:x`,
|
|
11
|
+
* `@agent-soleur:x` and grok `/x` for a known skill; bare agent leaves, `@agent-<leaf>`
|
|
12
|
+
* mentions and grok stems in prose are hand edits (the sentence around them changes).
|
|
13
|
+
*
|
|
14
|
+
* `--fix` REWRITES TRACKED FILES IN PLACE and is the remedy the gate's own failure message
|
|
15
|
+
* prescribes, so it refuses to run against a dirty working tree unless `--force` is passed.
|
|
16
|
+
* That is not ceremony: a grok slash and a root-relative path are lexically identical after a
|
|
17
|
+
* boundary character (`run /plan` vs `POST /invoice`), so a rewrite CAN consume a real byte,
|
|
18
|
+
* and the result then classifies CANONICAL — meaning the census reports clean and the loss is
|
|
19
|
+
* invisible to the gate. Requiring a clean tree makes every rewrite reviewable with `git diff`
|
|
20
|
+
* and revertible with `git checkout`, which is the only guard that covers the whole class
|
|
21
|
+
* rather than one spelling of it.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { execFileSync } from "child_process";
|
|
25
|
+
import { writeFileSync } from "fs";
|
|
26
|
+
import { resolve } from "path";
|
|
27
|
+
import { REPO_ROOT, census, classifyDoc, fixDoc, formatReport, readIndex, readPopulation } from "../lib/harness-parity";
|
|
28
|
+
|
|
29
|
+
const args = new Set(process.argv.slice(2));
|
|
30
|
+
const mode = args.has("--fix") ? "fix" : args.has("--report") ? "report" : undefined;
|
|
31
|
+
if (mode === undefined) {
|
|
32
|
+
console.error("usage: harness-parity-census.ts --report | --fix [--force]");
|
|
33
|
+
process.exit(2);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (mode === "fix" && !args.has("--force")) {
|
|
37
|
+
const dirty = execFileSync("git", ["status", "--porcelain", "--", "plugins/soleur"], {
|
|
38
|
+
cwd: REPO_ROOT,
|
|
39
|
+
encoding: "utf-8",
|
|
40
|
+
}).trim();
|
|
41
|
+
if (dirty.length > 0) {
|
|
42
|
+
console.error(
|
|
43
|
+
[
|
|
44
|
+
"harness-parity --fix: refusing to rewrite a dirty tree — it edits tracked files in place,",
|
|
45
|
+
"and an uncommitted change would be indistinguishable from its own rewrites in `git diff`.",
|
|
46
|
+
"Commit or discard the changes below, then re-run; pass --force to override.",
|
|
47
|
+
"",
|
|
48
|
+
dirty,
|
|
49
|
+
].join("\n"),
|
|
50
|
+
);
|
|
51
|
+
process.exit(2);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const index = readIndex();
|
|
56
|
+
const docs = readPopulation();
|
|
57
|
+
|
|
58
|
+
if (mode === "fix") {
|
|
59
|
+
let changed = 0;
|
|
60
|
+
let skipped = 0;
|
|
61
|
+
for (const doc of docs) {
|
|
62
|
+
// A malformed marker leaves the region state unreliable, and `fixDoc` mirrors that state to
|
|
63
|
+
// decide what is exempt — so rewriting such a doc can edit inside a region the author meant
|
|
64
|
+
// to protect. Report it and leave it; the marker is RED in the gate either way.
|
|
65
|
+
const pre = classifyDoc(doc.text, index, doc.regionPolicy, doc.path);
|
|
66
|
+
if (pre.errors.length > 0) {
|
|
67
|
+
console.log(`skipped ${doc.path} — malformed marker, fix the marker first:`);
|
|
68
|
+
for (const e of pre.errors) console.log(` ${e}`);
|
|
69
|
+
skipped += 1;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const fixed = fixDoc(doc.text, index, doc.regionPolicy);
|
|
73
|
+
if (fixed !== doc.text) {
|
|
74
|
+
writeFileSync(resolve(REPO_ROOT, doc.path), fixed);
|
|
75
|
+
changed += 1;
|
|
76
|
+
console.log(`fixed ${doc.path}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const after = census(readPopulation(), index);
|
|
80
|
+
console.log(`harness-parity --fix: ${changed} docs rewritten, ${skipped} skipped for malformed markers; ${after.noncanonical.length} non-canonical sites remain (hand edits)`);
|
|
81
|
+
process.exit(0);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const result = census(docs, index);
|
|
85
|
+
console.log(formatReport(result));
|
|
86
|
+
if (result.noncanonical.length > 0 || result.errors.length > 0) {
|
|
87
|
+
console.log(
|
|
88
|
+
`\nRED: ${result.noncanonical.length} non-canonical sites, ${result.errors.length} marker errors. ` +
|
|
89
|
+
"Run `bun plugins/soleur/scripts/harness-parity-census.ts --fix` for the mechanical shapes (it requires a clean tree, so its rewrites stay reviewable with `git diff`); the rest are hand edits.",
|
|
90
|
+
);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// Discoverability probe for #8296 PR-1: does the SOURCE declare the Inngest wrong-volume
|
|
3
|
+
// Better Stack alert ARMED? Resolves `paused = !var.inngest_luks_cutover_complete` against the
|
|
4
|
+
// variable's declared default through the same code path the drift reconciler uses
|
|
5
|
+
// (../lib/heartbeat-live-reconcile.ts via discoverLogsAlertsFromInfra), so a regression in either
|
|
6
|
+
// the declaration or the resolver prints EXEMPT here before it silences the twice-daily report.
|
|
7
|
+
//
|
|
8
|
+
// Credential-free and sub-second: it reads apps/web-platform/infra/*.tf only. It says nothing
|
|
9
|
+
// about the LIVE alert (a Doppler TF_VAR override, or a vendor-side pause) — that half is the
|
|
10
|
+
// reconciler's job on scheduled-terraform-drift.yml, and PR-2's followthrough probe covers the
|
|
11
|
+
// device the store is actually on.
|
|
12
|
+
//
|
|
13
|
+
// This is a standalone file, not a `bun -e` one-liner, because preflight Check 10 (ADR-175)
|
|
14
|
+
// runs the plan's discoverability command inside a sandbox behind a shell-active-token reject:
|
|
15
|
+
// an arrow function's `=>` and a statement `;` both trip it, by design.
|
|
16
|
+
//
|
|
17
|
+
// Exit 0 + "ARMED" when the declaration resolves to paused=false; exit 1 + "EXEMPT" otherwise
|
|
18
|
+
// (unresolvable variable, non-boolean default, or the alert missing from the root entirely).
|
|
19
|
+
import { discoverLogsAlertsFromInfra } from "./reconcile-live-heartbeats.ts";
|
|
20
|
+
|
|
21
|
+
// argv[2] is a TEST seam only (a synthesized root with the default flipped); the plan's
|
|
22
|
+
// discoverability command passes nothing and reads the real root.
|
|
23
|
+
const INFRA_DIR = process.argv[2] ?? "apps/web-platform/infra";
|
|
24
|
+
const RESOURCE = "inngest_luks_wrong_volume";
|
|
25
|
+
|
|
26
|
+
const alert = discoverLogsAlertsFromInfra(INFRA_DIR).find((a) => a.resourceName === RESOURCE);
|
|
27
|
+
const armed = alert?.pausedResolvesFalse === true;
|
|
28
|
+
console.log(armed ? "ARMED" : "EXEMPT");
|
|
29
|
+
process.exit(armed ? 0 : 1);
|
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Install the generated OpenCode front door into an OpenCode config directory.
|
|
4
|
+
*
|
|
5
|
+
* bun plugins/soleur/scripts/install-opencode-adapter.ts # ~/.config/opencode
|
|
6
|
+
* bun plugins/soleur/scripts/install-opencode-adapter.ts --target DIR # e.g. a project .opencode
|
|
7
|
+
* bun plugins/soleur/scripts/install-opencode-adapter.ts --check --target DIR
|
|
8
|
+
*
|
|
9
|
+
* Why this exists: the generated tree commits its paths as `__SOLEUR_PLUGIN_ROOT__` rather
|
|
10
|
+
* than absolute ones, because the tree is shared across machines and an absolute path would
|
|
11
|
+
* make `sync-opencode-adapter.ts --check` machine-dependent. OpenCode's `skills` and
|
|
12
|
+
* `instructions` keys take plain paths with no env expansion, and the config schema has no
|
|
13
|
+
* `import` key (measurement §7.1), so something must resolve the token once, on the
|
|
14
|
+
* operator's machine. That is this script.
|
|
15
|
+
*
|
|
16
|
+
* Shapes here are each forced by a measurement:
|
|
17
|
+
*
|
|
18
|
+
* - `agents/` and `commands/` are copied straight into the config dir, because those are
|
|
19
|
+
* the roots OpenCode discovers (§3.0, §4.0). Skills are **not** copied — they register
|
|
20
|
+
* from the canonical tree through the `skills` key (§2.0), so the config points at the
|
|
21
|
+
* checkout and a second skill tree that could drift is never created.
|
|
22
|
+
* - The config fragment is merged rather than written, so an operator's existing
|
|
23
|
+
* `skills` / `instructions` entries and every other key survive — for a config this script
|
|
24
|
+
* can READ. A config it cannot parse (JSONC comments, a syntax error, a torn write) is
|
|
25
|
+
* **refused**, not replaced: silently substituting `{}` would discard every key the operator
|
|
26
|
+
* ever set, and report success. `--force` replaces it after writing a `.bak-<ts>` beside it.
|
|
27
|
+
* - Writes are temp-file + rename, so an interrupted install cannot leave a half-written
|
|
28
|
+
* `opencode.json` whose next read takes the unparseable path.
|
|
29
|
+
* - The hook module (`opencode/plugin.ts`, source rather than a generated stub) is copied
|
|
30
|
+
* into `<configdir>/plugins/`, OpenCode's plugin discovery directory (measurement §6.6),
|
|
31
|
+
* with the plugin-root token resolved so the installed copy still reaches the checkout's
|
|
32
|
+
* guard scripts.
|
|
33
|
+
*
|
|
34
|
+
* `--check` writes nothing: it compares the target against `expectedInstalled` and exits 1
|
|
35
|
+
* on a difference.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "fs";
|
|
39
|
+
import { dirname, join, relative, resolve } from "path";
|
|
40
|
+
import {
|
|
41
|
+
ADAPTER_DIR,
|
|
42
|
+
ADAPTER_SOURCE_FILES,
|
|
43
|
+
PLUGIN_ROOT_TOKEN,
|
|
44
|
+
configFragmentValues,
|
|
45
|
+
expectedOpenCodeAdapter,
|
|
46
|
+
} from "./sync-opencode-adapter";
|
|
47
|
+
|
|
48
|
+
const PLUGIN_ROOT = resolve(dirname(import.meta.filename), "..");
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Where a vendored payload lives, target-relative.
|
|
52
|
+
*
|
|
53
|
+
* `<configdir>/soleur/` is already Soleur's exclusive namespace in a config dir (the installed
|
|
54
|
+
* `INSTRUCTIONS.md` lives there and `installedExtras` treats everything under it as ours by
|
|
55
|
+
* name), so the payload joins it rather than opening a second namespace. One directory is also
|
|
56
|
+
* one thing to remove on uninstall.
|
|
57
|
+
*/
|
|
58
|
+
export const VENDOR_DIR = "soleur";
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The plugin-root subtrees a vendored payload carries.
|
|
62
|
+
*
|
|
63
|
+
* A vendored payload is the canonical plugin root copied into the config dir. It exists because
|
|
64
|
+
* the npm distribution has **no checkout to point at**: `npx` runs the installer out of an
|
|
65
|
+
* ephemeral cache directory, so a config that named the package path rots the moment that cache
|
|
66
|
+
* is pruned — and the failure is silent, because the `skills` key and the guard scripts simply
|
|
67
|
+
* stop resolving. The copy is the durable root.
|
|
68
|
+
*
|
|
69
|
+
* Each entry is load-bearing: `skills` is what the `skills` key registers, `agents`/`commands`
|
|
70
|
+
* are what the generated stubs name, `hooks` is what the installed hook module spawns its guards
|
|
71
|
+
* from, `scripts` is what the canonical prose calls as `<root>/scripts/<name>.sh` (404 call
|
|
72
|
+
* sites), `lib` is what those scripts import, `opencode` is the generated tree the installer
|
|
73
|
+
* itself reads, and `.claude-plugin` is the identity marker `plugin-version.sh` and
|
|
74
|
+
* `resolve-regenerable-conflicts.sh` resolve the root by.
|
|
75
|
+
*/
|
|
76
|
+
export const PAYLOAD_DIRS = [
|
|
77
|
+
"skills",
|
|
78
|
+
"agents",
|
|
79
|
+
"commands",
|
|
80
|
+
"hooks",
|
|
81
|
+
"scripts",
|
|
82
|
+
"lib",
|
|
83
|
+
ADAPTER_DIR,
|
|
84
|
+
".claude-plugin",
|
|
85
|
+
] as const;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Marker that tells a plugin root apart as a **vendored payload** rather than a checkout.
|
|
89
|
+
*
|
|
90
|
+
* It is what lets the copy's own `scripts/install-opencode-adapter.ts --check` pass: run from
|
|
91
|
+
* `<configdir>/soleur/`, the payload is inside the target, so the extras sweep would otherwise
|
|
92
|
+
* report every one of the ~800 payload files as EXTRA and exit 1 — a correct install graded as
|
|
93
|
+
* broken.
|
|
94
|
+
*/
|
|
95
|
+
export const VENDOR_MARKER = ".soleur-vendored.json";
|
|
96
|
+
|
|
97
|
+
/** True when `root` is a payload the installer vendored, not a checkout. */
|
|
98
|
+
export function isVendoredRoot(root: string): boolean {
|
|
99
|
+
return existsSync(join(root, VENDOR_MARKER));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Deterministic marker bytes. No version and no timestamp: the payload's own files carry the
|
|
104
|
+
* version (an upgrade changes them and `--check` reports STALE), and a version here would make
|
|
105
|
+
* the marker flap between the two install modes.
|
|
106
|
+
*/
|
|
107
|
+
function vendorMarkerContent(): string {
|
|
108
|
+
return `${JSON.stringify({ format: 1, kind: "soleur-opencode-payload", owns: [...PAYLOAD_DIRS] }, null, 2)}\n`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Every file under `<root>/<dir>`, keyed `<dir>/<relative path>`, in sorted order. */
|
|
112
|
+
function walkPayloadFiles(root: string, dir: string): Array<[string, string]> {
|
|
113
|
+
const found: Array<[string, string]> = [];
|
|
114
|
+
const visit = (relativeDir: string): void => {
|
|
115
|
+
let entries;
|
|
116
|
+
try {
|
|
117
|
+
entries = readdirSync(join(root, relativeDir), { withFileTypes: true });
|
|
118
|
+
} catch {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
122
|
+
const path = `${relativeDir}/${entry.name}`;
|
|
123
|
+
if (entry.isDirectory()) {
|
|
124
|
+
visit(path);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
found.push([path, readFileSync(join(root, path), "utf-8")]);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
visit(dir);
|
|
131
|
+
return found;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface InstallOptions {
|
|
135
|
+
force?: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Mirror the canonical payload into `<target>/soleur/` and point every installed file at that
|
|
138
|
+
* copy instead of at `pluginRoot`. Used by the npm distribution, which has no checkout.
|
|
139
|
+
*
|
|
140
|
+
* A vendored payload is also recognised without this flag: a root carrying `VENDOR_MARKER`
|
|
141
|
+
* owns its payload wherever it sits inside the target, so the copy's own `--check` agrees
|
|
142
|
+
* with the install that produced it.
|
|
143
|
+
*/
|
|
144
|
+
vendorPayload?: boolean;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** `__SOLEUR_PLUGIN_ROOT__` → the real checkout. The only substitution in the whole install. */
|
|
148
|
+
function resolveToken(content: string, pluginRoot: string): string {
|
|
149
|
+
return content.split(PLUGIN_ROOT_TOKEN).join(pluginRoot);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Union a fragment's path arrays into an existing config, preserving every other key. */
|
|
153
|
+
export function mergeFragment(
|
|
154
|
+
existing: Record<string, unknown>,
|
|
155
|
+
fragment: { skills: string[]; instructions: string[] },
|
|
156
|
+
): Record<string, unknown> {
|
|
157
|
+
const merged: Record<string, unknown> = { ...existing };
|
|
158
|
+
for (const key of ["skills", "instructions"] as const) {
|
|
159
|
+
const present = Array.isArray(existing[key]) ? (existing[key] as unknown[]) : [];
|
|
160
|
+
merged[key] = [...present, ...fragment[key]].filter((value, index, all) => all.indexOf(value) === index);
|
|
161
|
+
}
|
|
162
|
+
return merged;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* A config file that exists but cannot be read as a JSON object.
|
|
167
|
+
*
|
|
168
|
+
* This is not a generic parse error: it is the branch that decides between merging into an
|
|
169
|
+
* operator's config and destroying it. It names the path and the remedy because the caller's
|
|
170
|
+
* only sane action is to look at that file.
|
|
171
|
+
*/
|
|
172
|
+
export class UnparseableConfigError extends Error {
|
|
173
|
+
constructor(
|
|
174
|
+
readonly path: string,
|
|
175
|
+
readonly detail: string,
|
|
176
|
+
) {
|
|
177
|
+
super(
|
|
178
|
+
`${path} exists but is not a JSON object (${detail}). Refusing to overwrite it — that would replace every key you set with the Soleur fragment alone. Fix the file, move it aside, or re-run with --force (which writes a timestamped backup first).`,
|
|
179
|
+
);
|
|
180
|
+
this.name = "UnparseableConfigError";
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Where each generated file lands in a config dir, with tokens resolved.
|
|
186
|
+
*
|
|
187
|
+
* The plugin module is the one file here that is **source, not a generated stub**: it is
|
|
188
|
+
* hand-written in the generator's namespace (`ADAPTER_SOURCE_FILES`) and installed into
|
|
189
|
+
* OpenCode's plugin discovery directory, `<configdir>/plugins/`, with the plugin-root token
|
|
190
|
+
* resolved so the checkout's guard scripts stay reachable from the installed copy.
|
|
191
|
+
*/
|
|
192
|
+
export function expectedInstalled(
|
|
193
|
+
targetDir: string,
|
|
194
|
+
pluginRoot = PLUGIN_ROOT,
|
|
195
|
+
config?: Record<string, unknown>,
|
|
196
|
+
options: InstallOptions = {},
|
|
197
|
+
): Map<string, string> {
|
|
198
|
+
const expected = new Map<string, string>();
|
|
199
|
+
// Where the installed files POINT, as opposed to where their bytes come from. The two are the
|
|
200
|
+
// same for a checkout install. They differ for a vendored payload, where the bytes come from
|
|
201
|
+
// the package and the pointer must name the copy — the only path that outlives the npm cache.
|
|
202
|
+
const effectiveRoot = options.vendorPayload === true ? join(targetDir, VENDOR_DIR) : pluginRoot;
|
|
203
|
+
for (const [path, content] of expectedOpenCodeAdapter(pluginRoot)) {
|
|
204
|
+
if (path === `${ADAPTER_DIR}/opencode.json`) continue; // merged below, never copied verbatim
|
|
205
|
+
// `opencode/` is the generator's namespace, not a discovery root. INSTRUCTIONS.md keeps a
|
|
206
|
+
// `soleur/` prefix so it cannot collide with anything the operator already has.
|
|
207
|
+
const installed =
|
|
208
|
+
path === `${ADAPTER_DIR}/INSTRUCTIONS.md` ? `soleur/${relative(ADAPTER_DIR, path)}` : relative(ADAPTER_DIR, path);
|
|
209
|
+
expected.set(installed, resolveToken(content, effectiveRoot));
|
|
210
|
+
}
|
|
211
|
+
for (const source of ADAPTER_SOURCE_FILES) {
|
|
212
|
+
if (!source.startsWith(`${ADAPTER_DIR}/`)) continue;
|
|
213
|
+
// Every `*.ts` in `<configdir>/plugins/` loads (measurement §6.6), so the installed name
|
|
214
|
+
// carries the plugin's namespace: a bare `plugin.ts` would collide with an operator's own.
|
|
215
|
+
const installed = `plugins/soleur-${source.slice(ADAPTER_DIR.length + 1)}`;
|
|
216
|
+
expected.set(installed, resolveToken(readFileSync(join(pluginRoot, source), "utf-8"), effectiveRoot));
|
|
217
|
+
}
|
|
218
|
+
for (const [path, content] of payloadExpected(targetDir, pluginRoot, effectiveRoot, options)) {
|
|
219
|
+
expected.set(path, content);
|
|
220
|
+
}
|
|
221
|
+
// One definition of the fragment's shape, shared with the generator: the generator emits it
|
|
222
|
+
// with the token, this resolves the token and unions it into the operator's config.
|
|
223
|
+
const fragment = configFragmentValues(effectiveRoot);
|
|
224
|
+
const merged = mergeFragment(config ?? readConfig(join(targetDir, "opencode.json")), {
|
|
225
|
+
skills: fragment.skills,
|
|
226
|
+
// The installed path (`soleur/`), not the generator's `opencode/` namespace.
|
|
227
|
+
instructions: [join(targetDir, "soleur", "INSTRUCTIONS.md")],
|
|
228
|
+
});
|
|
229
|
+
expected.set("opencode.json", `${JSON.stringify(merged, null, 2)}\n`);
|
|
230
|
+
return expected;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* The payload files this install owns, keyed target-relative.
|
|
235
|
+
*
|
|
236
|
+
* Content always comes from `sourceRoot` and is written under `effectiveRoot`, which is what
|
|
237
|
+
* makes the two install modes one code path: a checkout install has no payload inside the target
|
|
238
|
+
* (the checkout is the root, so `effectiveRoot` is outside it and this returns nothing), while a
|
|
239
|
+
* vendored install has `effectiveRoot` inside the target and mirrors the bytes there.
|
|
240
|
+
*
|
|
241
|
+
* Ownership is the point, not the copy: these paths join `expected`, so the extras sweep — which
|
|
242
|
+
* deletes anything under `soleur/` the installer did not write — keeps them instead of deleting
|
|
243
|
+
* the payload one pass after writing it.
|
|
244
|
+
*/
|
|
245
|
+
function payloadExpected(
|
|
246
|
+
targetDir: string,
|
|
247
|
+
sourceRoot: string,
|
|
248
|
+
effectiveRoot: string,
|
|
249
|
+
options: InstallOptions,
|
|
250
|
+
): Map<string, string> {
|
|
251
|
+
const owned = options.vendorPayload === true || isVendoredRoot(sourceRoot);
|
|
252
|
+
const result = new Map<string, string>();
|
|
253
|
+
if (!owned) return result;
|
|
254
|
+
const prefix = relative(targetDir, effectiveRoot).split("\\").join("/");
|
|
255
|
+
// A root outside the target owns nothing inside it: that is the checkout install.
|
|
256
|
+
if (prefix === "" || prefix.startsWith("..")) return result;
|
|
257
|
+
for (const dir of PAYLOAD_DIRS) {
|
|
258
|
+
for (const [path, content] of walkPayloadFiles(sourceRoot, dir)) {
|
|
259
|
+
result.set(`${prefix}/${path}`, content);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
result.set(`${prefix}/${VENDOR_MARKER}`, vendorMarkerContent());
|
|
263
|
+
return result;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Read an operator config. A **missing** config is an empty one (a first install); anything
|
|
268
|
+
* else that is not a JSON object throws `UnparseableConfigError`. The two cases were one branch
|
|
269
|
+
* (`catch → {}`), which made "first install" and "operator config with JSONC comments"
|
|
270
|
+
* indistinguishable — and the write path then replaced the second with the fragment alone.
|
|
271
|
+
*/
|
|
272
|
+
function readConfig(path: string): Record<string, unknown> {
|
|
273
|
+
let raw: string;
|
|
274
|
+
try {
|
|
275
|
+
raw = readFileSync(path, "utf-8");
|
|
276
|
+
} catch (error) {
|
|
277
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return {};
|
|
278
|
+
throw new UnparseableConfigError(path, `could not be read: ${String(error)}`);
|
|
279
|
+
}
|
|
280
|
+
let parsed: unknown;
|
|
281
|
+
try {
|
|
282
|
+
parsed = JSON.parse(raw);
|
|
283
|
+
} catch (error) {
|
|
284
|
+
throw new UnparseableConfigError(path, String(error));
|
|
285
|
+
}
|
|
286
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
287
|
+
throw new UnparseableConfigError(path, `top level is ${Array.isArray(parsed) ? "an array" : parsed === null ? "null" : typeof parsed}`);
|
|
288
|
+
}
|
|
289
|
+
return parsed as Record<string, unknown>;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/** Target-relative paths of every file under `dir` (empty when the directory is absent). */
|
|
293
|
+
function walkFiles(targetDir: string, dir: string): string[] {
|
|
294
|
+
const found: string[] = [];
|
|
295
|
+
const visit = (relativeDir: string): void => {
|
|
296
|
+
let entries;
|
|
297
|
+
try {
|
|
298
|
+
entries = readdirSync(join(targetDir, relativeDir), { withFileTypes: true });
|
|
299
|
+
} catch {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
for (const entry of entries) {
|
|
303
|
+
const path = `${relativeDir}/${entry.name}`;
|
|
304
|
+
if (entry.isDirectory()) visit(path);
|
|
305
|
+
else found.push(path);
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
visit(dir);
|
|
309
|
+
return found.sort();
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* The generated stubs' own signature. `agents/` and `commands/` are SHARED with the operator, so
|
|
314
|
+
* a file there is only removable when it says, in its own text, that this generator wrote it and
|
|
315
|
+
* that it points at the resolved checkout. Anything else in those roots is not ours.
|
|
316
|
+
*/
|
|
317
|
+
const STUB_SIGNATURES = ["Stub for the canonical agent `", "Run the canonical `"] as const;
|
|
318
|
+
|
|
319
|
+
function isGeneratedStub(content: string, pluginRoot: string): boolean {
|
|
320
|
+
return content.includes(pluginRoot) && STUB_SIGNATURES.some((signature) => content.includes(signature));
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Files an install owns but no longer generates. Without this, deleting an agent or renaming a
|
|
325
|
+
* command in the canonical tree leaves its installed stub loading forever — a half-updated
|
|
326
|
+
* install that `--check` would call ok.
|
|
327
|
+
*/
|
|
328
|
+
export function installedExtras(
|
|
329
|
+
targetDir: string,
|
|
330
|
+
expected: Map<string, string>,
|
|
331
|
+
root = PLUGIN_ROOT,
|
|
332
|
+
): string[] {
|
|
333
|
+
const extras: string[] = [];
|
|
334
|
+
// Exclusive namespaces: everything under `soleur/` and `plugins/soleur-*` is ours by name.
|
|
335
|
+
// A vendored payload's own files are in `expected`, so they are not "extras".
|
|
336
|
+
for (const path of walkFiles(targetDir, "soleur")) if (!expected.has(path)) extras.push(path);
|
|
337
|
+
for (const path of walkFiles(targetDir, "plugins")) {
|
|
338
|
+
if (path.startsWith("plugins/soleur-") && !expected.has(path)) extras.push(path);
|
|
339
|
+
}
|
|
340
|
+
// Shared roots: attributed by content, never by location. A stub names the RESOLVED root, so
|
|
341
|
+
// `root` here is the effective root the install wrote into those stubs, not the source.
|
|
342
|
+
for (const root_ of ["agents", "commands"]) {
|
|
343
|
+
for (const path of walkFiles(targetDir, root_)) {
|
|
344
|
+
if (expected.has(path)) continue;
|
|
345
|
+
let content: string;
|
|
346
|
+
try {
|
|
347
|
+
content = readFileSync(join(targetDir, path), "utf-8");
|
|
348
|
+
} catch {
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
if (isGeneratedStub(content, root)) extras.push(path);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return extras.sort();
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/** Write through a sibling temp file and rename, so a reader never sees a partial file. */
|
|
358
|
+
function writeAtomic(full: string, content: string): void {
|
|
359
|
+
mkdirSync(dirname(full), { recursive: true });
|
|
360
|
+
const temp = `${full}.soleur-tmp-${process.pid}`;
|
|
361
|
+
writeFileSync(temp, content);
|
|
362
|
+
renameSync(temp, full);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export interface InstallResult {
|
|
366
|
+
/** Config-dir-relative files written or updated, sorted. */
|
|
367
|
+
written: string[];
|
|
368
|
+
/** Config-dir-relative files that were already correct, sorted. */
|
|
369
|
+
unchanged: string[];
|
|
370
|
+
/** Config-dir-relative stale files removed, sorted. */
|
|
371
|
+
removed: string[];
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export function installOpenCodeAdapter(
|
|
375
|
+
targetDir: string,
|
|
376
|
+
pluginRoot = PLUGIN_ROOT,
|
|
377
|
+
options: InstallOptions = {},
|
|
378
|
+
): InstallResult {
|
|
379
|
+
const result: InstallResult = { written: [], unchanged: [], removed: [] };
|
|
380
|
+
const configPath = join(targetDir, "opencode.json");
|
|
381
|
+
let config: Record<string, unknown> | undefined;
|
|
382
|
+
try {
|
|
383
|
+
config = readConfig(configPath);
|
|
384
|
+
} catch (error) {
|
|
385
|
+
if (!(error instanceof UnparseableConfigError)) throw error;
|
|
386
|
+
if (options.force !== true) throw error;
|
|
387
|
+
const backup = `${configPath}.bak-${Date.now()}`;
|
|
388
|
+
copyFileSync(configPath, backup);
|
|
389
|
+
console.error(`[soleur] --force: replaced ${configPath}; the previous bytes are at ${backup}`);
|
|
390
|
+
config = {};
|
|
391
|
+
}
|
|
392
|
+
const expected = expectedInstalled(targetDir, pluginRoot, config, options);
|
|
393
|
+
const effectiveRoot = options.vendorPayload === true ? join(targetDir, VENDOR_DIR) : pluginRoot;
|
|
394
|
+
for (const [path, content] of expected) {
|
|
395
|
+
const full = join(targetDir, path);
|
|
396
|
+
let current: string | undefined;
|
|
397
|
+
try {
|
|
398
|
+
current = readFileSync(full, "utf-8");
|
|
399
|
+
} catch {
|
|
400
|
+
current = undefined;
|
|
401
|
+
}
|
|
402
|
+
if (current === content) {
|
|
403
|
+
result.unchanged.push(path);
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
writeAtomic(full, content);
|
|
407
|
+
result.written.push(path);
|
|
408
|
+
}
|
|
409
|
+
for (const path of installedExtras(targetDir, expected, effectiveRoot)) {
|
|
410
|
+
rmSync(join(targetDir, path), { force: true });
|
|
411
|
+
result.removed.push(path);
|
|
412
|
+
}
|
|
413
|
+
result.written.sort();
|
|
414
|
+
result.unchanged.sort();
|
|
415
|
+
result.removed.sort();
|
|
416
|
+
return result;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/** Read-only: paths the target does not already match. Empty means installed and current. */
|
|
420
|
+
export function installProblems(targetDir: string, pluginRoot = PLUGIN_ROOT, options: InstallOptions = {}): string[] {
|
|
421
|
+
const problems: string[] = [];
|
|
422
|
+
const expected = expectedInstalled(targetDir, pluginRoot, undefined, options);
|
|
423
|
+
const effectiveRoot = options.vendorPayload === true ? join(targetDir, VENDOR_DIR) : pluginRoot;
|
|
424
|
+
for (const [path, content] of expected) {
|
|
425
|
+
let current: string | undefined;
|
|
426
|
+
try {
|
|
427
|
+
current = readFileSync(join(targetDir, path), "utf-8");
|
|
428
|
+
} catch {
|
|
429
|
+
current = undefined;
|
|
430
|
+
}
|
|
431
|
+
if (current !== content) problems.push(current === undefined ? `MISSING: ${path}` : `STALE: ${path}`);
|
|
432
|
+
}
|
|
433
|
+
for (const path of installedExtras(targetDir, expected, effectiveRoot)) {
|
|
434
|
+
problems.push(`EXTRA: ${path}`);
|
|
435
|
+
}
|
|
436
|
+
return problems.sort();
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function parseArg(argv: readonly string[], flag: string): string | undefined {
|
|
440
|
+
const index = argv.indexOf(flag);
|
|
441
|
+
if (index === -1) return undefined;
|
|
442
|
+
const value = argv[index + 1];
|
|
443
|
+
if (value === undefined) throw new Error(`${flag} requires a directory`);
|
|
444
|
+
return value;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
const USAGE = [
|
|
448
|
+
"Usage: bun plugins/soleur/scripts/install-opencode-adapter.ts [--target DIR] [--plugin-root DIR] [--vendor-payload] [--check] [--force] [--help]",
|
|
449
|
+
"",
|
|
450
|
+
" --target DIR config dir to install into (default: $HOME/.config/opencode)",
|
|
451
|
+
" --plugin-root DIR checkout (or package) the installed files should point at (default: this checkout)",
|
|
452
|
+
" --vendor-payload copy the payload into <target>/soleur/ and point the installed files at that",
|
|
453
|
+
" copy; required when there is no checkout to point at (the npm distribution)",
|
|
454
|
+
" --check write nothing; report MISSING / STALE / EXTRA",
|
|
455
|
+
" --force replace an existing opencode.json that cannot be parsed (backup first)",
|
|
456
|
+
" --help, -h print this text and exit 0 without writing",
|
|
457
|
+
].join("\n");
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Unknown arguments are rejected: a typo (`--chek`) otherwise falls through to the WRITE path,
|
|
461
|
+
* which is the direction that changes an operator's machine.
|
|
462
|
+
*/
|
|
463
|
+
function validateArgs(argv: readonly string[]): void {
|
|
464
|
+
const withValue = new Set(["--target", "--plugin-root"]);
|
|
465
|
+
const known = new Set([...withValue, "--vendor-payload", "--check", "--force", "--help", "-h"]);
|
|
466
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
467
|
+
const arg = argv[i];
|
|
468
|
+
if (arg === "--help" || arg === "-h") {
|
|
469
|
+
console.log(USAGE);
|
|
470
|
+
process.exit(0);
|
|
471
|
+
}
|
|
472
|
+
if (!known.has(arg)) {
|
|
473
|
+
console.error(`unknown argument: ${arg}\n${USAGE}`);
|
|
474
|
+
process.exit(2);
|
|
475
|
+
}
|
|
476
|
+
if (withValue.has(arg)) i += 1;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function main(): void {
|
|
481
|
+
const argv = process.argv.slice(2);
|
|
482
|
+
validateArgs(argv);
|
|
483
|
+
const explicitTarget = parseArg(argv, "--target");
|
|
484
|
+
const home = process.env["HOME"];
|
|
485
|
+
if (explicitTarget === undefined && (home === undefined || home === "")) {
|
|
486
|
+
console.error(
|
|
487
|
+
"HOME is not set and --target was not given: refusing to install into a cwd-relative `.config/opencode`. Pass --target DIR.",
|
|
488
|
+
);
|
|
489
|
+
process.exit(2);
|
|
490
|
+
}
|
|
491
|
+
const targetDir = resolve(explicitTarget ?? join(home as string, ".config", "opencode"));
|
|
492
|
+
const pluginRoot = resolve(parseArg(argv, "--plugin-root") ?? PLUGIN_ROOT);
|
|
493
|
+
const options: InstallOptions = {
|
|
494
|
+
force: argv.includes("--force"),
|
|
495
|
+
vendorPayload: argv.includes("--vendor-payload"),
|
|
496
|
+
};
|
|
497
|
+
try {
|
|
498
|
+
if (argv.includes("--check")) {
|
|
499
|
+
const problems = installProblems(targetDir, pluginRoot, options);
|
|
500
|
+
if (problems.length > 0) {
|
|
501
|
+
for (const problem of problems) console.error(problem);
|
|
502
|
+
process.exit(1);
|
|
503
|
+
}
|
|
504
|
+
console.log("opencode-install ok");
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
const result = installOpenCodeAdapter(targetDir, pluginRoot, options);
|
|
508
|
+
console.log(
|
|
509
|
+
`opencode-adapter installed into ${targetDir} (${result.written.length} written, ${result.unchanged.length} unchanged, ${result.removed.length} removed)`,
|
|
510
|
+
);
|
|
511
|
+
} catch (error) {
|
|
512
|
+
if (error instanceof UnparseableConfigError) {
|
|
513
|
+
console.error(error.message);
|
|
514
|
+
process.exit(1);
|
|
515
|
+
}
|
|
516
|
+
throw error;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (import.meta.main) main();
|