@soleur/opencode 0.0.0-stage → 3.354.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.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 +660 -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 +29 -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 +361 -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 +171 -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 +818 -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 +411 -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 +509 -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 +115 -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 +165 -0
- package/scripts/sync-opencode-adapter.ts +498 -0
- package/scripts/sync-pr-behind.sh +647 -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 +67 -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 +143 -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 +120 -0
- package/skills/fix-issue/references/exclude-label-jq-snippet.md +97 -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 +670 -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 +331 -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 +141 -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 +1620 -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-evidence-comment.md +36 -0
- package/skills/review/references/review-todo-structure.md +165 -0
- package/skills/review/references/risk-tier-and-fix-rounds.md +97 -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 +3023 -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/cleanup-merged-archival.md +39 -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/delegated-act-authoring-form.md +7 -0
- package/skills/ship/references/detached-battery-verdict.md +13 -0
- package/skills/ship/references/epic-close-sweep.md +62 -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 +179 -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/verification-scaffold/SKILL.md +73 -0
- package/skills/verification-scaffold/references/gitleaks.toml.template +13 -0
- package/skills/verification-scaffold/references/guardrail-audit.md +156 -0
- package/skills/verification-scaffold/references/guards/block-stash-hook.sh.template +72 -0
- package/skills/verification-scaffold/references/guards/commit-on-main-hook.sh.template +82 -0
- package/skills/verification-scaffold/references/guards/orphan-test-check.sh.template +102 -0
- package/skills/verification-scaffold/references/guards/precommit-guard.sh.template +115 -0
- package/skills/verification-scaffold/references/guards/secret-scan-hook.sh.template +176 -0
- package/skills/verification-scaffold/references/guards/verification-gates.yml.template +49 -0
- package/skills/verification-scaffold/references/guards/wrapper-boundary.sh.template +47 -0
- package/skills/verification-scaffold/references/guards.tsv +21 -0
- package/skills/verification-scaffold/references/verification-readme.template +55 -0
- package/skills/verification-scaffold/scripts/verification-scaffold.sh +785 -0
- package/skills/verification-scaffold/test/bite-proof.test.sh +159 -0
- package/skills/verification-scaffold/test/generator.test.sh +319 -0
- package/skills/verification-scaffold/test/manifest.test.sh +144 -0
- package/skills/work/SKILL.md +1480 -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,528 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# plugin-version.sh — resolve the installed and latest Soleur plugin version.
|
|
3
|
+
#
|
|
4
|
+
# Shared by the SessionStart banner (hooks/version-banner.sh), /soleur:version and
|
|
5
|
+
# /soleur:help, so all three agree. Output is key=value lines, one shape for callers
|
|
6
|
+
# and tests. Never reports a version it did not read; always exits 0 (fail open).
|
|
7
|
+
#
|
|
8
|
+
# Modes (one required):
|
|
9
|
+
# --installed source=manifest|commit|checkout|unknown|none, version=, commit=, marketplace=
|
|
10
|
+
# --cached-latest --installed keys + cache_dir= + the cached latest release; NO network
|
|
11
|
+
# --latest [--refresh] latest release tag; uses a fresh cache unless --refresh
|
|
12
|
+
# --compare [--refresh] --installed + --latest + relation=older|current|unknown
|
|
13
|
+
# --cmp A B semver order of two X.Y.Z strings: older|same|newer
|
|
14
|
+
#
|
|
15
|
+
# Installed identity precedence: manifest top-level `.version` (X.Y.Z) -> basename of the
|
|
16
|
+
# plugin root when it is a commit-hash cache dir -> the HEAD commit of the local git checkout
|
|
17
|
+
# the plugin is loaded from in place (source=checkout) -> unknown. A manifest with no `version`
|
|
18
|
+
# key is the normal published shape (ADR-182 D1), so the commit hash is the usual answer.
|
|
19
|
+
#
|
|
20
|
+
# source=checkout: a local-Folder marketplace (or --plugin-dir) loads the plugin from
|
|
21
|
+
# <top>/plugins/soleur, which has neither a manifest version nor a commit-hash directory name.
|
|
22
|
+
# The identity is then <top>'s HEAD commit, read with PLAIN FILE READS ONLY (HEAD -> a loose
|
|
23
|
+
# ref or packed-refs; a detached HEAD holds the sha). Git is never run against that repository:
|
|
24
|
+
# its .git/config, hooks and attributes are untrusted project input. The lookup is anchored on
|
|
25
|
+
# the layout (the root ends in /plugins/soleur, <top>/.git exists, plugin.json exists), never a
|
|
26
|
+
# walk up to "the first .git", which would adopt a dotfiles repository above the project. Every
|
|
27
|
+
# file is size-gated by stat BEFORE it is read, HEAD and loose refs must be exactly one line,
|
|
28
|
+
# only a 40-hex commit is accepted, and only its first 12 hex are ever printed.
|
|
29
|
+
# The plugin root is CLAUDE_PLUGIN_ROOT, or, when that is unset (the Bash tool does not
|
|
30
|
+
# always export it), the directory one level above this script's directory.
|
|
31
|
+
#
|
|
32
|
+
# Latest release: highest tag matching ^v[0-9]+.[0-9]+.[0-9]+$ from `git ls-remote`
|
|
33
|
+
# against a fixed URL. The repo also publishes web-v*, vinngest-v*, telegram-v* and
|
|
34
|
+
# zot-image-* tags; the strict regex excludes them and prereleases.
|
|
35
|
+
#
|
|
36
|
+
# Relation for a commit-hash or local-checkout install uses one unauthenticated GitHub compare API call
|
|
37
|
+
# (ls-remote maps tags to commits but cannot order an installed commit against them).
|
|
38
|
+
# `diverged` or any failure is `unknown`, never "current". A relation answered from a
|
|
39
|
+
# stale cache or after a failed lookup is reported as unknown, except `older`, which
|
|
40
|
+
# stays true (releases only move forward).
|
|
41
|
+
#
|
|
42
|
+
# Network isolation: the lookups run from a neutral directory with the user's and the
|
|
43
|
+
# project's git configuration disabled and https as the only allowed protocol, so a
|
|
44
|
+
# `url.<base>.insteadOf` rewrite, `http.extraHeader`, `core.sshCommand` or a GIT_CONFIG_*
|
|
45
|
+
# variable cannot redirect the request, add credentials or run a command. Proxy
|
|
46
|
+
# environment variables still apply.
|
|
47
|
+
#
|
|
48
|
+
# Cache: one file per install, ${XDG_CACHE_HOME:-~/.cache}/soleur/latest-release.<id>
|
|
49
|
+
# (a relative XDG_CACHE_HOME is ignored, per the XDG spec). Treated as fresh for 24 h;
|
|
50
|
+
# the file stays on disk until replaced or deleted. A local checkout moves with every commit,
|
|
51
|
+
# so all checkouts share the one file latest-release.checkout (it records which commit it
|
|
52
|
+
# answers; another commit's entry reads as cache=missing and is simply replaced).
|
|
53
|
+
#
|
|
54
|
+
# Env: SOLEUR_FETCH_TIMEOUT (seconds per request, default 8, must be >= 1).
|
|
55
|
+
set -uo pipefail
|
|
56
|
+
|
|
57
|
+
REPO_URL="https://github.com/jikig-ai/soleur.git"
|
|
58
|
+
COMPARE_API="https://api.github.com/repos/jikig-ai/soleur/compare"
|
|
59
|
+
TAG_RE='^v[0-9]+\.[0-9]+\.[0-9]+$'
|
|
60
|
+
SEMVER_RE='^[0-9]+\.[0-9]+\.[0-9]+$'
|
|
61
|
+
DIR_RE='^[0-9a-f]{12}(-[0-9a-f]{8})?$'
|
|
62
|
+
SHA40_RE='^[0-9a-f]{40}$'
|
|
63
|
+
SHA12_RE='^[0-9a-f]{12}$'
|
|
64
|
+
SMALL_MAX=512 # bytes: HEAD, loose refs, .git pointer files, commondir
|
|
65
|
+
PACKED_MAX=4194304 # bytes: packed-refs (this repository's own is ~0.5 MB)
|
|
66
|
+
MANIFEST_MAX=65536 # bytes: plugin.json (the real one is ~1 KB; the no-jq awk scanner is superlinear, 100 KB cost seconds on mawk)
|
|
67
|
+
TTL_S=86400
|
|
68
|
+
# A failed compare is cached as fresh for only this long (the fetched stamp is backdated by
|
|
69
|
+
# TTL_S - FAIL_FRESH_S), so one rate-limit response does not silence the notice for a day.
|
|
70
|
+
FAIL_FRESH_S=3600
|
|
71
|
+
FETCH_TIMEOUT="${SOLEUR_FETCH_TIMEOUT:-8}"
|
|
72
|
+
if [[ "$FETCH_TIMEOUT" =~ ^[0-9]+$ ]] && (( 10#$FETCH_TIMEOUT >= 1 )); then
|
|
73
|
+
FETCH_TIMEOUT=$((10#$FETCH_TIMEOUT))
|
|
74
|
+
else
|
|
75
|
+
FETCH_TIMEOUT=8
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
TIMEOUT_CMD=""
|
|
79
|
+
if command -v timeout >/dev/null 2>&1; then TIMEOUT_CMD="timeout"
|
|
80
|
+
elif command -v gtimeout >/dev/null 2>&1; then TIMEOUT_CMD="gtimeout"; fi
|
|
81
|
+
|
|
82
|
+
# With timeout/gtimeout the command is bounded by it. Without them (stock macOS) a bash
|
|
83
|
+
# watchdog kills it after FETCH_TIMEOUT: http.lowSpeedLimit alone does not bound a stalled
|
|
84
|
+
# connect or TLS handshake. A killed command is reported as rc 124 (timeout).
|
|
85
|
+
run_bounded() {
|
|
86
|
+
if [[ -n "$TIMEOUT_CMD" ]]; then "$TIMEOUT_CMD" "$FETCH_TIMEOUT" "$@"; return; fi
|
|
87
|
+
local pid wd rc
|
|
88
|
+
"$@" &
|
|
89
|
+
pid=$!
|
|
90
|
+
( sleep "$FETCH_TIMEOUT"; pkill -P "$pid" 2>/dev/null; kill "$pid" 2>/dev/null ) </dev/null >/dev/null 2>&1 &
|
|
91
|
+
wd=$!
|
|
92
|
+
wait "$pid" 2>/dev/null
|
|
93
|
+
rc=$?
|
|
94
|
+
kill "$wd" 2>/dev/null
|
|
95
|
+
wait "$wd" 2>/dev/null
|
|
96
|
+
(( rc >= 128 )) && rc=124
|
|
97
|
+
return "$rc"
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# ---- semver ------------------------------------------------------------------
|
|
101
|
+
semver_cmp() { # A B (both X.Y.Z) -> older|same|newer; numeric, leading zeros are not octal
|
|
102
|
+
local IFS=. i p q
|
|
103
|
+
local -a x y
|
|
104
|
+
IFS=. read -r -a x <<< "$1"
|
|
105
|
+
IFS=. read -r -a y <<< "$2"
|
|
106
|
+
for i in 0 1 2; do
|
|
107
|
+
p=$((10#${x[i]:-0}))
|
|
108
|
+
q=$((10#${y[i]:-0}))
|
|
109
|
+
(( p < q )) && { echo older; return 0; }
|
|
110
|
+
(( p > q )) && { echo newer; return 0; }
|
|
111
|
+
done
|
|
112
|
+
echo same
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# ---- cache location ----------------------------------------------------------
|
|
116
|
+
CACHE_DIR=""
|
|
117
|
+
resolve_cache_dir() {
|
|
118
|
+
local base="${XDG_CACHE_HOME:-}"
|
|
119
|
+
case "$base" in /*) ;; *) base="" ;; esac # relative values must be ignored (XDG spec)
|
|
120
|
+
[[ "$base" == *[[:cntrl:]]* ]] && base="" # a newline would inject key=value lines downstream
|
|
121
|
+
if [[ -z "$base" ]]; then
|
|
122
|
+
case "${HOME:-}" in /*) ;; *) return 0 ;; esac
|
|
123
|
+
[[ "$HOME" == *[[:cntrl:]]* ]] && return 0
|
|
124
|
+
base="$HOME/.cache"
|
|
125
|
+
fi
|
|
126
|
+
CACHE_DIR="$base/soleur"
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
# ---- installed ---------------------------------------------------------------
|
|
130
|
+
INST_SOURCE=none INST_VERSION="" INST_COMMIT="" INST_ID="" INST_MARKETPLACE="" CACHE_FILE=""
|
|
131
|
+
|
|
132
|
+
# Top-level "version" string of a JSON file without jq: a small depth-aware scanner, so a
|
|
133
|
+
# nested {"mcpServers":{"x":{"version":"1.0.0"}}} is never mistaken for the plugin version.
|
|
134
|
+
manifest_version_nojq() {
|
|
135
|
+
awk '
|
|
136
|
+
{ buf = buf $0 "\n" }
|
|
137
|
+
END {
|
|
138
|
+
n = length(buf); depth = 0; i = 1; want = 0
|
|
139
|
+
while (i <= n) {
|
|
140
|
+
c = substr(buf, i, 1)
|
|
141
|
+
if (c == "\"") {
|
|
142
|
+
j = i + 1; s = ""
|
|
143
|
+
while (j <= n) {
|
|
144
|
+
d = substr(buf, j, 1)
|
|
145
|
+
if (d == "\\") { s = s substr(buf, j, 2); j += 2; continue }
|
|
146
|
+
if (d == "\"") break
|
|
147
|
+
s = s d; j++
|
|
148
|
+
}
|
|
149
|
+
i = j + 1
|
|
150
|
+
if (want) { if (depth == 1) { print s; exit } want = 0; continue }
|
|
151
|
+
k = i
|
|
152
|
+
while (k <= n && substr(buf, k, 1) ~ /[ \t\r\n]/) k++
|
|
153
|
+
if (substr(buf, k, 1) == ":" && depth == 1 && s == "version") want = 1
|
|
154
|
+
continue
|
|
155
|
+
}
|
|
156
|
+
if (c == "{" || c == "[") depth++
|
|
157
|
+
else if (c == "}" || c == "]") depth--
|
|
158
|
+
else if (want && c !~ /[ \t\r\n:]/) want = 0
|
|
159
|
+
i++
|
|
160
|
+
}
|
|
161
|
+
}' "$1" 2>/dev/null
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
read_manifest_version() {
|
|
165
|
+
local f="$1" v="" n
|
|
166
|
+
# A FIFO or a /dev/zero symlink here would stall jq/awk for the whole hook budget.
|
|
167
|
+
[[ -f "$f" && -r "$f" ]] || return 0
|
|
168
|
+
n="$(file_size "$f")" || return 0
|
|
169
|
+
(( n <= MANIFEST_MAX )) || return 0
|
|
170
|
+
if command -v jq >/dev/null 2>&1; then
|
|
171
|
+
v="$(jq -r '.version // empty' "$f" 2>/dev/null)" || v=""
|
|
172
|
+
else
|
|
173
|
+
v="$(manifest_version_nojq "$f")"
|
|
174
|
+
fi
|
|
175
|
+
printf '%s' "$v"
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
# ---- local checkout (source=checkout): plain file reads, never git ---------------------
|
|
179
|
+
# These and the manifest read are the only readers of repository bytes. Each checks regular-file-ness
|
|
180
|
+
# AND a stat size before it reads (a FIFO or device would hang an open; a sparse multi-GiB HEAD of
|
|
181
|
+
# NULs took 38 s through `read -n 512` alone), and nothing is executed, sourced or evaluated.
|
|
182
|
+
CK_VAL=""
|
|
183
|
+
|
|
184
|
+
file_size() { # path -> byte count on stdout; nothing when it cannot be measured
|
|
185
|
+
local n
|
|
186
|
+
n="$(stat -L -c %s -- "$1" 2>/dev/null || stat -L -f %z -- "$1" 2>/dev/null)" || return 1
|
|
187
|
+
[[ "$n" =~ ^[0-9]+$ ]] || return 1
|
|
188
|
+
printf '%s' "$n"
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
read_small() { # path -> CK_VAL = the file's single line (no newline); 1 when absent, irregular, oversize or not exactly one line
|
|
192
|
+
local f="$1" n line="" rc=0 got LC_ALL=C # bytes, not characters: a non-ASCII name must not change the verdict
|
|
193
|
+
CK_VAL=""
|
|
194
|
+
[[ -f "$f" && -r "$f" ]] || return 1
|
|
195
|
+
n="$(file_size "$f")" || return 1
|
|
196
|
+
(( n >= 1 && n <= SMALL_MAX )) || return 1
|
|
197
|
+
{ IFS= read -r -n "$SMALL_MAX" line < "$f"; } 2>/dev/null || rc=$?
|
|
198
|
+
# What was consumed must be exactly what the file holds. `read` silently drops NUL bytes and
|
|
199
|
+
# stops at the first newline, so a NUL-spliced or multi-line file consumes fewer bytes than
|
|
200
|
+
# its size and is refused instead of printing an identity from a string that is not its
|
|
201
|
+
# bytes. LC_ALL=C makes ${#line} count bytes in every locale, so a non-ASCII branch or path
|
|
202
|
+
# resolves the same under C and UTF-8 (a character count would silently drop the banner).
|
|
203
|
+
got=${#line}
|
|
204
|
+
if (( rc == 0 && got < SMALL_MAX )); then got=$((got + 1)); fi # the newline `read` consumed
|
|
205
|
+
(( got == n )) || return 1
|
|
206
|
+
CK_VAL="$line"
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
valid_ref_name() { # refs/heads/<name> -> 0 when it is a plausible git branch ref, else 1 (deny-list, git check-ref-format style)
|
|
210
|
+
local r="$1" rest LC_ALL=C # the bracket classes below must mean the same thing in every locale
|
|
211
|
+
case "$r" in refs/heads/?*) ;; *) return 1 ;; esac
|
|
212
|
+
rest="${r#refs/heads/}"
|
|
213
|
+
case "$rest" in
|
|
214
|
+
*[[:cntrl:][:space:]~^:?*\[\\]*|*..*|*//*|*@\{*|/*|*/|.*|*/.*|*.|*.lock|*.lock/*|@) return 1 ;;
|
|
215
|
+
esac
|
|
216
|
+
return 0
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
packed_ref_sha() { # commondir ref -> CK_VAL = sha for the exact ref in packed-refs
|
|
220
|
+
local f="$1/packed-refs" n
|
|
221
|
+
CK_VAL=""
|
|
222
|
+
[[ -f "$f" && -r "$f" ]] || return 1
|
|
223
|
+
n="$(file_size "$f")" || return 1
|
|
224
|
+
(( n >= 1 && n <= PACKED_MAX )) || return 1
|
|
225
|
+
# A peel line (`^sha`) has one field, so it never matches; a first field starting with `#` is skipped;
|
|
226
|
+
# a record over 1 KiB (a real entry is ~40 + a ref name <= ~500) is skipped before awk splits it, and
|
|
227
|
+
# whatever the first match holds must still pass the 40-hex test below, so a corrupt line yields
|
|
228
|
+
# `unknown` or a sha the repository's own bytes name, never invented bytes. LC_ALL=C makes length()
|
|
229
|
+
# count bytes on every awk.
|
|
230
|
+
CK_VAL="$(SOLEUR_REF="$2" LC_ALL=C awk '
|
|
231
|
+
length($0) < 1024 && $1 !~ /^#/ && $2 == ENVIRON["SOLEUR_REF"] { print $1; exit }' "$f" 2>/dev/null)"
|
|
232
|
+
[[ "$CK_VAL" =~ $SHA40_RE ]]
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
resolve_checkout_commit() { # absolute plugin root -> CK_VAL = 40-hex HEAD commit, else 1
|
|
236
|
+
local root="${1%/}" top gd="" common head ref
|
|
237
|
+
CK_VAL=""
|
|
238
|
+
case "$root" in /*) ;; *) return 1 ;; esac
|
|
239
|
+
# Physical path first: a plugin root that is a symlink into another checkout must read THAT
|
|
240
|
+
# checkout's HEAD, not the HEAD of the repository that merely holds the link.
|
|
241
|
+
root="$(cd -P -- "$root" 2>/dev/null && pwd -P)" || return 1
|
|
242
|
+
case "$root" in */plugins/soleur) ;; *) return 1 ;; esac
|
|
243
|
+
top="${root%/plugins/soleur}"
|
|
244
|
+
[[ -n "$top" ]] || return 1
|
|
245
|
+
[[ -f "$root/.claude-plugin/plugin.json" ]] || return 1
|
|
246
|
+
# <top>/.git is a directory (clone or bare layout) or a file `gitdir: <path>` (linked worktree).
|
|
247
|
+
if [[ -d "$top/.git" ]]; then
|
|
248
|
+
gd="$top/.git"
|
|
249
|
+
elif [[ -f "$top/.git" ]]; then
|
|
250
|
+
read_small "$top/.git" || return 1
|
|
251
|
+
case "$CK_VAL" in gitdir:\ ?*) gd="${CK_VAL#gitdir: }" ;; *) return 1 ;; esac
|
|
252
|
+
case "$gd" in /*) ;; *) gd="$top/$gd" ;; esac
|
|
253
|
+
[[ -d "$gd" ]] || return 1
|
|
254
|
+
else
|
|
255
|
+
return 1
|
|
256
|
+
fi
|
|
257
|
+
common="$gd"
|
|
258
|
+
if [[ -f "$gd/commondir" ]]; then
|
|
259
|
+
read_small "$gd/commondir" || return 1
|
|
260
|
+
case "$CK_VAL" in /*) common="$CK_VAL" ;; *) common="$gd/$CK_VAL" ;; esac
|
|
261
|
+
[[ -d "$common" ]] || return 1
|
|
262
|
+
fi
|
|
263
|
+
read_small "$gd/HEAD" || return 1
|
|
264
|
+
head="$CK_VAL"
|
|
265
|
+
if [[ "$head" =~ $SHA40_RE ]]; then CK_VAL="$head"; return 0; fi # detached HEAD
|
|
266
|
+
case "$head" in "ref: "?*) ref="${head#ref: }" ;; *) return 1 ;; esac
|
|
267
|
+
valid_ref_name "$ref" || return 1
|
|
268
|
+
# A loose ref that exists must be valid; it never falls through to a stale packed entry.
|
|
269
|
+
if [[ -e "$common/$ref" || -L "$common/$ref" ]]; then
|
|
270
|
+
read_small "$common/$ref" || return 1
|
|
271
|
+
[[ "$CK_VAL" =~ $SHA40_RE ]] || return 1
|
|
272
|
+
return 0
|
|
273
|
+
fi
|
|
274
|
+
packed_ref_sha "$common" "$ref" || return 1
|
|
275
|
+
return 0
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
resolve_installed() {
|
|
279
|
+
local root="${CLAUDE_PLUGIN_ROOT:-}" v base parent
|
|
280
|
+
if [[ -z "$root" ]]; then
|
|
281
|
+
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." 2>/dev/null && pwd)" || root=""
|
|
282
|
+
fi
|
|
283
|
+
resolve_cache_dir
|
|
284
|
+
if [[ -z "$root" || ! -d "$root" ]]; then INST_SOURCE=none; return 0; fi
|
|
285
|
+
# .../plugins/cache/<marketplace>/soleur/<id> -> marketplace (selects the right update command)
|
|
286
|
+
root="${root%/}"
|
|
287
|
+
parent="$(dirname "$root")"
|
|
288
|
+
if [[ "$(basename "$parent")" == soleur && "$(basename "$(dirname "$(dirname "$parent")")")" == cache ]]; then
|
|
289
|
+
base="$(basename "$(dirname "$parent")")"
|
|
290
|
+
[[ "$base" =~ ^[A-Za-z0-9._-]+$ ]] && INST_MARKETPLACE="$base"
|
|
291
|
+
fi
|
|
292
|
+
v="$(read_manifest_version "$root/.claude-plugin/plugin.json")"
|
|
293
|
+
if [[ "$v" =~ $SEMVER_RE ]]; then
|
|
294
|
+
INST_SOURCE=manifest INST_VERSION="$v" INST_ID="$v"
|
|
295
|
+
else
|
|
296
|
+
base="$(basename "$root")"
|
|
297
|
+
if [[ "$base" =~ $DIR_RE ]]; then
|
|
298
|
+
INST_SOURCE=commit INST_COMMIT="${base:0:12}" INST_ID="${base:0:12}"
|
|
299
|
+
elif resolve_checkout_commit "$root"; then
|
|
300
|
+
INST_SOURCE=checkout INST_COMMIT="${CK_VAL:0:12}" INST_ID="${CK_VAL:0:12}"
|
|
301
|
+
else
|
|
302
|
+
INST_SOURCE=unknown
|
|
303
|
+
fi
|
|
304
|
+
fi
|
|
305
|
+
if [[ -n "$INST_ID" && -n "$CACHE_DIR" ]]; then
|
|
306
|
+
if [[ "$INST_SOURCE" == checkout ]]; then
|
|
307
|
+
CACHE_FILE="$CACHE_DIR/latest-release.checkout" # one file for every commit of a moving checkout
|
|
308
|
+
else
|
|
309
|
+
CACHE_FILE="$CACHE_DIR/latest-release.$INST_ID"
|
|
310
|
+
fi
|
|
311
|
+
fi
|
|
312
|
+
return 0
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
print_installed() {
|
|
316
|
+
printf 'source=%s\n' "$INST_SOURCE"
|
|
317
|
+
[[ -n "$INST_VERSION" ]] && printf 'version=%s\n' "$INST_VERSION"
|
|
318
|
+
[[ -n "$INST_COMMIT" ]] && printf 'commit=%s\n' "$INST_COMMIT"
|
|
319
|
+
[[ -n "$INST_MARKETPLACE" ]] && printf 'marketplace=%s\n' "$INST_MARKETPLACE"
|
|
320
|
+
return 0
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
# ---- cache -------------------------------------------------------------------
|
|
324
|
+
C_TAG="" C_SHA="" C_FETCHED="" C_REL="" C_REASON="" CACHE_STATE=missing
|
|
325
|
+
|
|
326
|
+
reset_cache_vars() { C_TAG="" C_SHA="" C_FETCHED="" C_REL="" C_REASON="" CACHE_STATE=missing; }
|
|
327
|
+
|
|
328
|
+
load_cache() {
|
|
329
|
+
reset_cache_vars
|
|
330
|
+
[[ -n "$CACHE_FILE" && -f "$CACHE_FILE" ]] || return 0
|
|
331
|
+
# Same trust rule as write_cache: never read a cache from a directory we do not own.
|
|
332
|
+
[[ -O "$CACHE_DIR" && ! -L "$CACHE_DIR" ]] || return 0
|
|
333
|
+
local line key val rel_for="" complete="" now age mtime
|
|
334
|
+
while IFS= read -r line; do
|
|
335
|
+
key="${line%%=*}" val="${line#*=}"
|
|
336
|
+
case "$key" in
|
|
337
|
+
tag) C_TAG="$val" ;; sha) C_SHA="$val" ;; fetched) C_FETCHED="$val" ;;
|
|
338
|
+
relation) C_REL="$val" ;; relation_for) rel_for="$val" ;; reason) C_REASON="$val" ;;
|
|
339
|
+
complete) complete="$val" ;;
|
|
340
|
+
esac
|
|
341
|
+
done < "$CACHE_FILE" 2>/dev/null
|
|
342
|
+
# A truncated write loses the trailing `complete=1`, so it reads as corrupt, never as a
|
|
343
|
+
# fresh "unknown" that would silence the notice for a day.
|
|
344
|
+
# The one latest-release.checkout file answers a single commit at a time: an entry written for
|
|
345
|
+
# another commit is not corruption (and must not be reported as such), it is just not this
|
|
346
|
+
# commit's answer, so it reads as missing and the opt-in refresh replaces it.
|
|
347
|
+
if [[ "$INST_SOURCE" == checkout && "$complete" == 1 && "$rel_for" != "$INST_ID" && "$rel_for" =~ $SHA12_RE ]]; then
|
|
348
|
+
reset_cache_vars; CACHE_STATE=missing
|
|
349
|
+
return 0
|
|
350
|
+
fi
|
|
351
|
+
if [[ "$complete" != 1 || "$rel_for" != "$INST_ID" || ! "$C_TAG" =~ $TAG_RE || ! "$C_FETCHED" =~ ^[1-9][0-9]{0,11}$ ]]; then
|
|
352
|
+
reset_cache_vars; CACHE_STATE=corrupt
|
|
353
|
+
return 0
|
|
354
|
+
fi
|
|
355
|
+
[[ "$C_SHA" =~ $SHA40_RE ]] || C_SHA=""
|
|
356
|
+
case "$C_REL" in older|current|unknown) ;; *) C_REL="" ;; esac
|
|
357
|
+
[[ "$C_REASON" =~ ^[a-z-]{0,40}$ ]] || C_REASON=""
|
|
358
|
+
now="$(date +%s)"
|
|
359
|
+
age=$(( now - C_FETCHED ))
|
|
360
|
+
# A future-dated cache (clock change, hand edit) counts as stale, not fresh forever.
|
|
361
|
+
if (( age < 0 || age >= TTL_S )); then CACHE_STATE=stale; else CACHE_STATE=fresh; fi
|
|
362
|
+
mtime="$(stat -c %Y "$CACHE_FILE" 2>/dev/null || stat -f %m "$CACHE_FILE" 2>/dev/null || echo 0)"
|
|
363
|
+
if [[ "$mtime" =~ ^[0-9]+$ ]] && (( mtime > now + 60 )); then CACHE_STATE=stale; fi
|
|
364
|
+
return 0
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
write_cache() { # tag sha relation reason fetched
|
|
368
|
+
[[ -n "$CACHE_FILE" && -n "$CACHE_DIR" ]] || return 0
|
|
369
|
+
( umask 077; mkdir -p "$CACHE_DIR" ) 2>/dev/null || return 0
|
|
370
|
+
# Never write into a directory we do not own or that is a symlink (shared XDG dirs).
|
|
371
|
+
[[ -d "$CACHE_DIR" && -O "$CACHE_DIR" && ! -L "$CACHE_DIR" ]] || return 0
|
|
372
|
+
chmod 700 "$CACHE_DIR" 2>/dev/null || true
|
|
373
|
+
local tmp="$CACHE_FILE.$$"
|
|
374
|
+
rm -f "$tmp" 2>/dev/null
|
|
375
|
+
# noclobber makes `>` fail on an existing path (including a planted symlink).
|
|
376
|
+
if ( set -C; umask 077
|
|
377
|
+
{ printf 'tag=%s\nsha=%s\nfetched=%s\n' "$1" "$2" "$5"
|
|
378
|
+
printf 'relation=%s\nrelation_for=%s\nreason=%s\ncomplete=1\n' "$3" "$INST_ID" "$4"; } > "$tmp" ) 2>/dev/null; then
|
|
379
|
+
mv -f "$tmp" "$CACHE_FILE" 2>/dev/null || rm -f "$tmp" 2>/dev/null
|
|
380
|
+
else
|
|
381
|
+
rm -f "$tmp" 2>/dev/null
|
|
382
|
+
fi
|
|
383
|
+
return 0
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
# ---- latest release ----------------------------------------------------------
|
|
387
|
+
FETCH_STATUS="" F_TAG="" F_SHA=""
|
|
388
|
+
|
|
389
|
+
fetch_latest() {
|
|
390
|
+
FETCH_STATUS="" F_TAG="" F_SHA=""
|
|
391
|
+
if ! command -v git >/dev/null 2>&1; then FETCH_STATUS=no-git; return 0; fi
|
|
392
|
+
local out rc
|
|
393
|
+
out="$(
|
|
394
|
+
cd / 2>/dev/null
|
|
395
|
+
unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_CONFIG_COUNT GIT_CONFIG_PARAMETERS \
|
|
396
|
+
GIT_SSH GIT_SSH_COMMAND GIT_PROXY_COMMAND GIT_ASKPASS SSH_ASKPASS GIT_EXEC_PATH
|
|
397
|
+
export GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null GIT_CONFIG_NOSYSTEM=1 \
|
|
398
|
+
GIT_TERMINAL_PROMPT=0 HOME=/nonexistent XDG_CONFIG_HOME=/nonexistent
|
|
399
|
+
run_bounded git -c protocol.allow=never -c protocol.https.allow=always \
|
|
400
|
+
-c http.lowSpeedLimit=1 -c "http.lowSpeedTime=$FETCH_TIMEOUT" \
|
|
401
|
+
ls-remote --tags "$REPO_URL" 'refs/tags/v[0-9]*' 2>/dev/null
|
|
402
|
+
)"
|
|
403
|
+
rc=$?
|
|
404
|
+
if (( rc == 124 )); then FETCH_STATUS=timeout; return 0; fi
|
|
405
|
+
if (( rc != 0 )); then FETCH_STATUS=offline; return 0; fi
|
|
406
|
+
# Highest strict vX.Y.Z by numeric key (no `sort -V`: not portable). Components wider than
|
|
407
|
+
# four digits are skipped so the key stays exact in awk's double arithmetic.
|
|
408
|
+
F_TAG="$(printf '%s\n' "$out" | awk -F'\t' '
|
|
409
|
+
NF >= 2 {
|
|
410
|
+
t = $2; sub(/^refs\/tags\//, "", t); sub(/\^\{\}$/, "", t)
|
|
411
|
+
if (t ~ /^v[0-9]+\.[0-9]+\.[0-9]+$/) {
|
|
412
|
+
split(substr(t, 2), a, ".")
|
|
413
|
+
if (length(a[1]) <= 4 && length(a[2]) <= 4 && length(a[3]) <= 4)
|
|
414
|
+
printf "%.0f %s\n", (a[1] * 10000 + a[2]) * 10000 + a[3], t
|
|
415
|
+
}
|
|
416
|
+
}' | sort -n | tail -1 | cut -d' ' -f2)"
|
|
417
|
+
if [[ -z "$F_TAG" ]]; then FETCH_STATUS=no-tags; return 0; fi
|
|
418
|
+
# The peeled line (^{}) carries the commit an annotated tag points at.
|
|
419
|
+
F_SHA="$(printf '%s\n' "$out" | awk -F'\t' -v t="refs/tags/$F_TAG" \
|
|
420
|
+
'$2==t"^{}"{p=$1} $2==t{s=$1} END{print (p!="" ? p : s)}')"
|
|
421
|
+
[[ "$F_SHA" =~ $SHA40_RE ]] || F_SHA=""
|
|
422
|
+
FETCH_STATUS=ok
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
REL="" REL_REASON=""
|
|
426
|
+
|
|
427
|
+
compute_relation() { # needs INST_*, F_TAG, F_SHA
|
|
428
|
+
REL=unknown REL_REASON=""
|
|
429
|
+
case "$INST_SOURCE" in
|
|
430
|
+
manifest)
|
|
431
|
+
REL="$(semver_cmp "$INST_VERSION" "${F_TAG#v}")"
|
|
432
|
+
[[ "$REL" == older ]] || REL=current
|
|
433
|
+
;;
|
|
434
|
+
commit|checkout)
|
|
435
|
+
# The tag's own commit is the installed one: nothing to compare.
|
|
436
|
+
if [[ -n "$F_SHA" && "${F_SHA:0:12}" == "$INST_COMMIT" ]]; then REL=current; return 0; fi
|
|
437
|
+
# Re-validated at the sink: only 12 hex ever reaches the URL, whatever the source said.
|
|
438
|
+
[[ "$INST_COMMIT" =~ $SHA12_RE ]] || { REL_REASON=installed-unknown; return 0; }
|
|
439
|
+
if ! command -v curl >/dev/null 2>&1; then REL_REASON=no-curl; return 0; fi
|
|
440
|
+
local body status
|
|
441
|
+
# page=2000 keeps the body ~20 KB instead of ~1.3 MB (the file list is paged); the
|
|
442
|
+
# top-level status is unaffected. -q ignores any ~/.curlrc.
|
|
443
|
+
body="$(cd / 2>/dev/null; run_bounded curl -q -fsS --proto =https --compressed -m "$FETCH_TIMEOUT" \
|
|
444
|
+
-H 'Accept: application/vnd.github+json' \
|
|
445
|
+
"$COMPARE_API/$INST_COMMIT...$F_TAG?per_page=1&page=2000" 2>/dev/null)" || { REL_REASON=compare-failed; return 0; }
|
|
446
|
+
# First "status" is the top-level one; later ones belong to the per-file entries.
|
|
447
|
+
status="$(printf '%s' "$body" | grep -o '"status"[[:space:]]*:[[:space:]]*"[a-z]*"' | head -1 | sed 's/.*"\([a-z]*\)"$/\1/')"
|
|
448
|
+
case "$status" in
|
|
449
|
+
ahead) REL=older ;;
|
|
450
|
+
identical|behind) REL=current ;;
|
|
451
|
+
diverged) REL_REASON=diverged ;;
|
|
452
|
+
*) REL_REASON=compare-unparseable ;;
|
|
453
|
+
esac
|
|
454
|
+
;;
|
|
455
|
+
*) REL_REASON=installed-unknown ;;
|
|
456
|
+
esac
|
|
457
|
+
return 0
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
# refresh_latest: fetch, compare, cache. Honors a fresh cache unless $1 == force.
|
|
461
|
+
refresh_latest() {
|
|
462
|
+
local fetched
|
|
463
|
+
load_cache
|
|
464
|
+
if [[ "${1:-}" != force && "$CACHE_STATE" == fresh ]]; then FETCH_STATUS=cache-fresh; return 0; fi
|
|
465
|
+
fetch_latest
|
|
466
|
+
if [[ "$FETCH_STATUS" == ok ]]; then
|
|
467
|
+
compute_relation
|
|
468
|
+
fetched="$(date +%s)"
|
|
469
|
+
case "$REL_REASON" in
|
|
470
|
+
compare-failed|no-curl|compare-unparseable) fetched=$(( fetched - TTL_S + FAIL_FRESH_S )) ;;
|
|
471
|
+
esac
|
|
472
|
+
# Nothing to key a cache on without a recognisable install: answer, but do not persist.
|
|
473
|
+
[[ -n "$INST_ID" ]] && write_cache "$F_TAG" "$F_SHA" "$REL" "$REL_REASON" "$fetched"
|
|
474
|
+
C_TAG="$F_TAG" C_SHA="$F_SHA" C_REL="$REL" C_REASON="$REL_REASON" C_FETCHED="$fetched" CACHE_STATE=fresh
|
|
475
|
+
fi
|
|
476
|
+
return 0
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
print_latest() {
|
|
480
|
+
local rel="$C_REL" reason="$C_REASON" unreliable=0
|
|
481
|
+
printf 'cache=%s\n' "$CACHE_STATE"
|
|
482
|
+
[[ -n "$CACHE_DIR" ]] && printf 'cache_dir=%s\n' "$CACHE_DIR"
|
|
483
|
+
[[ -n "$FETCH_STATUS" ]] && printf 'latest_status=%s\n' "$FETCH_STATUS"
|
|
484
|
+
[[ -n "$C_TAG" ]] || return 0
|
|
485
|
+
printf 'latest=%s\n' "$C_TAG"
|
|
486
|
+
[[ -n "$C_SHA" ]] && printf 'latest_commit=%s\n' "$C_SHA"
|
|
487
|
+
if [[ -z "$INST_ID" ]]; then
|
|
488
|
+
rel=unknown reason=installed-unknown
|
|
489
|
+
else
|
|
490
|
+
[[ "$CACHE_STATE" != fresh ]] && unreliable=1
|
|
491
|
+
case "$FETCH_STATUS" in offline|timeout|no-git|no-tags) unreliable=1 ;; esac
|
|
492
|
+
# `older` stays true when old (releases only move forward); `current` does not. An
|
|
493
|
+
# unknown keeps the reason it was first answered with (diverged, compare-failed, ...).
|
|
494
|
+
if (( unreliable )) && [[ "$rel" == current ]]; then rel=unknown reason=stale-cache; fi
|
|
495
|
+
[[ -n "$rel" ]] || { rel=unknown; reason=cache-invalid; }
|
|
496
|
+
fi
|
|
497
|
+
printf 'relation=%s\n' "$rel"
|
|
498
|
+
[[ -n "$reason" ]] && printf 'reason=%s\n' "$reason"
|
|
499
|
+
return 0
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
main() {
|
|
503
|
+
local mode="" force="" a1="" a2=""
|
|
504
|
+
while (( $# )); do
|
|
505
|
+
case "$1" in
|
|
506
|
+
--installed|--cached-latest|--latest|--compare) mode="$1" ;;
|
|
507
|
+
--cmp) mode="$1"; a1="${2:-}"; a2="${3:-}"; shift 2 2>/dev/null || shift $# ;;
|
|
508
|
+
--refresh) force=force ;;
|
|
509
|
+
esac
|
|
510
|
+
shift 2>/dev/null || break
|
|
511
|
+
done
|
|
512
|
+
if [[ "$mode" == --cmp ]]; then
|
|
513
|
+
if [[ "$a1" =~ $SEMVER_RE && "$a2" =~ $SEMVER_RE ]]; then semver_cmp "$a1" "$a2"; else echo unknown; fi
|
|
514
|
+
return 0
|
|
515
|
+
fi
|
|
516
|
+
resolve_installed
|
|
517
|
+
case "$mode" in
|
|
518
|
+
--installed) print_installed ;;
|
|
519
|
+
--cached-latest) print_installed; load_cache; print_latest ;;
|
|
520
|
+
--latest) refresh_latest "$force"; print_latest ;;
|
|
521
|
+
--compare) print_installed; refresh_latest "$force"; print_latest ;;
|
|
522
|
+
*) echo "usage: plugin-version.sh --installed|--cached-latest|--latest [--refresh]|--compare [--refresh]|--cmp A B" >&2 ;;
|
|
523
|
+
esac
|
|
524
|
+
return 0
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
main "$@"
|
|
528
|
+
exit 0
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# precommit-guard.sh — refuse `git commit` on main/master, without hook execution.
|
|
3
|
+
#
|
|
4
|
+
# Canonical source for the commit-on-main check (Soleur Cloud Mode, FR5).
|
|
5
|
+
# Plugin command hooks are documented cloud-capable for most events, but a
|
|
6
|
+
# skill cannot rely on hook execution in a not-local session — and user repos
|
|
7
|
+
# consuming via requiredPlugins have no .claude/hooks at all. work/ship/one-shot
|
|
8
|
+
# invoke this script directly so the refusal is structural in both worlds.
|
|
9
|
+
#
|
|
10
|
+
# Scope: commit-on-main ONLY. The DONE-marker stop-gate is not extractable —
|
|
11
|
+
# it reads hook-stdin transcript data a standalone script cannot see; it stays
|
|
12
|
+
# prose + the plugin Stop hook.
|
|
13
|
+
#
|
|
14
|
+
# Self-contained by design: no jq, no .claude/hooks/lib vendoring (those paths
|
|
15
|
+
# resolve relative to the repo, which is wrong when this script runs from the
|
|
16
|
+
# plugin install cache), no emit_incident — callers log their own incidents.
|
|
17
|
+
# ONE sibling dependency: scripts/lib/wrapper-boundary.sh ships beside this
|
|
18
|
+
# script in the plugin cache, so $(dirname)/lib/… resolves in both contexts
|
|
19
|
+
# (#10248 — the canonical wrapper-prefix grammar the COMMIT_RE below consumes).
|
|
20
|
+
#
|
|
21
|
+
# Usage:
|
|
22
|
+
# precommit-guard.sh "COMMAND" check a shell command string
|
|
23
|
+
# precommit-guard.sh --cwd DIR also check DIR's branch (a `cd DIR &&`
|
|
24
|
+
# or `git -C DIR` inside COMMAND wins)
|
|
25
|
+
#
|
|
26
|
+
# Exit 0 = allowed (not a commit, or not on main/master).
|
|
27
|
+
# Exit 1 = refused — reason on stderr.
|
|
28
|
+
# Exit 2 = usage error.
|
|
29
|
+
|
|
30
|
+
set -euo pipefail
|
|
31
|
+
|
|
32
|
+
COMMAND=""
|
|
33
|
+
CWD=""
|
|
34
|
+
while [[ $# -gt 0 ]]; do
|
|
35
|
+
case "$1" in
|
|
36
|
+
--cwd) CWD="${2:-}"; shift 2 ;;
|
|
37
|
+
-*) echo "precommit-guard.sh: unknown flag: $1" >&2; exit 2 ;;
|
|
38
|
+
*) COMMAND="$1"; shift ;;
|
|
39
|
+
esac
|
|
40
|
+
done
|
|
41
|
+
|
|
42
|
+
# Detection is per pipeline segment: a `git commit` can hide anywhere in a
|
|
43
|
+
# chain — `git add && git commit`, `cd repo; git commit`, `printf msg |
|
|
44
|
+
# git commit -F -`, `LEFTHOOK=0 git commit`. Split COMMAND on the chain
|
|
45
|
+
# operators (&&, ||, ;, |, newline), then judge each segment.
|
|
46
|
+
#
|
|
47
|
+
# Known lexical limits (documented, not silently missed): subshell/eval forms
|
|
48
|
+
# like `bash -c 'git commit'`, `$(git commit)`, `( git commit )`, quoted
|
|
49
|
+
# `-C`/`cd` paths containing spaces, `git -c <cfg> commit` side effects beyond
|
|
50
|
+
# detection, and commits created without `git commit` (merge/pull/cherry-pick/
|
|
51
|
+
# rebase/continue) are out of this guard's declared scope — commit-on-main ONLY.
|
|
52
|
+
# Opaque string payloads (`rtk run -c '…'`, `rtk summary --shell '…'`) join that
|
|
53
|
+
# same declared class — the boundary fragment deliberately excludes the
|
|
54
|
+
# -c/--command/--shell atoms so they cannot match here.
|
|
55
|
+
_PC_GUARD_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
56
|
+
unset SOLEUR_ENV_ASN_RE SOLEUR_LAUNCHER_RE SOLEUR_RTK_RE SOLEUR_BOUNDARY_PFX SOLEUR_BOUNDARY_PFX_LOADED
|
|
57
|
+
if [[ -f "$_PC_GUARD_DIR/lib/wrapper-boundary.sh" ]]; then
|
|
58
|
+
# shellcheck source=/dev/null
|
|
59
|
+
source "$_PC_GUARD_DIR/lib/wrapper-boundary.sh" 2>/dev/null || true
|
|
60
|
+
fi
|
|
61
|
+
if [[ "${SOLEUR_BOUNDARY_PFX_LOADED:-0}" != 1 ]]; then
|
|
62
|
+
unset SOLEUR_ENV_ASN_RE SOLEUR_LAUNCHER_RE SOLEUR_RTK_RE SOLEUR_BOUNDARY_PFX
|
|
63
|
+
echo "precommit-guard.sh: wrapper-boundary.sh unavailable at $_PC_GUARD_DIR/lib — commit gate runs pre-#10248 matching" >&2
|
|
64
|
+
fi
|
|
65
|
+
unset _PC_GUARD_DIR
|
|
66
|
+
# #10248: the shared fragment replaces the inline env-asn/launcher alternation —
|
|
67
|
+
# one canonical atom set for every boundary-anchored gate. The :- fallback is
|
|
68
|
+
# the PRE-FIX atom set (env + launcher) — a superset of this file's prior
|
|
69
|
+
# env*/launcher?/env* sandwich, which is the safe direction for a deny gate.
|
|
70
|
+
COMMIT_RE='^[[:space:]]*('"${SOLEUR_BOUNDARY_PFX:-([A-Za-z_][A-Za-z_0-9]*=[^[:space:]]+|sudo|command|nice|env|xargs)}"'[[:space:]]+)*git([[:space:]]+(-C[[:space:]]+[^[:space:]]+|-c[[:space:]]+[^[:space:]]+|--git-dir=[^[:space:]]+|--git-dir[[:space:]]+[^[:space:]]+|-[A-Za-z]))*[[:space:]]+commit([[:space:]]|$)'
|
|
71
|
+
|
|
72
|
+
last_cd=""
|
|
73
|
+
while IFS= read -r seg; do
|
|
74
|
+
# Track the dir the chain has cd'd into — it applies to later segments.
|
|
75
|
+
cd_hit="$(grep -oE '(^|[[:space:]])cd[[:space:]]+[^[:space:]]+' <<<"$seg" | tail -n 1 | sed -E 's/.*cd[[:space:]]+//' || true)"
|
|
76
|
+
[[ -n "$cd_hit" ]] && last_cd="$cd_hit"
|
|
77
|
+
|
|
78
|
+
grep -qE "$COMMIT_RE" <<<"$seg" || continue
|
|
79
|
+
|
|
80
|
+
# Resolve the repo THIS segment commits into. Priority: the -C / --git-dir
|
|
81
|
+
# attached to the commit's own git invocation, then a GIT_DIR env-assignment
|
|
82
|
+
# prefix (LEFTHOOK=0-style prefixes are the reason env-assignments are scanned
|
|
83
|
+
# at all — dropping GIT_DIR would resolve the wrong repo); then the chain's
|
|
84
|
+
# most recent cd; then --cwd; then ambient $PWD.
|
|
85
|
+
target="" git_dir=""
|
|
86
|
+
if grep -qoE -- '--git-dir[=[:space:]][^[:space:]]+' <<<"$seg"; then
|
|
87
|
+
git_dir="$(grep -oE -- '--git-dir[=[:space:]][^[:space:]]+' <<<"$seg" | tail -n 1 | sed -E 's/^--git-dir[=[:space:]]+//' || true)"
|
|
88
|
+
elif grep -qoE -- '(^|[[:space:]])GIT_DIR=[^[:space:]]+' <<<"$seg"; then
|
|
89
|
+
git_dir="$(grep -oE -- '(^|[[:space:]])GIT_DIR=[^[:space:]]+' <<<"$seg" | tail -n 1 | sed -E 's/.*GIT_DIR=//' || true)"
|
|
90
|
+
else
|
|
91
|
+
git_c="$(grep -oE -- '-C[[:space:]]+[^[:space:]]+' <<<"$seg" | tail -n 1 | sed -E 's/^-C[[:space:]]+//' || true)"
|
|
92
|
+
[[ -n "$git_c" ]] && target="$git_c"
|
|
93
|
+
fi
|
|
94
|
+
if [[ -z "$target" && -z "$git_dir" ]]; then
|
|
95
|
+
for cand in "$last_cd" "$CWD" "$PWD"; do
|
|
96
|
+
[[ -n "$cand" && -d "$cand" ]] && target="$cand" && break
|
|
97
|
+
done
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
if [[ -n "$git_dir" ]]; then
|
|
101
|
+
BRANCH="$(git --git-dir="$git_dir" rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
|
|
102
|
+
elif [[ -n "$target" && -d "$target" ]]; then
|
|
103
|
+
BRANCH="$(git -C "$target" rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
|
|
104
|
+
else
|
|
105
|
+
continue # nowhere to resolve — nothing to refuse on
|
|
106
|
+
fi
|
|
107
|
+
# The alternation is the stamped default-branch set — soleur:verification-scaffold
|
|
108
|
+
# emits this file with `main|master` substituted for the target's resolved default.
|
|
109
|
+
if [[ "$BRANCH" =~ ^(main|master)$ ]]; then
|
|
110
|
+
printf 'BLOCKED: Committing directly to %s is not allowed. Create a feature branch first.\n' "$BRANCH" >&2
|
|
111
|
+
exit 1
|
|
112
|
+
fi
|
|
113
|
+
done < <(printf '%s\n' "$COMMAND" | sed -E 's/&&|\|\||[;|]/\n/g')
|
|
114
|
+
|
|
115
|
+
exit 0
|