@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,363 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ci-head-verdict.sh -- the ONE resolver every reader of a PR head's CI state goes through (ADR-276 S3, #9728).
|
|
3
|
+
#
|
|
4
|
+
# ci-head-verdict.sh verdict <pr> [--repo OWNER/REPO]
|
|
5
|
+
# ci-head-verdict.sh wait-ready-run <pr> --before-count K [--timeout SEC] [--repo OWNER/REPO]
|
|
6
|
+
# ci-head-verdict.sh ready-count <pr> [--repo OWNER/REPO]
|
|
7
|
+
#
|
|
8
|
+
# WHY. With CI_DRAFT_LIGHT on, a draft PR's `test` context is RED BY DESIGN ("draft: full battery owed at ready",
|
|
9
|
+
# Option R). A reader that sees that red row on a PR that has since been marked ready misreads it as a failure
|
|
10
|
+
# (monitor, the Phase 7 poll, drain-prs triage, admin-merge --wait), and one that sees it with no ready run ever
|
|
11
|
+
# created misreads the silence as "still running" forever. The decision is TIME-BASED, so no reader needs a
|
|
12
|
+
# light-run detector: only a `ci.yml` pull_request run created at or after the PR's latest ready event speaks for a
|
|
13
|
+
# non-draft head. A run created at or after T was triggered by the ready event or a later push; the ci.yml
|
|
14
|
+
# `draft-light` step reads the PR LIVE and runs full for ACTION == ready_for_review and for a non-draft PR.
|
|
15
|
+
#
|
|
16
|
+
# APPLICABILITY. The mechanism exists only in a repo whose default-branch `.github/workflows/ci.yml` carries the
|
|
17
|
+
# `draft-light` job (the key may carry a trailing comment or quotes; a 200 body without a top-level `jobs:` key is an API
|
|
18
|
+
# error, never "not applicable"). Any other repo (a customer repo the plugin is installed in) never produces a ready run, so
|
|
19
|
+
# `verdict` answers n/a (reason no-draft-light) and `wait-ready-run` answers ok (reason not-applicable): its ship and
|
|
20
|
+
# merge flow is the one it had without this script, plus one timeline read and one contents read. A 404 on that file is "not applicable"; any other
|
|
21
|
+
# read failure is an API error (exit 3), never a guess.
|
|
22
|
+
#
|
|
23
|
+
# `verdict` prints exactly one marker as the last stdout line and exits 0 (a decision was made) or 3 (it could not be):
|
|
24
|
+
# SOLEUR_CI_HEAD_VERDICT state=<n/a|full-decided|pending-full|no-run|stalled|awaiting-approval> pr=<N> sha=<H> run=<id|none> reason=<token>
|
|
25
|
+
# The state set is CLOSED. On exit 3 the marker is `state=error` (reason names the cause): a state OUTSIDE the closed
|
|
26
|
+
# set, so a reader that whitelists the six states ignores it and keeps its own reading (a real red `test` stays red).
|
|
27
|
+
# Never answer a read failure with a member of the closed set: that would let an API hiccup read as a decision.
|
|
28
|
+
# Order of evaluation:
|
|
29
|
+
# 0. the repo does not carry the mechanism (see APPLICABILITY) -> n/a
|
|
30
|
+
# 1. no ready event ever (never a draft: bot-opened PRs with synthetic rows and no pull_request run), or the PR is a
|
|
31
|
+
# draft NOW -> n/a
|
|
32
|
+
# 2. the newest `test` check run (github-actions app) at H is completed + success -> full-decided (reason
|
|
33
|
+
# green-test, regardless of T: under Option R a green `test` is never a light result)
|
|
34
|
+
# 3. list `workflows/ci.yml/runs?event=pull_request&head_sha=H` (NEVER a run's pull_requests[], empty for ~92% of
|
|
35
|
+
# runs) and keep runs created at or after T; T is the latest ReadyForReviewEvent's server time. No skew
|
|
36
|
+
# allowance: the ready run was measured 2 to 3 s AFTER T (S3 gate 4), and an allowance would adopt a DRAFT push's
|
|
37
|
+
# light run created just before the ready call as "the ready run"
|
|
38
|
+
# 4. the newest kept run decides: not completed -> pending-full; completed success|failure|timed_out ->
|
|
39
|
+
# full-decided (its own rows are authoritative, a failure is never hidden as PENDING); action_required ->
|
|
40
|
+
# awaiting-approval; cancelled|skipped|stale|neutral|startup_failure|anything else -> no-run (fail closed);
|
|
41
|
+
# no kept run -> no-run
|
|
42
|
+
# 5. (a conflicting PR, mergeable_state dirty, with no run stays no-run reason=conflicting: GitHub builds no merge ref
|
|
43
|
+
# for it, so no run can ever appear and an undo/ready would not help)
|
|
44
|
+
# pending-full and no-run become `stalled` once more than N=120 minutes have passed since T (above the declared
|
|
45
|
+
# 73-minute path plus a ~14-minute p90 queue wait; a run still in flight at N is not a healthy slow run)
|
|
46
|
+
# `run=` is the DECIDING run: a reader judging `test` must use that run's rows. A newer `test` row that belongs to a
|
|
47
|
+
# different run (a manual re-run of a pre-T run) is stale; the row's run id is the `/actions/runs/<id>/` segment of
|
|
48
|
+
# its details_url. Every time comes from the SERVER (the PR read's Date header, the timeline, the runs API), never
|
|
49
|
+
# the local clock.
|
|
50
|
+
#
|
|
51
|
+
# `wait-ready-run` is the arm-after-ready gate. The caller reads K with `ready-count` BEFORE `gh pr ready`; the wait
|
|
52
|
+
# polls (every 10 s plus the calls themselves, budget --timeout, default 300: the real elapsed time is up to ~365 s, so
|
|
53
|
+
# give the calling tool a timeout of 420 s)
|
|
54
|
+
# until the PR's ReadyForReviewEvent count exceeds K AND a live read says it is not a draft (read-after-write lag
|
|
55
|
+
# guard: the previous event is never taken as T), takes the newest event's server time as T, then polls for a
|
|
56
|
+
# pull_request run at H created at or after T. Last stdout line:
|
|
57
|
+
# SOLEUR_CI_WAIT_READY_RUN result=<ok|fail> pr=<N> sha=<H|unknown> run=<id|none> reason=<run-created|not-applicable|no-ready-event|no-run|awaiting-approval|api-error>
|
|
58
|
+
# Exit 0 on ok, 1 on fail (FAIL CLOSED: the caller must NOT run `gh pr merge --auto`), 2 usage, 3 when the LAST poll
|
|
59
|
+
# could not read (api-error: the ready state is unknown, so re-run `verdict`; do NOT `gh pr ready --undo`).
|
|
60
|
+
#
|
|
61
|
+
# `ready-count` prints the number of ReadyForReviewEvents on the PR (the filtered nodes, NOT the timeline totalCount,
|
|
62
|
+
# which counts every event type) and exits 3 without a number when it cannot be counted.
|
|
63
|
+
#
|
|
64
|
+
# EXIT CODES: 0 decided/ok | 1 wait failed | 2 usage | 3 gh/jq/API error (verdict prints state=error reason=<cause>).
|
|
65
|
+
# PORTABILITY: bash, gh and jq only (jq does the time arithmetic; no GNU `date -d`), so it runs on a stock macOS host.
|
|
66
|
+
# TEST SEAMS: CI_HEAD_VERDICT_NOW (ISO-8601 UTC, replaces the server clock), CI_HEAD_VERDICT_POLL_SECONDS (default 10,
|
|
67
|
+
# the sleep between wait polls; the poll BUDGET is always counted in 10-second units).
|
|
68
|
+
#
|
|
69
|
+
# Every `gh pr ready` caller must use a non-GITHUB_TOKEN identity: measured on the S3 probe, GITHUB_TOKEN cannot
|
|
70
|
+
# ready a PR at all (markPullRequestReadyForReview: Resource not accessible by integration), so it can never produce
|
|
71
|
+
# the ready event or the ready run this script waits for.
|
|
72
|
+
set -uo pipefail
|
|
73
|
+
|
|
74
|
+
readonly MARKER="SOLEUR_CI_HEAD_VERDICT"
|
|
75
|
+
readonly WAIT_MARKER="SOLEUR_CI_WAIT_READY_RUN"
|
|
76
|
+
STALL_MINUTES=120
|
|
77
|
+
# shellcheck disable=SC2016 # GraphQL variables ($owner...) are not shell expansions
|
|
78
|
+
readonly READY_QUERY='query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){pullRequest(number:$number){timelineItems(last: 100, itemTypes: [READY_FOR_REVIEW_EVENT]){pageInfo{hasPreviousPage} nodes{... on ReadyForReviewEvent{createdAt}}}}}}'
|
|
79
|
+
|
|
80
|
+
usage() {
|
|
81
|
+
cat <<'EOF'
|
|
82
|
+
usage: ci-head-verdict.sh verdict <pr> [--repo OWNER/REPO]
|
|
83
|
+
ci-head-verdict.sh wait-ready-run <pr> --before-count K [--timeout SEC] [--repo OWNER/REPO]
|
|
84
|
+
ci-head-verdict.sh ready-count <pr> [--repo OWNER/REPO]
|
|
85
|
+
|
|
86
|
+
verdict: last stdout line
|
|
87
|
+
SOLEUR_CI_HEAD_VERDICT state=<n/a|full-decided|pending-full|no-run|stalled|awaiting-approval> pr=<N> sha=<H> run=<id|none> reason=<token>
|
|
88
|
+
(exit 3: state=error, outside that set)
|
|
89
|
+
wait-ready-run: last stdout line
|
|
90
|
+
SOLEUR_CI_WAIT_READY_RUN result=<ok|fail> pr=<N> sha=<H|unknown> run=<id|none> reason=<run-created|not-applicable|no-ready-event|no-run|awaiting-approval|api-error>
|
|
91
|
+
exit 0 ok | 1 wait failed (do NOT arm auto-merge) | 2 usage | 3 gh/jq/API error (ready state unknown: re-run verdict)
|
|
92
|
+
arm order: K=$(ready-count PR) && gh pr ready PR && wait-ready-run PR --before-count "$K"; arm only on exit 0
|
|
93
|
+
EOF
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
usage_error() { echo "ci-head-verdict: $1" >&2; usage >&2; exit 2; }
|
|
97
|
+
|
|
98
|
+
# ── args ──────────────────────────────────────────────────────────────────────────────────────
|
|
99
|
+
if [[ "${1-}" == "--help" || "${1-}" == "-h" ]]; then usage; exit 0; fi
|
|
100
|
+
CMD="${1-}"
|
|
101
|
+
case "$CMD" in verdict|wait-ready-run|ready-count) shift ;; *) usage_error "unknown or missing subcommand '${CMD}'" ;; esac
|
|
102
|
+
PR="${1-}"
|
|
103
|
+
[[ "$PR" =~ ^[0-9]+$ ]] || usage_error "<pr> must be a number"
|
|
104
|
+
shift
|
|
105
|
+
BEFORE=""; TIMEOUT=300
|
|
106
|
+
while (( $# > 0 )); do
|
|
107
|
+
case "$1" in
|
|
108
|
+
--repo)
|
|
109
|
+
[[ "${2-}" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*/[A-Za-z0-9._-]+$ ]] || usage_error "--repo must be OWNER/REPO (not a URL)"
|
|
110
|
+
export GH_REPO="$2"; shift 2 ;;
|
|
111
|
+
--before-count)
|
|
112
|
+
[[ "$CMD" == wait-ready-run && "${2-}" =~ ^[0-9]+$ ]] || usage_error "--before-count K (an integer) is for wait-ready-run only"
|
|
113
|
+
BEFORE=$((10#$2)); shift 2 ;;
|
|
114
|
+
--timeout)
|
|
115
|
+
# shellcheck disable=SC2015 # A && B || usage_error is the guard idiom here
|
|
116
|
+
[[ "$CMD" == wait-ready-run && "${2-}" =~ ^[0-9]+$ ]] && (( 10#$2 > 0 )) || usage_error "--timeout takes a positive integer and is for wait-ready-run only"
|
|
117
|
+
TIMEOUT=$((10#$2)); shift 2 ;;
|
|
118
|
+
*) usage_error "unknown argument '$1'" ;;
|
|
119
|
+
esac
|
|
120
|
+
done
|
|
121
|
+
[[ "$CMD" != wait-ready-run || -n "$BEFORE" ]] || usage_error "wait-ready-run needs --before-count K (read it with ready-count BEFORE gh pr ready)"
|
|
122
|
+
POLL_SECONDS="${CI_HEAD_VERDICT_POLL_SECONDS:-10}"
|
|
123
|
+
[[ "$POLL_SECONDS" =~ ^[0-9]+$ ]] || usage_error "CI_HEAD_VERDICT_POLL_SECONDS must be ^[0-9]+\$"
|
|
124
|
+
|
|
125
|
+
SHA_OUT="unknown"
|
|
126
|
+
# fail_api <message> [reason]: a read the resolver could not make. `verdict` prints a marker whose state is `error` (NOT a
|
|
127
|
+
# member of the closed set: a reader that whitelists the six states then keeps its own reading, so a real red `test`
|
|
128
|
+
# is never softened by an API hiccup) and exits 3; ready-count prints no number.
|
|
129
|
+
fail_api() {
|
|
130
|
+
local reason="${2:-api-error}"
|
|
131
|
+
echo "ci-head-verdict: $1" >&2
|
|
132
|
+
if [[ "$CMD" == verdict ]]; then
|
|
133
|
+
printf '%s state=error pr=%s sha=%s run=none reason=%s\n' "$MARKER" "$PR" "$SHA_OUT" "$reason"
|
|
134
|
+
elif [[ "$CMD" == wait-ready-run ]]; then
|
|
135
|
+
printf '%s result=fail pr=%s sha=unknown run=none reason=api-error\n' "$WAIT_MARKER" "$PR"
|
|
136
|
+
fi
|
|
137
|
+
exit 3
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
for bin in gh jq; do
|
|
141
|
+
command -v "$bin" >/dev/null 2>&1 || fail_api "$bin not found on PATH" missing-tool
|
|
142
|
+
done
|
|
143
|
+
WORK="$(mktemp -d)" || fail_api "mktemp failed" mktemp
|
|
144
|
+
trap 'rm -rf "$WORK"' EXIT
|
|
145
|
+
|
|
146
|
+
ERRMSG=""
|
|
147
|
+
# ── reads. Each returns 0 on a parsed answer, 1 with ERRMSG set otherwise. ─────────────────────
|
|
148
|
+
PR_DRAFT=""; PR_SHA=""; PR_MSTATE=""; SERVER_DATE=""
|
|
149
|
+
read_pr() {
|
|
150
|
+
gh api -i "repos/{owner}/{repo}/pulls/$PR" > "$WORK/pr.http" 2> "$WORK/err" \
|
|
151
|
+
|| { ERRMSG="reading PR $PR failed: $(head -c 200 "$WORK/err" | tr '\n' ' ')"; return 1; }
|
|
152
|
+
awk 'b { print; next } /^\r?$/ { b = 1 }' "$WORK/pr.http" > "$WORK/pr.json"
|
|
153
|
+
SERVER_DATE="$(awk 'b { exit } /^\r?$/ { b = 1; next } tolower($0) ~ /^date:/ { sub(/^[Dd][Aa][Tt][Ee]:[ \t]*/, ""); sub(/\r$/, ""); print; exit }' "$WORK/pr.http")"
|
|
154
|
+
jq -e 'type == "object" and (.draft | type) == "boolean" and (.head.sha | type) == "string" and (.head.sha | test("^[0-9a-f]{40}$"))' \
|
|
155
|
+
"$WORK/pr.json" >/dev/null 2>&1 || { ERRMSG="unparseable PR $PR body"; return 1; }
|
|
156
|
+
PR_DRAFT="$(jq -r '.draft' "$WORK/pr.json")"
|
|
157
|
+
PR_SHA="$(jq -r '.head.sha' "$WORK/pr.json")"
|
|
158
|
+
PR_MSTATE="$(jq -r '(.mergeable_state // "") | if type == "string" then . else "" end' "$WORK/pr.json")"
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
READY_COUNT=0; READY_T=""; READY_TRUNC="false"
|
|
162
|
+
read_ready() {
|
|
163
|
+
gh api graphql -F owner='{owner}' -F name='{repo}' -F number="$PR" -f query="$READY_QUERY" > "$WORK/ready.json" 2> "$WORK/err" \
|
|
164
|
+
|| { ERRMSG="reading the ready-event timeline of PR $PR failed: $(head -c 200 "$WORK/err" | tr '\n' ' ')"; return 1; }
|
|
165
|
+
jq -e '.data.repository.pullRequest.timelineItems
|
|
166
|
+
| (.nodes | type) == "array" and all(.nodes[]; (.createdAt | type) == "string") and (.pageInfo.hasPreviousPage | type) == "boolean"' \
|
|
167
|
+
"$WORK/ready.json" >/dev/null 2>&1 || { ERRMSG="unparseable ready-event timeline for PR $PR"; return 1; }
|
|
168
|
+
READY_COUNT="$(jq -r '.data.repository.pullRequest.timelineItems.nodes | length' "$WORK/ready.json")"
|
|
169
|
+
READY_T="$(jq -r '.data.repository.pullRequest.timelineItems.nodes | last | .createdAt // ""' "$WORK/ready.json")"
|
|
170
|
+
READY_TRUNC="$(jq -r '.data.repository.pullRequest.timelineItems.pageInfo.hasPreviousPage' "$WORK/ready.json")"
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
# The newest `test` check run (github-actions app) at <sha>: TEST_STATUS / TEST_CONCLUSION / TEST_RUN (id or "").
|
|
174
|
+
TEST_STATUS=""; TEST_CONCLUSION=""; TEST_RUN=""
|
|
175
|
+
read_test_row() {
|
|
176
|
+
gh api --paginate --slurp "repos/{owner}/{repo}/commits/$1/check-runs?check_name=test&per_page=100&filter=all" > "$WORK/checks.json" 2> "$WORK/err" \
|
|
177
|
+
|| { ERRMSG="reading check runs at $1 failed: $(head -c 200 "$WORK/err" | tr '\n' ' ')"; return 1; }
|
|
178
|
+
jq -e 'type == "array" and all(.[]; type == "object" and (.check_runs | type) == "array")' "$WORK/checks.json" >/dev/null 2>&1 \
|
|
179
|
+
|| { ERRMSG="unparseable check-runs response at $1"; return 1; }
|
|
180
|
+
jq -c --arg h "$1" '[.[].check_runs[] | select(.name == "test" and .app.id == 15368 and .head_sha == $h)]
|
|
181
|
+
| if length == 0 then null else max_by(.id | tonumber) end' "$WORK/checks.json" > "$WORK/testrow.json" \
|
|
182
|
+
|| { ERRMSG="unparseable check-runs response at $1"; return 1; }
|
|
183
|
+
TEST_STATUS="$(jq -r '.status // ""' "$WORK/testrow.json")"
|
|
184
|
+
TEST_CONCLUSION="$(jq -r '.conclusion // ""' "$WORK/testrow.json")"
|
|
185
|
+
TEST_RUN="$(jq -r '(.details_url // "") | capture("/actions/runs/(?<id>[0-9]+)(/|$)") | .id' "$WORK/testrow.json" 2>/dev/null || true)"
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
# The newest ci.yml pull_request run at <sha> created at or after <floor-epoch>: RUN_ID / RUN_STATUS / RUN_CONCLUSION
|
|
189
|
+
# (RUN_ID empty when none). Looked up by head_sha, never through a run's pull_requests[].
|
|
190
|
+
RUN_ID=""; RUN_STATUS=""; RUN_CONCLUSION=""
|
|
191
|
+
read_newest_run() { # <sha> <floor-epoch>
|
|
192
|
+
gh api --paginate --slurp "repos/{owner}/{repo}/actions/workflows/ci.yml/runs?event=pull_request&head_sha=$1&per_page=100" > "$WORK/runs.json" 2> "$WORK/err" \
|
|
193
|
+
|| { ERRMSG="listing ci.yml runs at $1 failed: $(head -c 200 "$WORK/err" | tr '\n' ' ')"; return 1; }
|
|
194
|
+
jq -e 'type == "array" and all(.[]; type == "object" and (.workflow_runs | type) == "array")' "$WORK/runs.json" >/dev/null 2>&1 \
|
|
195
|
+
|| { ERRMSG="unparseable ci.yml run list at $1"; return 1; }
|
|
196
|
+
jq -c --arg h "$1" --argjson floor "$2" '
|
|
197
|
+
[ .[] | .workflow_runs[]? | select(.head_sha == $h and .event == "pull_request")
|
|
198
|
+
| . + {ts: (.created_at | fromdateiso8601)} | select(.ts >= $floor) ]
|
|
199
|
+
| sort_by([.ts, .id]) | last // null' "$WORK/runs.json" > "$WORK/newest.json" \
|
|
200
|
+
|| { ERRMSG="unparseable ci.yml run list at $1"; return 1; }
|
|
201
|
+
RUN_ID="$(jq -r '(.id // "") | tostring' "$WORK/newest.json")"
|
|
202
|
+
[[ -z "$RUN_ID" || "$RUN_ID" =~ ^[0-9]+$ ]] || { ERRMSG="non-numeric run id in the ci.yml run list at $1"; return 1; }
|
|
203
|
+
RUN_STATUS="$(jq -r '.status // ""' "$WORK/newest.json")"
|
|
204
|
+
RUN_CONCLUSION="$(jq -r '.conclusion // ""' "$WORK/newest.json")"
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
# Does this repo carry the mechanism? True when the DEFAULT branch's ci.yml has a `draft-light` job. APPLICABLE is
|
|
208
|
+
# 1/0; a 404 (no ci.yml) is 0, any other failure is an error (ERRMSG set, return 1).
|
|
209
|
+
APPLICABLE=""
|
|
210
|
+
read_applicable() {
|
|
211
|
+
gh api -H 'Accept: application/vnd.github.raw+json' "repos/{owner}/{repo}/contents/.github/workflows/ci.yml" > "$WORK/ci.yml" 2> "$WORK/err" || {
|
|
212
|
+
if grep -qE 'HTTP 404' "$WORK/err"; then APPLICABLE=0; return 0; fi
|
|
213
|
+
ERRMSG="reading the default branch's ci.yml failed: $(head -c 200 "$WORK/err" | tr '\n' ' ')"; return 1
|
|
214
|
+
}
|
|
215
|
+
[[ -s "$WORK/ci.yml" ]] || { ERRMSG="empty ci.yml body"; return 1; }
|
|
216
|
+
# A 200 that is not a workflow file (an HTML error page, a truncated body) is an error, never "not applicable": that
|
|
217
|
+
# answer would switch the wait gate off. The job key may carry a trailing comment or quotes.
|
|
218
|
+
grep -qE '^jobs:' "$WORK/ci.yml" || { ERRMSG="the default branch's ci.yml body has no top-level jobs: key"; return 1; }
|
|
219
|
+
if grep -qE "^ ['\"]?draft-light['\"]?:[[:space:]]*(#.*)?$" "$WORK/ci.yml"; then APPLICABLE=1; else APPLICABLE=0; fi
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
# <status> <conclusion> -> "<state> <reason>" (the closed mapping of rule 4)
|
|
223
|
+
classify_run() {
|
|
224
|
+
case "$1" in
|
|
225
|
+
completed) : ;;
|
|
226
|
+
queued|in_progress|waiting|requested|pending) echo "pending-full run-in-progress"; return 0 ;;
|
|
227
|
+
*) echo "no-run run-unknown-status"; return 0 ;;
|
|
228
|
+
esac
|
|
229
|
+
case "$2" in
|
|
230
|
+
success) echo "full-decided run-success" ;;
|
|
231
|
+
failure) echo "full-decided run-failure" ;;
|
|
232
|
+
timed_out) echo "full-decided run-timed-out" ;;
|
|
233
|
+
action_required) echo "awaiting-approval run-action-required" ;;
|
|
234
|
+
cancelled|skipped|stale|neutral|startup_failure) echo "no-run run-${2//_/-}" ;;
|
|
235
|
+
*) echo "no-run run-unknown-conclusion" ;;
|
|
236
|
+
esac
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
# Epoch seconds from an ISO-8601 UTC time (2031-03-04T05:06:07Z) or an HTTP Date header (RFC 1123), via jq so the
|
|
240
|
+
# script runs without GNU `date -d`. Prints digits and returns 0, or returns 1.
|
|
241
|
+
epoch_of() {
|
|
242
|
+
local out
|
|
243
|
+
out="$(LC_ALL=C jq -rn --arg s "$1" 'if ($s | test("^[A-Za-z]{3}, ")) then ($s | strptime("%a, %d %b %Y %H:%M:%S GMT") | mktime) else ($s | fromdateiso8601) end' 2>/dev/null)" || return 1
|
|
244
|
+
[[ "$out" =~ ^[0-9]+$ ]] || return 1
|
|
245
|
+
printf '%s\n' "$out"
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
NOW_EPOCH=0
|
|
249
|
+
server_now() {
|
|
250
|
+
local raw="${CI_HEAD_VERDICT_NOW:-$SERVER_DATE}"
|
|
251
|
+
[[ -n "$raw" ]] || return 1
|
|
252
|
+
epoch_of "$raw"
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
emit() { # <state> <run|""> <reason>
|
|
256
|
+
printf '%s state=%s pr=%s sha=%s run=%s reason=%s\n' "$MARKER" "$1" "$PR" "$SHA_OUT" "${2:-none}" "$3"
|
|
257
|
+
exit 0
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
# ── verdict ───────────────────────────────────────────────────────────────────────────────────
|
|
261
|
+
cmd_verdict() {
|
|
262
|
+
local t_epoch st rs
|
|
263
|
+
read_pr || fail_api "$ERRMSG"
|
|
264
|
+
SHA_OUT="$PR_SHA"
|
|
265
|
+
NOW_EPOCH=$(server_now) || fail_api "no usable server time (Date header absent or unparseable)" no-server-time
|
|
266
|
+
read_ready || fail_api "$ERRMSG"
|
|
267
|
+
(( READY_COUNT > 0 )) || emit n/a "" never-ready
|
|
268
|
+
[[ "$PR_DRAFT" == true ]] && emit n/a "" draft
|
|
269
|
+
read_applicable || fail_api "$ERRMSG"
|
|
270
|
+
[[ "$APPLICABLE" == 1 ]] || emit n/a "" no-draft-light
|
|
271
|
+
t_epoch=$(epoch_of "$READY_T") || fail_api "unparseable ready-event time '$READY_T'"
|
|
272
|
+
|
|
273
|
+
read_test_row "$PR_SHA" || fail_api "$ERRMSG"
|
|
274
|
+
if [[ "$TEST_STATUS" == completed && "$TEST_CONCLUSION" == success ]]; then
|
|
275
|
+
emit full-decided "$TEST_RUN" green-test
|
|
276
|
+
fi
|
|
277
|
+
|
|
278
|
+
read_newest_run "$PR_SHA" "$t_epoch" || fail_api "$ERRMSG"
|
|
279
|
+
if [[ -z "$RUN_ID" ]]; then
|
|
280
|
+
st="no-run"; rs="no-run-after-ready"
|
|
281
|
+
else
|
|
282
|
+
read -r st rs <<<"$(classify_run "$RUN_STATUS" "$RUN_CONCLUSION")" || fail_api "run classification failed"
|
|
283
|
+
[[ -n "$st" ]] || fail_api "run classification failed"
|
|
284
|
+
fi
|
|
285
|
+
# A conflicting PR (mergeable_state dirty) gets NO pull_request run at all: GitHub cannot build the merge ref. That is
|
|
286
|
+
# the conflict's doing, not a lost ready run, and `stalled` would advise an undo/ready that cannot help: it stays no-run.
|
|
287
|
+
if [[ "$st" == no-run && "$rs" == no-run-after-ready && "$PR_MSTATE" == dirty ]]; then rs="conflicting"
|
|
288
|
+
elif [[ "$st" == pending-full || "$st" == no-run ]] && (( NOW_EPOCH - t_epoch > STALL_MINUTES * 60 )); then
|
|
289
|
+
st=stalled; rs="undecided-after-${STALL_MINUTES}m"
|
|
290
|
+
fi
|
|
291
|
+
emit "$st" "$RUN_ID" "$rs"
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
# ── ready-count ───────────────────────────────────────────────────────────────────────────────
|
|
295
|
+
cmd_ready_count() {
|
|
296
|
+
read_ready || fail_api "$ERRMSG"
|
|
297
|
+
[[ "$READY_TRUNC" != true ]] || fail_api "more ReadyForReviewEvents than one timeline page holds; cannot count" too-many-events
|
|
298
|
+
printf '%s\n' "$READY_COUNT"
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
# ── wait-ready-run ────────────────────────────────────────────────────────────────────────────
|
|
302
|
+
WAIT_REASON="no-ready-event"; WAIT_RUN=""; WAIT_SHA="unknown"; WAIT_API_ERR=0
|
|
303
|
+
# One poll. 0 = a ready run exists; 1 = keep waiting (WAIT_REASON says what is missing; WAIT_API_ERR=1 when a READ
|
|
304
|
+
# failed, which is not the same as "not there yet"); 2 = terminal failure.
|
|
305
|
+
wait_once() {
|
|
306
|
+
local t_epoch st rs
|
|
307
|
+
WAIT_REASON="no-ready-event"; WAIT_RUN=""; WAIT_API_ERR=1
|
|
308
|
+
read_pr || { echo "ci-head-verdict: $ERRMSG" >&2; return 1; }
|
|
309
|
+
WAIT_SHA="$PR_SHA"
|
|
310
|
+
read_ready || { echo "ci-head-verdict: $ERRMSG" >&2; return 1; }
|
|
311
|
+
[[ "$READY_TRUNC" != true ]] || { echo "ci-head-verdict: too many ready events to count" >&2; return 1; }
|
|
312
|
+
WAIT_API_ERR=0
|
|
313
|
+
if [[ "$READY_COUNT" -gt "$BEFORE" && "$PR_DRAFT" == false ]]; then
|
|
314
|
+
:
|
|
315
|
+
else
|
|
316
|
+
return 1
|
|
317
|
+
fi
|
|
318
|
+
t_epoch=$(epoch_of "$READY_T") || { echo "ci-head-verdict: unparseable ready-event time '$READY_T'" >&2; WAIT_API_ERR=1; return 1; }
|
|
319
|
+
WAIT_REASON="no-run"
|
|
320
|
+
read_newest_run "$PR_SHA" "$t_epoch" || { echo "ci-head-verdict: $ERRMSG" >&2; WAIT_API_ERR=1; return 1; }
|
|
321
|
+
[[ -n "$RUN_ID" ]] || return 1
|
|
322
|
+
WAIT_RUN="$RUN_ID"
|
|
323
|
+
read -r st rs <<<"$(classify_run "$RUN_STATUS" "$RUN_CONCLUSION")"
|
|
324
|
+
case "$st" in
|
|
325
|
+
pending-full|full-decided) WAIT_REASON="run-created"; return 0 ;;
|
|
326
|
+
awaiting-approval) WAIT_REASON="awaiting-approval"; return 2 ;;
|
|
327
|
+
*) return 1 ;;
|
|
328
|
+
esac
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
wait_marker() { # <ok|fail>
|
|
332
|
+
printf '%s result=%s pr=%s sha=%s run=%s reason=%s\n' "$WAIT_MARKER" "$1" "$PR" "$WAIT_SHA" "${WAIT_RUN:-none}" "$WAIT_REASON"
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
cmd_wait() {
|
|
336
|
+
local max=$(( (TIMEOUT + 9) / 10 )) poll rc prev=""
|
|
337
|
+
(( max >= 1 )) || max=1
|
|
338
|
+
# A repo without the mechanism has no ready run to wait for: arming is today's behaviour there.
|
|
339
|
+
if ! read_applicable; then echo "ci-head-verdict: $ERRMSG" >&2; WAIT_REASON="api-error"; wait_marker fail; exit 3; fi
|
|
340
|
+
if [[ "$APPLICABLE" != 1 ]]; then WAIT_REASON="not-applicable"; wait_marker ok; exit 0; fi
|
|
341
|
+
for (( poll = 1; poll <= max; poll++ )); do
|
|
342
|
+
wait_once; rc=$?
|
|
343
|
+
case "$rc" in
|
|
344
|
+
0) wait_marker ok; exit 0 ;;
|
|
345
|
+
2) wait_marker fail; exit 1 ;;
|
|
346
|
+
esac
|
|
347
|
+
if [[ "$WAIT_REASON" != "$prev" ]]; then
|
|
348
|
+
printf 'WAIT poll=%d/%d waiting-for=%s\n' "$poll" "$max" "$WAIT_REASON"
|
|
349
|
+
prev="$WAIT_REASON"
|
|
350
|
+
fi
|
|
351
|
+
(( poll < max )) && sleep "$POLL_SECONDS"
|
|
352
|
+
done
|
|
353
|
+
# The last poll could not READ: the ready state is unknown, which is not "no ready event / no run".
|
|
354
|
+
if (( WAIT_API_ERR == 1 )); then WAIT_REASON="api-error"; wait_marker fail; exit 3; fi
|
|
355
|
+
wait_marker fail
|
|
356
|
+
exit 1
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
case "$CMD" in
|
|
360
|
+
verdict) cmd_verdict ;;
|
|
361
|
+
ready-count) cmd_ready_count ;;
|
|
362
|
+
wait-ready-run) cmd_wait ;;
|
|
363
|
+
esac
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# cloud-detect.sh -- the ONE local-vs-cloud classifier for Devin sessions (TR1).
|
|
3
|
+
#
|
|
4
|
+
# Emits exactly one token on stdout:
|
|
5
|
+
# local -- positive this-host, plugin-sourced local-session evidence
|
|
6
|
+
# not-local:<reason> -- everything else; consumers MUST fail closed on it
|
|
7
|
+
#
|
|
8
|
+
# Reasons, in priority order (first match wins):
|
|
9
|
+
# sentinel-absent -- no .devin/soleur-local-session under the git root (or no git
|
|
10
|
+
# repo/git) on a box that IS Devin-marked (some DEVIN* var set)
|
|
11
|
+
# no-devin-env -- no sentinel AND no DEVIN / DEVIN_HOME / DEVIN_PROJECT_DIR /
|
|
12
|
+
# DEVIN_PLUGIN_ROOT / DEVIN_DIR set. This means "not a Devin
|
|
13
|
+
# session at all" — local Devin exec shells expose ZERO DEVIN*
|
|
14
|
+
# vars (probe 2026-09-15, both arms), so env cannot gate the
|
|
15
|
+
# `local` verdict; the sentinel carries it. Callers treat
|
|
16
|
+
# no-devin-env like `local` (a Claude Code session must not
|
|
17
|
+
# activate the cloud contract).
|
|
18
|
+
# malformed -- sentinel exists but is not a JSON object or lacks host/hook_source
|
|
19
|
+
# foreign-host -- sentinel host != `hostname` (committed sentinel; measured 2026-09-17:
|
|
20
|
+
# /handoff transfers committed content only, so a gitignored sentinel
|
|
21
|
+
# cannot travel via it — the arm remains forward-defense for any
|
|
22
|
+
# transport that does carry the file, and for user repos that commit it)
|
|
23
|
+
# non-plugin-source -- sentinel hook_source != "plugin" (repo-level SessionStart firing in
|
|
24
|
+
# cloud must never read as a local session)
|
|
25
|
+
# conflicting-evidence -- valid plugin-sourced, this-host sentinel on a box whose env
|
|
26
|
+
# marks it as a cloud VM (DEVIN_DIR / DEVIN_DISABLE_HISTEXPAND are
|
|
27
|
+
# measured cloud-only in exec shells). The upstream-convergence arm:
|
|
28
|
+
# if Cognition ships plugin-hook dispatch in cloud (#8160) before
|
|
29
|
+
# plugin subagents, the hook fires and writes a sentinel while the
|
|
30
|
+
# capability gap persists — that must NOT read as local.
|
|
31
|
+
#
|
|
32
|
+
# Exit status is ALWAYS 0 for a classification outcome: a classifier that errors
|
|
33
|
+
# fails OPEN at consumers, and fail-open is exactly the defect this script exists
|
|
34
|
+
# to kill. (Usage errors — unknown flags — exit 2; that is not a classification.)
|
|
35
|
+
#
|
|
36
|
+
# --banner: when classification is not-local, also emit a reason-aware capability
|
|
37
|
+
# banner to STDERR naming the absent surfaces (plugin subagents, SessionStart /
|
|
38
|
+
# SessionEnd hooks) and what still works (skills, AGENTS.md rules, MCP). Emits
|
|
39
|
+
# nothing extra when local. Callers are expected to gate on positive Devin
|
|
40
|
+
# identity before invoking --banner (the contract in devin/INSTRUCTIONS.md), so a
|
|
41
|
+
# Claude Code session never sees cloud banners.
|
|
42
|
+
#
|
|
43
|
+
# Sentinel shape (written by hooks/devin-session-start.sh):
|
|
44
|
+
# {"host":"<hostname>","ts":"<ISO8601 utc>","hook_source":"plugin"|"repo"}
|
|
45
|
+
#
|
|
46
|
+
# Deliberately jq- and python3-free: both may be absent on a minimal cloud VM, so
|
|
47
|
+
# the flat JSON is parsed with grep/sed, whitespace-tolerant and fail-closed.
|
|
48
|
+
|
|
49
|
+
set -euo pipefail
|
|
50
|
+
|
|
51
|
+
BANNER=0
|
|
52
|
+
for arg in "$@"; do
|
|
53
|
+
case "$arg" in
|
|
54
|
+
--banner) BANNER=1 ;;
|
|
55
|
+
*)
|
|
56
|
+
echo "cloud-detect.sh: unknown argument: $arg" >&2
|
|
57
|
+
echo "usage: cloud-detect.sh [--banner]" >&2
|
|
58
|
+
exit 2
|
|
59
|
+
;;
|
|
60
|
+
esac
|
|
61
|
+
done
|
|
62
|
+
|
|
63
|
+
# Extract a top-level string field from the flat sentinel JSON — whitespace
|
|
64
|
+
# tolerant, no jq/python3 dependency. Prints the value (possibly empty); never
|
|
65
|
+
# fails, because an unreadable/unparseable file must classify malformed, not die.
|
|
66
|
+
sentinel_field() {
|
|
67
|
+
local field="$1" file="$2"
|
|
68
|
+
grep -oE "\"${field}\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" "$file" 2>/dev/null \
|
|
69
|
+
| head -n 1 \
|
|
70
|
+
| sed -E 's/^[^:]*:[[:space:]]*"//; s/"[[:space:]]*$//' \
|
|
71
|
+
|| true
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Any DEVIN* marker present — used only to pick the reason when the sentinel is
|
|
75
|
+
# missing; it never gates `local` (local exec shells expose no DEVIN* vars).
|
|
76
|
+
devin_env_present() {
|
|
77
|
+
[[ -n "${DEVIN:-}" || -n "${DEVIN_HOME:-}" || -n "${DEVIN_PROJECT_DIR:-}" || -n "${DEVIN_PLUGIN_ROOT:-}" || -n "${DEVIN_DIR:-}" ]]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
classify() {
|
|
81
|
+
# 1. Sentinel under the git root; outside a repo (or without git) there is
|
|
82
|
+
# nowhere for it to live. Absent sentinel: Devin-marked box → sentinel-absent;
|
|
83
|
+
# no Devin env at all → no-devin-env (likely not a Devin session — callers
|
|
84
|
+
# proceed normally).
|
|
85
|
+
local root sentinel
|
|
86
|
+
root="$(git rev-parse --show-toplevel 2>/dev/null)" || root=""
|
|
87
|
+
sentinel="${root:+$root/.devin/soleur-local-session}"
|
|
88
|
+
if [[ -z "$root" || ! -f "$sentinel" ]]; then
|
|
89
|
+
if devin_env_present; then
|
|
90
|
+
echo "not-local:sentinel-absent"
|
|
91
|
+
else
|
|
92
|
+
echo "not-local:no-devin-env"
|
|
93
|
+
fi
|
|
94
|
+
return
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# 2. Content-bearing sentinel: must look like a JSON object and carry both
|
|
98
|
+
# required fields, else malformed.
|
|
99
|
+
local content host hook_source
|
|
100
|
+
content="$(cat "$sentinel" 2>/dev/null || true)"
|
|
101
|
+
if [[ ! "$content" =~ ^[[:space:]]*\{ ]] || [[ ! "$content" =~ \}[[:space:]]*$ ]]; then
|
|
102
|
+
echo "not-local:malformed"
|
|
103
|
+
return
|
|
104
|
+
fi
|
|
105
|
+
host="$(sentinel_field host "$sentinel")"
|
|
106
|
+
hook_source="$(sentinel_field hook_source "$sentinel")"
|
|
107
|
+
if [[ -z "$host" || -z "$hook_source" ]]; then
|
|
108
|
+
echo "not-local:malformed"
|
|
109
|
+
return
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# 3. Host must match — a sentinel that travelled is not evidence of THIS
|
|
113
|
+
# host's session (measured 2026-09-17: /handoff carries committed content
|
|
114
|
+
# only, so gitignored files do not move via it; the live cause is a
|
|
115
|
+
# commit in a user repo that doesn't gitignore .devin/, plus any future
|
|
116
|
+
# transport that does carry the file). Same `hostname` invocation as the
|
|
117
|
+
# write side.
|
|
118
|
+
local this_host
|
|
119
|
+
this_host="$(hostname 2>/dev/null || true)"
|
|
120
|
+
if [[ -z "$this_host" || "$host" != "$this_host" ]]; then
|
|
121
|
+
echo "not-local:foreign-host"
|
|
122
|
+
return
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
# 4. Source must be the plugin registration — a repo-level SessionStart hook
|
|
126
|
+
# firing on a cloud VM (the undocumented arm the probe checks) writes a
|
|
127
|
+
# matching-host sentinel, which must NOT read as local.
|
|
128
|
+
if [[ "$hook_source" != "plugin" ]]; then
|
|
129
|
+
echo "not-local:non-plugin-source"
|
|
130
|
+
return
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
# 5. Conflicting evidence: everything above attests "plugin SessionStart fired
|
|
134
|
+
# on this host" — but a cloud-only env marker is present. If Cognition ships
|
|
135
|
+
# plugin-hook dispatch in cloud (#8160) before plugin subagents, this arm is
|
|
136
|
+
# what keeps the gap fail-closed instead of silently reading as local.
|
|
137
|
+
if [[ -n "${DEVIN_DIR:-}" || -n "${DEVIN_DISABLE_HISTEXPAND:-}" ]]; then
|
|
138
|
+
echo "not-local:conflicting-evidence"
|
|
139
|
+
return
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
echo "local"
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
# Reason-aware capability banner — stderr only, never stdout. Silence about
|
|
146
|
+
# absent surfaces is the failure class this feature exists to kill.
|
|
147
|
+
emit_banner() {
|
|
148
|
+
local reason="$1" detail
|
|
149
|
+
case "$reason" in
|
|
150
|
+
no-devin-env)
|
|
151
|
+
detail="no Devin session environment (DEVIN, DEVIN_HOME, DEVIN_PROJECT_DIR, DEVIN_PLUGIN_ROOT, DEVIN_DIR all unset)"
|
|
152
|
+
;;
|
|
153
|
+
sentinel-absent)
|
|
154
|
+
detail="no local-session sentinel at .devin/soleur-local-session (plugin SessionStart never ran here)"
|
|
155
|
+
;;
|
|
156
|
+
malformed)
|
|
157
|
+
detail="local-session sentinel is unreadable, not a JSON object, or missing host/hook_source"
|
|
158
|
+
;;
|
|
159
|
+
foreign-host)
|
|
160
|
+
detail="local-session sentinel was written by a different host (committed file — /handoff does not carry gitignored content, measured 2026-09-17)"
|
|
161
|
+
;;
|
|
162
|
+
non-plugin-source)
|
|
163
|
+
detail="local-session sentinel was written by a repo-level hook, not the plugin registration"
|
|
164
|
+
;;
|
|
165
|
+
conflicting-evidence)
|
|
166
|
+
detail="plugin-sourced sentinel on a cloud-marked VM (DEVIN_DIR set) — plugin hooks may partially dispatch here; the capability gap persists"
|
|
167
|
+
;;
|
|
168
|
+
*)
|
|
169
|
+
detail="unrecognized classification"
|
|
170
|
+
;;
|
|
171
|
+
esac
|
|
172
|
+
{
|
|
173
|
+
printf '=== Soleur Cloud Mode — reduced-capability session ===\n'
|
|
174
|
+
printf 'This Devin session is NOT running the local Soleur surface (reason: %s — %s).\n' "$reason" "$detail"
|
|
175
|
+
printf 'Absent surfaces: plugin subagents (run_subagent / Task agent fan-out), ALL hooks\n'
|
|
176
|
+
printf ' (SessionStart / SessionEnd / PreToolUse / PostToolUse / Stop — incl.\n'
|
|
177
|
+
printf ' the credential guard, guardrails, and DONE-marker stop-gate)\n'
|
|
178
|
+
printf 'Still available: /soleur:* skills, AGENTS.md rules, MCP servers\n'
|
|
179
|
+
printf 'Degrade path: spawn-site skills run agent roles sequentially inline and disclose with\n'
|
|
180
|
+
printf ' "Reviewed-Coverage: sequential-fallback" in the deliverable\n'
|
|
181
|
+
printf 'Secrets/prod: reads and mutations require an explicit cloud acknowledgement first\n'
|
|
182
|
+
} >&2
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
RESULT="$(classify)"
|
|
186
|
+
echo "$RESULT"
|
|
187
|
+
# --banner is suppressed for no-devin-env as well as local: that reason means
|
|
188
|
+
# "no Devin markers at all" (e.g. a Claude Code session), and the banner asserts
|
|
189
|
+
# "This Devin session…" — emitting it there would be a false claim.
|
|
190
|
+
if [[ "$RESULT" != "local" && "$RESULT" != "not-local:no-devin-env" && "$BANNER" -eq 1 ]]; then
|
|
191
|
+
emit_banner "${RESULT#not-local:}"
|
|
192
|
+
fi
|
|
193
|
+
exit 0
|