@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,493 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Soleur's OpenCode plugin — the OpenCode peer of `hooks/hooks.json`.
|
|
4
|
+
*
|
|
5
|
+
* LOAD SHAPE (measured — measurement §6.6 arm A). OpenCode 2.0.32 requires a **default**
|
|
6
|
+
* export carrying an `id` and a `setup` function. The V1 named-export form
|
|
7
|
+
* (`export const Soleur = async (ctx) => ({ hooks })`) is rejected outright:
|
|
8
|
+
* `Plugin must export a default definition with an id and an effect or setup function.`
|
|
9
|
+
* A plain object importing only `node:` builtins is enough to load (arms B/C), so this
|
|
10
|
+
* module deliberately imports nothing from `@opencode/plugin` and carries no runtime
|
|
11
|
+
* dependency. That is also why the pin task resolves to "nothing to pin": there is no vendor
|
|
12
|
+
* package on the module's import graph (measurement §6.6, "Package identity").
|
|
13
|
+
*
|
|
14
|
+
* WHY THIS FILE IS NOT GENERATED. It holds dispatch logic that has to be unit-tested by
|
|
15
|
+
* import, and a generator-owned template string cannot be imported. The generator therefore
|
|
16
|
+
* treats it as a **source file** (`ADAPTER_SOURCE_FILES` in `scripts/sync-opencode-adapter.ts`):
|
|
17
|
+
* it asserts the file exists, never emits it, and never deletes it. The installer copies it
|
|
18
|
+
* into `<configdir>/plugins/` with the `__SOLEUR_PLUGIN_ROOT__` token resolved.
|
|
19
|
+
*
|
|
20
|
+
* WHERE THE GUARDS BIND, AND WHY NOT SOMEWHERE ELSE (measurement §12). The Bash guards bind at
|
|
21
|
+
* `ctx.permission.hook("evaluate")`, whose event carries the tool as `action` and the command
|
|
22
|
+
* as `resources[0]`, with a **mutable** `effect: allow | ask | deny`. Measured live:
|
|
23
|
+
*
|
|
24
|
+
* - `effect = "deny"` + `message` ⇒ the tool ends `{status:"error", error:{type:
|
|
25
|
+
* "permission.rejected", message}}`, it never runs, and the model reads the message.
|
|
26
|
+
* - `effect = "ask"` + `message` ⇒ the tool stays `running` awaiting a decision. A real
|
|
27
|
+
* prompt, so a guard's `ask` is delivered as an `ask` and NOT downgraded to a refusal.
|
|
28
|
+
*
|
|
29
|
+
* `ctx.tool.hook("execute.before")` is deliberately **not** bound. It fires *before* the
|
|
30
|
+
* permission hook, and its only refusal channel is a thrown error, so binding it would let a
|
|
31
|
+
* `deny`-or-`ask` both collapse into a throw and preempt the real ask behind it. It is a fine
|
|
32
|
+
* surface (a throw there was measured to block the call and reach the model) and simply the
|
|
33
|
+
* wrong one for a two-valued guard.
|
|
34
|
+
*
|
|
35
|
+
* WHAT IT CANNOT DO (measurement §6.6). Every V2 hook surface communicates only by mutating
|
|
36
|
+
* the event object it is handed, and `ctx.event.subscribe` is a one-way iterator with no
|
|
37
|
+
* return channel. No hook can defer a stop, force a continuation, or veto a completion.
|
|
38
|
+
* The completion marker is therefore observed, never enforced.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
import { spawnSync } from "node:child_process";
|
|
42
|
+
import { appendFileSync, existsSync, lstatSync, readFileSync } from "node:fs";
|
|
43
|
+
import { join, resolve } from "node:path";
|
|
44
|
+
|
|
45
|
+
/** Replaced in place by `install-opencode-adapter.ts` with the checkout path. */
|
|
46
|
+
const INSTALLED_ROOT = "__SOLEUR_PLUGIN_ROOT__";
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Where the guard scripts live.
|
|
50
|
+
*
|
|
51
|
+
* In an installed copy the installer has already replaced `INSTALLED_ROOT` with the checkout
|
|
52
|
+
* path, and this module sits at `<configdir>/plugins/`, so only the token knows where the
|
|
53
|
+
* checkout is. In an unresolved copy — the committed tree, a test run — the module still sits
|
|
54
|
+
* at `<checkout>/opencode/`, so its own parent IS the checkout. The two are told apart by the
|
|
55
|
+
* plugin identity file (`.claude-plugin/plugin.json`), which only a checkout carries — the
|
|
56
|
+
* repo's established root-resolution marker (devin/INSTRUCTIONS.md §Detection). (A module that
|
|
57
|
+
* landed at `<configdir>/plugins/` still carrying the literal token must not resolve to a
|
|
58
|
+
* *relative* token: a planted `__SOLEUR_PLUGIN_ROOT__/hooks/` directory inside the session's own
|
|
59
|
+
* working directory would then supply both guard scripts. It is anchored at `/` so that path
|
|
60
|
+
* cannot exist, and `decideBash` turns the failed spawn into a deny naming the dead path.) The
|
|
61
|
+
* env override exists so a test or a local run can point at a checkout explicitly.
|
|
62
|
+
*/
|
|
63
|
+
function resolvePluginRoot(): string {
|
|
64
|
+
const override = process.env["SOLEUR_OPENCODE_PLUGIN_ROOT"];
|
|
65
|
+
if (override !== undefined && override !== "") return override;
|
|
66
|
+
const sibling = resolve(import.meta.dir, "..");
|
|
67
|
+
return existsSync(join(sibling, ".claude-plugin", "plugin.json")) ? sibling : join("/", INSTALLED_ROOT);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const PLUGIN_ROOT = resolvePluginRoot();
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* OpenCode tool wire name → the Claude Code tool name the guard scripts decide on.
|
|
74
|
+
*
|
|
75
|
+
* `shell` is the measured wire name of the shell tool on 2.0.32 (§12.1): a live
|
|
76
|
+
* `tool.execute.before` carried `tool="shell"` and a live `permission.evaluate` carried
|
|
77
|
+
* `action="shell"`. `bash` is kept as well because the permission-key table in the V1 docs
|
|
78
|
+
* names the key `bash`; if the wire name ever tracks that table, the mapping still holds.
|
|
79
|
+
* An unmapped name passes through unchanged, and the guards decline a name that is not `Bash`.
|
|
80
|
+
*/
|
|
81
|
+
const CLAUDE_TOOL_NAME: Readonly<Record<string, string>> = {
|
|
82
|
+
shell: "Bash",
|
|
83
|
+
bash: "Bash",
|
|
84
|
+
edit: "Edit",
|
|
85
|
+
write: "Write",
|
|
86
|
+
read: "Read",
|
|
87
|
+
grep: "Grep",
|
|
88
|
+
glob: "Glob",
|
|
89
|
+
apply_patch: "Write",
|
|
90
|
+
skill: "Skill",
|
|
91
|
+
webfetch: "WebFetch",
|
|
92
|
+
websearch: "WebSearch",
|
|
93
|
+
question: "AskUserQuestion",
|
|
94
|
+
task: "Task",
|
|
95
|
+
// The measured V2 spawn tool (§12.8): the same logical agent, named `subagent` on the wire.
|
|
96
|
+
subagent: "Task",
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Guards that decide a shell call, in `hooks.json` registration order. The first guard to
|
|
101
|
+
* return a decision ends the walk, matching the Claude registrations, where an earlier hook's
|
|
102
|
+
* `deny` is already final.
|
|
103
|
+
*/
|
|
104
|
+
export const BASH_GUARDS: readonly { id: string; script: string }[] = [
|
|
105
|
+
{ id: "browser-snapshot-credential-guard", script: "hooks/browser-snapshot-credential-guard.sh" },
|
|
106
|
+
{ id: "destructive-command-guard", script: "hooks/destructive-command-guard.sh" },
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
/** Wall-clock bound for one guard spawn. `hooks.json` registers the same guards at 10 s. */
|
|
110
|
+
const GUARD_TIMEOUT_MS = 12_000;
|
|
111
|
+
|
|
112
|
+
export interface ScriptRun {
|
|
113
|
+
status: number | null;
|
|
114
|
+
stdout: string;
|
|
115
|
+
stderr: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export type ScriptRunner = (script: string, stdin: string, cwd: string) => ScriptRun;
|
|
119
|
+
|
|
120
|
+
/** Run a hook script the way the harness does: JSON envelope in on stdin, JSON out on stdout. */
|
|
121
|
+
export function runScript(script: string, stdin: string, cwd: string): ScriptRun {
|
|
122
|
+
const result = spawnSync("bash", [script], {
|
|
123
|
+
input: stdin,
|
|
124
|
+
cwd,
|
|
125
|
+
encoding: "utf8",
|
|
126
|
+
timeout: GUARD_TIMEOUT_MS,
|
|
127
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
128
|
+
env: { ...process.env, CLAUDE_PROJECT_DIR: cwd },
|
|
129
|
+
});
|
|
130
|
+
return {
|
|
131
|
+
status: result.status,
|
|
132
|
+
stdout: typeof result.stdout === "string" ? result.stdout : "",
|
|
133
|
+
stderr: typeof result.stderr === "string" ? result.stderr : "",
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Last parseable JSON object in a stream — a script may print a diagnostic line first. */
|
|
138
|
+
function lastJsonObject(text: string): Record<string, unknown> | undefined {
|
|
139
|
+
const whole = text.trim();
|
|
140
|
+
if (whole !== "") {
|
|
141
|
+
try {
|
|
142
|
+
const parsed: unknown = JSON.parse(whole);
|
|
143
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
144
|
+
return parsed as Record<string, unknown>;
|
|
145
|
+
}
|
|
146
|
+
} catch {
|
|
147
|
+
// fall through to the line scan
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const lines = text.split("\n");
|
|
151
|
+
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
152
|
+
const line = lines[i].trim();
|
|
153
|
+
if (!line.startsWith("{")) continue;
|
|
154
|
+
try {
|
|
155
|
+
const parsed: unknown = JSON.parse(line);
|
|
156
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
157
|
+
return parsed as Record<string, unknown>;
|
|
158
|
+
}
|
|
159
|
+
} catch {
|
|
160
|
+
// keep scanning
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function objectField(source: Record<string, unknown> | undefined, key: string): Record<string, unknown> | undefined {
|
|
167
|
+
const value = source?.[key];
|
|
168
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
169
|
+
? (value as Record<string, unknown>)
|
|
170
|
+
: undefined;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function claudeToolName(tool: string): string {
|
|
174
|
+
return CLAUDE_TOOL_NAME[tool] ?? tool;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* The Claude PreToolUse envelope the guards parse. Returns `undefined` for any tool the guards
|
|
179
|
+
* cannot decide, so no process is spawned for a call no guard would look at. `tool_input` is
|
|
180
|
+
* passed through whole rather than pre-extracted: the destructive guard's documented behavior
|
|
181
|
+
* on an absent or non-string `command` is to **ask**, and pre-extracting here would silently
|
|
182
|
+
* turn that ask into an allow.
|
|
183
|
+
*/
|
|
184
|
+
export function guardEnvelope(tool: string, input: unknown, cwd: string): string | undefined {
|
|
185
|
+
const name = claudeToolName(tool);
|
|
186
|
+
if (name !== "Bash") return undefined;
|
|
187
|
+
const toolInput = input !== null && typeof input === "object" && !Array.isArray(input) ? input : {};
|
|
188
|
+
return JSON.stringify({ hook_event_name: "PreToolUse", tool_name: name, tool_input: toolInput, cwd });
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export interface GuardDecision {
|
|
192
|
+
guard: string;
|
|
193
|
+
decision: "deny" | "ask";
|
|
194
|
+
reason: string;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Read `hookSpecificOutput.permissionDecision` out of a guard's stdout. No decision → undefined. */
|
|
198
|
+
export function parseGuardOutput(stdout: string): { decision: "deny" | "ask"; reason: string } | undefined {
|
|
199
|
+
const specific = objectField(lastJsonObject(stdout), "hookSpecificOutput");
|
|
200
|
+
const decision = specific?.["permissionDecision"];
|
|
201
|
+
if (decision !== "deny" && decision !== "ask") return undefined;
|
|
202
|
+
const reason = specific?.["permissionDecisionReason"];
|
|
203
|
+
return { decision, reason: typeof reason === "string" ? reason : "" };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** The guard id a failed guard *run* is reported under — never a guard that examined and declined. */
|
|
207
|
+
export const GUARD_RUN_FAILURE = "guard-did-not-run";
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Run the Bash guards in order for a tool call; the first decision wins. `undefined` means
|
|
211
|
+
* every guard **ran and declined**, and the call proceeds unchanged.
|
|
212
|
+
*
|
|
213
|
+
* A run that did not produce a decision is not the same event. Both guard scripts print a
|
|
214
|
+
* decision or nothing and exit 0 in every path, so a non-zero status (missing or moved checkout,
|
|
215
|
+
* an unresolved `__SOLEUR_PLUGIN_ROOT__` → 127, a spawn error, the 12 s timeout → `null`) means
|
|
216
|
+
* the guard never spoke. That is a **deny**, with the dead path in the reason: the alternative is
|
|
217
|
+
* a silent fail-open of the credential and destructive-command guards — a support failure dressed
|
|
218
|
+
* as a feature, and the exact class this adapter's spec names as its load-bearing risk. Measured:
|
|
219
|
+
* `decideBash("shell", {command:"rm -rf /"}, …)` returned `undefined` for a `{status:127}` runner
|
|
220
|
+
* before this branch (10-seat review, 2026-10-19).
|
|
221
|
+
*/
|
|
222
|
+
export function decideBash(
|
|
223
|
+
tool: string,
|
|
224
|
+
input: unknown,
|
|
225
|
+
cwd: string,
|
|
226
|
+
runner: ScriptRunner = runScript,
|
|
227
|
+
pluginRoot: string = PLUGIN_ROOT,
|
|
228
|
+
): GuardDecision | undefined {
|
|
229
|
+
const envelope = guardEnvelope(tool, input, cwd);
|
|
230
|
+
if (envelope === undefined) return undefined;
|
|
231
|
+
for (const guard of BASH_GUARDS) {
|
|
232
|
+
const script = join(pluginRoot, guard.script);
|
|
233
|
+
const run = runner(script, envelope, cwd);
|
|
234
|
+
const parsed = parseGuardOutput(run.stdout);
|
|
235
|
+
if (parsed !== undefined) return { guard: guard.id, ...parsed };
|
|
236
|
+
if (run.status !== 0) {
|
|
237
|
+
const how = run.status === null ? "timed out or could not be spawned" : `exited ${run.status}`;
|
|
238
|
+
return {
|
|
239
|
+
guard: GUARD_RUN_FAILURE,
|
|
240
|
+
decision: "deny",
|
|
241
|
+
reason: `the guard did not run (${how}): ${script}. The checkout the adapter points at may have moved or been removed — re-run \`bun "${INSTALLED_ROOT}/scripts/install-opencode-adapter.ts" --check\` from the plugin checkout. The command was NOT run, because an unrunnable guard cannot vouch for it.`,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return undefined;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* The command a `permission.evaluate` event describes.
|
|
250
|
+
*
|
|
251
|
+
* Measured shape (§12.2): a shell call arrives as `action: "shell"`,
|
|
252
|
+
* `resources: ["echo hello-from-probe"]` — one string that IS the command. Joining rather than
|
|
253
|
+
* indexing is deliberate: it cannot lose text if a shell call ever arrives with more than one
|
|
254
|
+
* resource, and it is identical to indexing on the measured shape.
|
|
255
|
+
*/
|
|
256
|
+
export function permissionCommand(resources: readonly unknown[]): string {
|
|
257
|
+
return resources.filter((resource): resource is string => typeof resource === "string").join("\n");
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Decide a `permission.evaluate` event. Non-shell actions cost nothing: the tool-name gate
|
|
262
|
+
* inside `guardEnvelope` returns before any process is spawned.
|
|
263
|
+
*/
|
|
264
|
+
export function decidePermission(
|
|
265
|
+
action: unknown,
|
|
266
|
+
resources: readonly unknown[],
|
|
267
|
+
cwd: string,
|
|
268
|
+
runner: ScriptRunner = runScript,
|
|
269
|
+
pluginRoot: string = PLUGIN_ROOT,
|
|
270
|
+
): GuardDecision | undefined {
|
|
271
|
+
if (typeof action !== "string") return undefined;
|
|
272
|
+
return decideBash(action, { command: permissionCommand(resources) }, cwd, runner, pluginRoot);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* The message the decision carries. The guard's own reason is already the operator-facing text
|
|
277
|
+
* (`This command was NOT run. …` / `Stop and tell the person …`), so it is passed through whole
|
|
278
|
+
* and only prefixed with which guard spoke — never rewritten, because the reason contains the
|
|
279
|
+
* escalation instructions a person needs.
|
|
280
|
+
*/
|
|
281
|
+
export function decisionMessage(decision: GuardDecision): string {
|
|
282
|
+
const head = `Soleur's ${decision.guard}:`;
|
|
283
|
+
return decision.reason === "" ? head : `${head} ${decision.reason}`;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** ADR-094: the corpus's frontmatter is stripped before injection. */
|
|
287
|
+
export function stripFrontmatter(text: string): string {
|
|
288
|
+
return text.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "");
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** A regular file that is not a symlink — the rules loader's prompt-injection defense, kept. */
|
|
292
|
+
function isRealFile(path: string): boolean {
|
|
293
|
+
try {
|
|
294
|
+
return lstatSync(path).isFile();
|
|
295
|
+
} catch {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function additionalContext(stdout: string): string | undefined {
|
|
301
|
+
const value = objectField(lastJsonObject(stdout), "hookSpecificOutput")?.["additionalContext"];
|
|
302
|
+
return typeof value === "string" && value !== "" ? value : undefined;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* The rule corpus for a session, reuse-first.
|
|
307
|
+
*
|
|
308
|
+
* Where the repository carries the canonical loader (`.claude/hooks/session-rules-loader.sh` —
|
|
309
|
+
* ADR-151's frontmatter strip, over-strip guard, symlink rejection, manifest and stamps), it is
|
|
310
|
+
* invoked with a SessionStart envelope and its `additionalContext` is used verbatim. Otherwise
|
|
311
|
+
* the corpus is read directly, keeping the two properties that must never be missing: a symlink
|
|
312
|
+
* is refused, and frontmatter is stripped. Everything the loader adds on top of that (the
|
|
313
|
+
* manifest, the tmpfs alarm block, the SOC 2 session-context snapshot) is not reproduced, and
|
|
314
|
+
* the disposition ledger says so.
|
|
315
|
+
*/
|
|
316
|
+
export function rulesInjection(cwd: string, runner: ScriptRunner = runScript): string | undefined {
|
|
317
|
+
const loader = join(cwd, ".claude", "hooks", "session-rules-loader.sh");
|
|
318
|
+
if (isRealFile(loader)) {
|
|
319
|
+
const envelope = JSON.stringify({ hook_event_name: "SessionStart", source: "startup", cwd });
|
|
320
|
+
const injected = additionalContext(runner(loader, envelope, cwd).stdout);
|
|
321
|
+
if (injected !== undefined) return injected;
|
|
322
|
+
}
|
|
323
|
+
const corpus = join(cwd, "AGENTS.rules.md");
|
|
324
|
+
if (isRealFile(corpus)) return stripFrontmatter(readFileSync(corpus, "utf8"));
|
|
325
|
+
return undefined;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* The post-compaction re-read directive. `compaction-state.sh` cannot be reused: it counts
|
|
330
|
+
* `compact_boundary` records in a Claude Code transcript, which this harness has no equivalent
|
|
331
|
+
* of. The directive is reproduced; the window bookkeeping is not (disposition: `downgraded`).
|
|
332
|
+
*/
|
|
333
|
+
export function compactionDirective(): string {
|
|
334
|
+
return [
|
|
335
|
+
"[soleur] A checkpoint summary has replaced part of this conversation.",
|
|
336
|
+
"Re-read the rule corpus (`AGENTS.rules.md`, or the copy injected at session start) before",
|
|
337
|
+
"continuing: a summary compresses rule bodies, and a rule you cannot quote is a rule you",
|
|
338
|
+
"cannot follow.",
|
|
339
|
+
].join(" ");
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** Optional observation target. Unset means the completion observer writes nothing. */
|
|
343
|
+
const EVENT_LOG = process.env["SOLEUR_OPENCODE_EVENT_LOG"];
|
|
344
|
+
|
|
345
|
+
export interface PermissionEvaluateEvent {
|
|
346
|
+
readonly action?: unknown;
|
|
347
|
+
readonly resources?: readonly unknown[];
|
|
348
|
+
readonly agent?: unknown;
|
|
349
|
+
effect: "allow" | "ask" | "deny";
|
|
350
|
+
message?: string;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export interface SetupContext {
|
|
354
|
+
location?: { directory?: string };
|
|
355
|
+
permission: {
|
|
356
|
+
hook(
|
|
357
|
+
name: "evaluate",
|
|
358
|
+
handler: (event: PermissionEvaluateEvent) => Promise<void> | void,
|
|
359
|
+
): Promise<unknown>;
|
|
360
|
+
};
|
|
361
|
+
session: {
|
|
362
|
+
hook(
|
|
363
|
+
name: string,
|
|
364
|
+
handler: (event: Record<string, unknown>) => Promise<void> | void,
|
|
365
|
+
options?: { providerID?: string },
|
|
366
|
+
): Promise<unknown>;
|
|
367
|
+
};
|
|
368
|
+
event: { subscribe(options?: { signal?: AbortSignal }): AsyncIterable<{ type?: string; data?: unknown }> };
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/** Session-scoped injection state: inject once, then again after a compaction. */
|
|
372
|
+
interface SessionState {
|
|
373
|
+
injected: boolean;
|
|
374
|
+
compacted: boolean;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Cap on remembered sessions. A long-lived `opencode serve` sees one session per conversation and
|
|
379
|
+
* no session-end event was measured to hook (§6.6), so the map is bounded here and the oldest
|
|
380
|
+
* entry is evicted first — `Map` preserves insertion order, so this is a two-line LRU.
|
|
381
|
+
*/
|
|
382
|
+
const MAX_SESSIONS = 500;
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Build `setup`. The hooks are returned bound to injected collaborators so the unit tests can
|
|
386
|
+
* drive them with a fake context and a fake script runner.
|
|
387
|
+
*/
|
|
388
|
+
export function createSetup(
|
|
389
|
+
runner: ScriptRunner = runScript,
|
|
390
|
+
pluginRoot: string = PLUGIN_ROOT,
|
|
391
|
+
write: (line: string) => void = (line) => {
|
|
392
|
+
if (EVENT_LOG !== undefined) appendFileSync(EVENT_LOG, `${line}\n`);
|
|
393
|
+
},
|
|
394
|
+
): (ctx: SetupContext) => Promise<void> {
|
|
395
|
+
const sessions = new Map<string, SessionState>();
|
|
396
|
+
|
|
397
|
+
/** Wire-controlled text before it goes into a TSV line: no C0/C1, no line/paragraph separators. */
|
|
398
|
+
const field = (value: unknown): string => String(value).replace(/[\u0000-\u001f\u007f\u2028\u2029]/g, "_");
|
|
399
|
+
|
|
400
|
+
/** Remember a session's state, keeping the map bounded and the most recent entry last. */
|
|
401
|
+
const remember = (id: string, state: SessionState): void => {
|
|
402
|
+
sessions.delete(id);
|
|
403
|
+
sessions.set(id, state);
|
|
404
|
+
while (sessions.size > MAX_SESSIONS) {
|
|
405
|
+
const oldest = sessions.keys().next();
|
|
406
|
+
if (oldest.done === true) break;
|
|
407
|
+
sessions.delete(oldest.value);
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
return async function setup(ctx: SetupContext): Promise<void> {
|
|
412
|
+
const sessionCwd = ctx.location?.directory ?? process.cwd();
|
|
413
|
+
|
|
414
|
+
// The only blocking surface bound here. A guard's decision replaces the ruleset's own verdict
|
|
415
|
+
// — except in one direction: an arriving `deny` is never relaxed to `ask`. Only `allow`
|
|
416
|
+
// arrivals were measured (§12.2), and relaxing an unmeasured deny is the silent-enforcement-loss
|
|
417
|
+
// direction.
|
|
418
|
+
await ctx.permission.hook("evaluate", (event) => {
|
|
419
|
+
const decision = decidePermission(event.action, event.resources ?? [], sessionCwd, runner, pluginRoot);
|
|
420
|
+
if (decision === undefined) return;
|
|
421
|
+
if (event.effect === "deny" && decision.decision === "ask") return;
|
|
422
|
+
event.effect = decision.decision;
|
|
423
|
+
event.message = decisionMessage(decision);
|
|
424
|
+
// A guard that could not run is an operator-visible fault, so it is announced even when the
|
|
425
|
+
// observation channel was never armed.
|
|
426
|
+
if (decision.guard === GUARD_RUN_FAILURE) {
|
|
427
|
+
console.error(`[soleur] ${decision.reason}`);
|
|
428
|
+
write(`soleur-opencode\tguard-run-failure\teffect=deny\t${field(decision.reason)}`);
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
await ctx.session.hook("context", (event) => {
|
|
433
|
+
const cwd = typeof event["cwd"] === "string" ? event["cwd"] : sessionCwd;
|
|
434
|
+
const rawSessionID = event["sessionID"];
|
|
435
|
+
const sessionID = typeof rawSessionID === "string" ? rawSessionID : undefined;
|
|
436
|
+
// A missing or non-string id gets no shared bucket: one session's `injected` must never
|
|
437
|
+
// silence another's. Such an event injects and is not memoized.
|
|
438
|
+
const state =
|
|
439
|
+
sessionID === undefined ? { injected: false, compacted: false } : (sessions.get(sessionID) ?? { injected: false, compacted: false });
|
|
440
|
+
if (state.injected && !state.compacted) return;
|
|
441
|
+
const system = event["system"];
|
|
442
|
+
if (!Array.isArray(system)) {
|
|
443
|
+
write(`soleur-opencode\tcontext\tno-system-array\tsession=${field(sessionID)}`);
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
// The compaction hook's own `system` reaches only the summarization call, so the re-read
|
|
447
|
+
// directive has to ride the next real request — which is this one (measurement §12.3).
|
|
448
|
+
if (state.compacted) system.push({ type: "text", text: compactionDirective() });
|
|
449
|
+
const rules = rulesInjection(cwd, runner);
|
|
450
|
+
if (rules !== undefined) system.push({ type: "text", text: rules });
|
|
451
|
+
// One line per injection decision: whether the corpus landed must be answerable from the
|
|
452
|
+
// log, so a hook that stops firing — or a corpus that moved — is visible rather than
|
|
453
|
+
// indistinguishable from working.
|
|
454
|
+
const outcome = rules === undefined ? "no-corpus" : `injected:${rules.length}`;
|
|
455
|
+
write(`soleur-opencode\tcontext\t${outcome}\tsession=${field(sessionID)}\tcwd=${field(cwd)}`);
|
|
456
|
+
if (sessionID !== undefined) remember(sessionID, { injected: true, compacted: false });
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
await ctx.session.hook("compaction", (event) => {
|
|
460
|
+
const rawSessionID = event["sessionID"];
|
|
461
|
+
if (typeof rawSessionID !== "string") {
|
|
462
|
+
write(`soleur-opencode\tcompaction\tunkeyed\treread-not-armed`);
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
const state = sessions.get(rawSessionID) ?? { injected: false, compacted: false };
|
|
466
|
+
remember(rawSessionID, { ...state, compacted: true });
|
|
467
|
+
write(`soleur-opencode\tcompaction\treread-armed\tsession=${field(rawSessionID)}`);
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
// Observation only, and it must stay that way: §6.6 measured no return channel, so an idle
|
|
471
|
+
// signal can be noticed and acted on by nothing. Off unless SOLEUR_OPENCODE_EVENT_LOG names
|
|
472
|
+
// a path.
|
|
473
|
+
void (async () => {
|
|
474
|
+
try {
|
|
475
|
+
for await (const event of ctx.event.subscribe()) {
|
|
476
|
+
const type = typeof event?.type === "string" ? event.type : "unknown";
|
|
477
|
+
if (type.startsWith("session.")) write(`soleur-opencode\t${field(type)}\tadvisory-completion-marker-not-enforceable`);
|
|
478
|
+
}
|
|
479
|
+
} catch (error) {
|
|
480
|
+
write(`soleur-opencode\tevent-stream-error\t${field(String(error))}`);
|
|
481
|
+
}
|
|
482
|
+
})();
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* The module's default export — a static object, because the loader reads `id` and `setup` off
|
|
488
|
+
* the default export directly.
|
|
489
|
+
*/
|
|
490
|
+
export default {
|
|
491
|
+
id: "soleur",
|
|
492
|
+
setup: createSetup(),
|
|
493
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soleur/opencode",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Soleur AI organization plugin for OpenCode",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"soleur-opencode": "bin/soleur-opencode.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"install.js",
|
|
11
|
+
"bin",
|
|
12
|
+
"opencode",
|
|
13
|
+
"skills",
|
|
14
|
+
"agents",
|
|
15
|
+
"commands",
|
|
16
|
+
"scripts",
|
|
17
|
+
"hooks",
|
|
18
|
+
"lib",
|
|
19
|
+
".claude-plugin"
|
|
20
|
+
],
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"yaml": "^2.8.3"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"opencode",
|
|
26
|
+
"plugin",
|
|
27
|
+
"ai-agents",
|
|
28
|
+
"soleur"
|
|
29
|
+
],
|
|
30
|
+
"author": "Jean Deruelle <jean.deruelle@jikigai.com>",
|
|
31
|
+
"license": "BUSL-1.1",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/jikig-ai/soleur.git",
|
|
35
|
+
"directory": "packages/opencode-plugin"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://soleur.ai"
|
|
38
|
+
}
|