@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,247 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: linear-fetch
|
|
3
|
+
description: "This skill should be used when a user input contains a Linear issue reference (e.g., SOL-39 or linear.app/.../issue/<ID>) and the downstream agent needs the screenshots embedded in the issue as visual context."
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Bash
|
|
6
|
+
- mcp__linear-server__get_issue
|
|
7
|
+
- mcp__linear-server__list_comments
|
|
8
|
+
- mcp__linear-server__extract_images
|
|
9
|
+
preconditions:
|
|
10
|
+
- Linear MCP server is authenticated (mcp__linear-server__authenticate has been run for this session)
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<!-- grok-harness-invoke:start -->
|
|
14
|
+
**Grok Build (`plugins/soleur/lib/harness.ts` `invokeSkill()`):** Read this SKILL.md in this process and run it to completion. A one-segment `soleur:<name>` in this document names a SKILL — on Grok Build, Read `plugins/soleur/skills/<name>/SKILL.md` in this process; it is not a nested tool_use. A multi-segment id such as `soleur:<domain>:<name>` names an AGENT: spawn it, never Read it, and on Grok Build spawn_subagent takes the id with its colons replaced by hyphens (`agentIdToGrokSubagentType`). **Claude Code:** Skill tool for a skill (`soleur:<name>`), Task tool with `subagent_type` for an agent. Forbidden is executing a subset, not the Read.
|
|
15
|
+
<!-- grok-harness-invoke:end -->
|
|
16
|
+
|
|
17
|
+
# Linear Issue Image Context
|
|
18
|
+
|
|
19
|
+
This skill detects Linear issue references in caller input, fetches the issue body and recent comments, and streams the embedded screenshots directly into the active model conversation. The caller (typically `soleur:one-shot` Step 0a or `soleur:brainstorm` Phase 0.4) receives two return artifacts and is responsible for choosing the right one for each downstream consumer.
|
|
20
|
+
|
|
21
|
+
## Caller Contract
|
|
22
|
+
|
|
23
|
+
This skill returns **two artifacts**. Mixing them up is the load-bearing failure mode the skill exists to prevent.
|
|
24
|
+
|
|
25
|
+
1. **Agent context** — the full markdown blob (description + comment bodies) with Linear image content blocks streamed into the active conversation by `mcp__linear-server__extract_images`. **Callers MUST NOT write this artifact to disk, a PR body, a commit message, or any file under `knowledge-base/`.** The Linear image URLs inside it (`uploads.linear.app/*`) are signed bearer credentials that grant public-internet read access for their validity window.
|
|
26
|
+
2. **Persist-safe summary** — the same text with every `uploads.linear.app/*` URL redacted to the literal token `[linear-image: REDACTED]`. **Callers MUST use this variant for any persistence**: writes to `knowledge-base/`, PR descriptions, commit messages, learning files, downstream subagent prompts.
|
|
27
|
+
|
|
28
|
+
The redaction primitive lives at [scripts/redact-linear-urls.sh](./scripts/redact-linear-urls.sh). It uses a **case-insensitive hostname match** (`[Hh][Tt][Tt][Pp][Ss]?://[Uu][Pp][Ll][Oo][Aa][Dd][Ss]\.[Ll][Ii][Nn][Ee][Aa][Rr]\.[Aa][Pp][Pp]/`) — DNS is case-insensitive and `https://Uploads.Linear.App/...` serves the same signed bearer credential as the lowercase form. The URL path uses a positive ASCII-only character class (RFC 3986 unreserved + reserved set), so Unicode separators (U+2028, U+2029, NBSP) and markdown/HTML terminators (`< > " ' ) ]`) all terminate the match cleanly. The full justification per character is inline in the script. The companion CI `pii-grep` job in `.github/workflows/pr-quality-guards.yml` mirrors the case-insensitive matching with `grep -iE`.
|
|
29
|
+
|
|
30
|
+
The repository is public on GitHub. A single leaked `uploads.linear.app` URL is a `single-user incident` brand-survival event per `knowledge-base/project/specs/archive/20261013-014038-feat-linear-issue-image-context/spec.md`.
|
|
31
|
+
|
|
32
|
+
## Phases
|
|
33
|
+
|
|
34
|
+
### Phase A — Reference detection
|
|
35
|
+
|
|
36
|
+
Scan the input string for substrings matching either:
|
|
37
|
+
|
|
38
|
+
- The identifier shape `[A-Z]{2,}-[0-9]+` (matches `SOL-39`, `LIN-12`, `ENG-100`, but also `PR-123`, `HTTP-200`, `CVE-2024` — false positives are handled in Phase B, not at the regex level), OR
|
|
39
|
+
- The URL shape `linear\.app/[^/]+/issue/([A-Z]+-[0-9]+)` — extract the captured identifier.
|
|
40
|
+
|
|
41
|
+
Uppercase each captured identifier and deduplicate (case-sensitive after uppercasing, exact-match on the number — `SOL-39` and `sol-39` collapse to one entry).
|
|
42
|
+
|
|
43
|
+
If more than 5 distinct identifiers match, use the `AskUserQuestion` tool to ask the user how to proceed before any MCP call:
|
|
44
|
+
|
|
45
|
+
- **Header:** "Linear cap"
|
|
46
|
+
- **Question:** "Found N Linear references; the default cap is 5 to bound prompt size and MCP cost. Process the first 5, all N, or abort?"
|
|
47
|
+
- **Options:** "Process first 5 (default)", "Process all (may bloat context)", "Abort". The "Other" escape is appended automatically by the runtime.
|
|
48
|
+
|
|
49
|
+
Take the user's choice as the working set for Phase B.
|
|
50
|
+
|
|
51
|
+
If 5 or fewer matches, proceed directly.
|
|
52
|
+
|
|
53
|
+
If zero matches, return immediately with no disclosure line — the skill is a no-op for inputs that do not reference Linear.
|
|
54
|
+
|
|
55
|
+
### Phase B — Fetch + comment scan
|
|
56
|
+
|
|
57
|
+
For each identifier in the working set:
|
|
58
|
+
|
|
59
|
+
1. Invoke `mcp__linear-server__get_issue(id=<identifier>)`. On a `404 Not Found` response, silently drop the identifier — this converts false-positive matches like `PR-123` or `CVE-2024` into no-ops with no user-visible failure. On any other failure (`403`, network error, token expired), emit the warning from Phase E and skip to the next identifier; do not abort.
|
|
60
|
+
2. Invoke `mcp__linear-server__list_comments(issueId=<identifier>, orderBy="createdAt", limit=250)`. The MCP schema (verified at Phase 0 of the plan) supports `orderBy: createdAt | updatedAt` and `limit` up to 250. The schema does NOT expose an order-direction parameter, so the response order is treated as ambiguous: parse each comment's `createdAt` field and sort client-side **descending**, then take the first 10 entries as "10 most-recent by creation time." If the response contains 10 or fewer comments, skip the sort.
|
|
61
|
+
3. Concatenate the issue description and the 10 most-recent comment bodies into a single markdown blob, delimited as `\n\n--- comment by <author.displayName> on <createdAt> ---\n\n` between each block.
|
|
62
|
+
|
|
63
|
+
### Phase B.0 — Pre-fetch preflight (blob-independent; runs BEFORE Phase C)
|
|
64
|
+
|
|
65
|
+
**Run this fence before invoking `extract_images`, and abort the whole skill on a non-zero exit.**
|
|
66
|
+
|
|
67
|
+
Both checks below are **blob-independent** — they interrogate the plugin installation, not the
|
|
68
|
+
issue. Until #7450 they sat in Phase D, *after* Phase C had already streamed the issue's image
|
|
69
|
+
content blocks into the conversation. So on every halt path the signed `uploads.linear.app`
|
|
70
|
+
bearer URLs were already in the parent transcript, and the "fail closed" refusal protected only
|
|
71
|
+
the artifact nobody had produced yet. A guard that cannot run before the exposure is not a guard
|
|
72
|
+
against it. Nothing here depends on the blob, so nothing forced that ordering.
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
[ -f "${CLAUDE_PLUGIN_ROOT}/.claude-plugin/plugin.json" ] \
|
|
76
|
+
&& grep -q '"name"[[:space:]]*:[[:space:]]*"soleur"' "${CLAUDE_PLUGIN_ROOT}/.claude-plugin/plugin.json" \
|
|
77
|
+
|| { echo "SOLEUR_LINEAR_FETCH_HALT reason=plugin-root-unverified root=[${CLAUDE_PLUGIN_ROOT}]"
|
|
78
|
+
echo "linear-fetch: cannot verify the Soleur plugin installation — stopping before anything is fetched." >&2
|
|
79
|
+
echo " Resolved plugin root: [${CLAUDE_PLUGIN_ROOT}]" >&2
|
|
80
|
+
echo " If that is EMPTY: no Soleur plugin is loaded in this session. Install it and start a NEW session — re-running here resolves the same empty root." >&2
|
|
81
|
+
echo " If it names a path: that path is not a Soleur install (a repo checkout is not an install). Run 'claude plugin update soleur@soleur-marketplace' (or the id 'claude plugin list' prints, if you added the repository directly), then RESTART Claude Code — plugin changes apply only on restart. If you installed with --scope project or --scope local, pass the same scope. Reinstall only if that does not clear it." >&2
|
|
82
|
+
echo " Nothing has been fetched yet, so nothing has leaked." >&2
|
|
83
|
+
exit 2; }
|
|
84
|
+
SCRUBBER="${CLAUDE_PLUGIN_ROOT}/skills/linear-fetch/scripts/redact-linear-urls.sh"
|
|
85
|
+
[[ -r "$SCRUBBER" ]] || { echo "SOLEUR_LINEAR_FETCH_HALT reason=scrubber-unreadable scrubber=[$SCRUBBER]"
|
|
86
|
+
echo "linear-fetch: the redaction primitive is missing from an otherwise valid Soleur install — stopping." >&2
|
|
87
|
+
echo " Expected at: [$SCRUBBER]" >&2
|
|
88
|
+
echo " The install is partial or out of date. Run 'claude plugin update soleur@soleur-marketplace' (or the id 'claude plugin list' prints, if you added the repository directly), then RESTART Claude Code — plugin changes apply only on restart. If you installed with --scope project or --scope local, pass the same scope. Reinstall only if that does not clear it." >&2
|
|
89
|
+
echo " Nothing has been fetched yet, so nothing has leaked." >&2
|
|
90
|
+
exit 2; }
|
|
91
|
+
echo "SOLEUR_LINEAR_FETCH_PREFLIGHT_OK scrubber=present"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
If this fence exits non-zero, **stop**: do not invoke `extract_images`, do not emit
|
|
95
|
+
`agent_context`, and do not emit a disclosure line. The correct operator-visible outcome is the
|
|
96
|
+
halt message above, not a partially-fetched issue.
|
|
97
|
+
|
|
98
|
+
### Phase C — Image passthrough
|
|
99
|
+
|
|
100
|
+
For each issue's combined markdown blob from Phase B, invoke `mcp__linear-server__extract_images(markdown=<blob>)`. The MCP server resolves Linear-authenticated CDN URLs server-side and streams the underlying image bytes back into the active conversation as image content blocks. The skill never sees the bytes, never writes them to disk, never re-fetches them.
|
|
101
|
+
|
|
102
|
+
Count the image content blocks returned per issue (call this `N_images_total`), and count how many were extracted from comment bodies specifically (call this `M_comments_with_images`). The MCP response shape should make this distinguishable; if not, infer from the per-source split by passing description and comments through `extract_images` separately.
|
|
103
|
+
|
|
104
|
+
### Phase D — Disclosure & dual-artifact return
|
|
105
|
+
|
|
106
|
+
For each issue, emit exactly one disclosure line to stdout based on the Phase C counts:
|
|
107
|
+
|
|
108
|
+
<!-- markdownlint-disable MD038 -->
|
|
109
|
+
<!-- #7927: MD038 on this table is cosmetic. Verified with the repo's own markdown-it:
|
|
110
|
+
every span here renders with no edge space (CommonMark strips a single leading and
|
|
111
|
+
trailing space), except one where the leading space is the point -- the cell
|
|
112
|
+
documents a string that is APPENDED, so its space is content. A disable-line comment
|
|
113
|
+
cannot be used: GFM discards anything past a row's closing pipe. -->
|
|
114
|
+
| Condition | Disclosure line |
|
|
115
|
+
|---|---|
|
|
116
|
+
| Images present | `Detected <ID> — fetched issue + N_images_total images from description and M_comments_with_images comments.` |
|
|
117
|
+
| Text-only (description and comments had zero `uploads.linear.app` references and `extract_images` returned zero images) | `Detected <ID> — text-only issue, no images.` |
|
|
118
|
+
| Soft anomaly (description or comments contained `uploads.linear.app` URLs but `extract_images` returned zero images) | `Detected <ID> — N image URLs found but extraction returned 0 images (soft anomaly).` |
|
|
119
|
+
| Comment cap hit (`list_comments` returned exactly 250 — Linear MCP's per-call limit, may have more comments past the cap) | append ` (comment cap hit — may be missing newer comments)` to the appropriate line above. The skill takes the 10 most-recent from the 250-window, so very high-volume issues may miss comments past position 250. Cursor pagination is a v1.1 follow-up (issue filed at plan finalization). |
|
|
120
|
+
<!-- markdownlint-enable MD038 -->
|
|
121
|
+
|
|
122
|
+
Construct the two return artifacts:
|
|
123
|
+
|
|
124
|
+
- **agent_context** — emit the full markdown blob inline in the conversation, so the parent's message history holds both the text and the image content blocks from `extract_images`. The parent retains these for downstream phases (one-shot Steps 3+, brainstorm Phase 2 Synthesis, brainstorm Phase 3 Capture). Per `2026-05-12-task-subagent-prompt-text-only.md`, image content blocks do NOT propagate to Task subagents — design accordingly.
|
|
125
|
+
- **persist_safe_summary** — produce by piping the full markdown blob through the redaction primitive, resolved from the **deployed plugin root** (ADR-179's canonical bare anchor, no fallback arm). The redacted text is the only artifact callers may persist. Return it as a fenced text block clearly labeled `PERSIST-SAFE SUMMARY (use this for any write to disk):` so the parent skill cannot confuse it with the agent_context.
|
|
126
|
+
|
|
127
|
+
**The exit-code dispatch below is load-bearing, and this site had none before #7450.** With no
|
|
128
|
+
guard, an unresolved root yields exit `127` and **empty stdout** — and empty stdout is exactly
|
|
129
|
+
the shape an agent can mistake for "the redacted text" and persist. Empty output is a failure,
|
|
130
|
+
never a clean summary. The default arm was removed, not re-pointed: `review/SKILL.md` instructs
|
|
131
|
+
`gh pr checkout`, so that arm resolved this scrubber from the reviewed party's tree.
|
|
132
|
+
|
|
133
|
+
The identity and readability checks are NOT repeated here — they ran in **Phase B.0**, before
|
|
134
|
+
anything was fetched. What remains is the blob-dependent half.
|
|
135
|
+
|
|
136
|
+
Substitute the full markdown blob verbatim between the heredoc delimiters. **The delimiter is
|
|
137
|
+
quoted (`<<'LINEAR_BLOB'`), which is load-bearing twice over**: it stops the shell expanding
|
|
138
|
+
issue text that Linear users control, and it keeps the blob off disk. The pre-#7450 form
|
|
139
|
+
(`bash "$SCRUBBER" <blob-tmpfile>`) wrote the **un-redacted, bearer-URL-bearing** blob to a file
|
|
140
|
+
that was never created, named, or removed by any step in this skill, on all four halt paths —
|
|
141
|
+
while the prose two paragraphs up still described the operation as piping.
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# RE-DERIVED, not inherited. Phase B.0 is a SEPARATE Bash call, and shell state does not
|
|
145
|
+
# persist across calls — so `$SCRUBBER` is EMPTY here unless it is defined in this fence.
|
|
146
|
+
# Assuming otherwise is not a theoretical risk: it shipped, and it bricked this skill on
|
|
147
|
+
# every invocation (`bash: : No such file or directory` -> reason=scrubber-nonzero-exit ->
|
|
148
|
+
# rc 2, so `persist_safe_summary` could never be produced and every caller hard-stopped).
|
|
149
|
+
# It failed CLOSED only because the anchor is quoted; unquoted, `bash $SCRUBBER <<'…'`
|
|
150
|
+
# executes the heredoc, i.e. runs Linear issue text as a shell script.
|
|
151
|
+
# B.0 still owns the identity preflight and the readability check — those are the
|
|
152
|
+
# blob-independent halts that must precede the fetch. This line is the same bare anchor,
|
|
153
|
+
# re-stated where it is used.
|
|
154
|
+
SCRUBBER="${CLAUDE_PLUGIN_ROOT}/skills/linear-fetch/scripts/redact-linear-urls.sh"
|
|
155
|
+
|
|
156
|
+
# The scrubber reads stdin and writes redacted text to stdout.
|
|
157
|
+
PERSIST_SAFE="$(bash "$SCRUBBER" <<'LINEAR_BLOB'
|
|
158
|
+
<the full markdown blob from Phase B, verbatim>
|
|
159
|
+
LINEAR_BLOB
|
|
160
|
+
)" || { echo "SOLEUR_LINEAR_FETCH_HALT reason=scrubber-nonzero-exit"
|
|
161
|
+
echo "linear-fetch: the redaction primitive exited non-zero — stopping." >&2
|
|
162
|
+
echo " Nothing is persisted. Do NOT fall back to agent_context; it carries the bearer URLs." >&2
|
|
163
|
+
echo " What to do: re-run once. If it repeats, this is a Soleur defect — file it with the exit status; do not hand-copy the issue text." >&2
|
|
164
|
+
exit 2; }
|
|
165
|
+
|
|
166
|
+
[ -n "$PERSIST_SAFE" ] \
|
|
167
|
+
|| { echo "SOLEUR_LINEAR_FETCH_HALT reason=redaction-empty-output"
|
|
168
|
+
echo "linear-fetch: redaction produced EMPTY output — stopping." >&2
|
|
169
|
+
echo " Empty output is a failure, not a clean summary. Do NOT persist it." >&2
|
|
170
|
+
echo " What to do: re-run once. If it repeats, this is a Soleur defect — file it; do not paste the issue text by hand." >&2
|
|
171
|
+
exit 2; }
|
|
172
|
+
|
|
173
|
+
# Redaction must have HAPPENED, not merely have run. A scrubber that returns its input
|
|
174
|
+
# unchanged is non-empty and exits 0, so every other guard here stays green while the
|
|
175
|
+
# artifact labelled PERSIST-SAFE still carries the signed bearer URLs. This is also the
|
|
176
|
+
# only check on this path that does not depend on the anchor being trustworthy.
|
|
177
|
+
# Herestring, not a pipe: under `set -o pipefail` a `grep -q` that matches early closes
|
|
178
|
+
# the pipe, the producer takes SIGPIPE, and the pipeline reports failure on a match.
|
|
179
|
+
if grep -qiE 'uploads\.linear\.app' <<<"$PERSIST_SAFE"; then
|
|
180
|
+
echo "SOLEUR_LINEAR_FETCH_HALT reason=redaction-ineffective"
|
|
181
|
+
echo "linear-fetch: redaction did NOT remove the signed uploads.linear.app URLs — stopping." >&2
|
|
182
|
+
echo " The scrubber ran and returned output, but the output still carries bearer credentials." >&2
|
|
183
|
+
echo " Do NOT persist this text." >&2
|
|
184
|
+
echo " This is a SOLEUR DEFECT, not a problem with your issue: the scrubber ran and returned bearer URLs anyway." >&2
|
|
185
|
+
echo " What to do: do NOT retry — a retry will produce the same result. File this with the issue identifier (not its contents)." >&2
|
|
186
|
+
exit 2
|
|
187
|
+
fi
|
|
188
|
+
|
|
189
|
+
# Emit it. Shell state does not persist across Bash calls, so a block that assigns
|
|
190
|
+
# PERSIST_SAFE and never prints it cannot produce the artifact it exists to produce.
|
|
191
|
+
printf '%s\n' "$PERSIST_SAFE"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
On any halt above, `persist_safe_summary` **does not exist**. Callers must treat its absence as a hard stop and MUST NOT substitute `agent_context` — see the absent-artifact contract in [one-shot](../one-shot/SKILL.md) Step 0a and [brainstorm](../brainstorm/SKILL.md) Phase 0.4. `agent_context` carries the signed `uploads.linear.app` bearer URLs this primitive exists to remove, so falling back to it converts a refusal into the exact leak.
|
|
195
|
+
|
|
196
|
+
**Telemetry redaction (TR7).** This skill MUST NOT include the matched Linear identifier, the issue title, any image URL, or any signed-URL fragment in incident telemetry (`.claude/hooks/lib/incidents.sh emit_incident`). If telemetry is ever emitted from inside this skill, use generic strings only (e.g., `linear-fetch applied`). The current implementation has zero `emit_incident` call sites; a future maintainer adding one must pass the [assert-no-linear-telemetry.sh](./scripts/assert-no-linear-telemetry.sh) assertion or extend the assertion to cover the new emission shape.
|
|
197
|
+
|
|
198
|
+
### Phase E — Failure handling
|
|
199
|
+
|
|
200
|
+
For any MCP failure that is NOT a benign 404 false-positive:
|
|
201
|
+
|
|
202
|
+
- Emit a one-line warning to stdout: `Linear fetch failed for <ID>: <reason>. Continuing without image context.`
|
|
203
|
+
- Do NOT abort the parent skill. The original identifier text remains in `$ARGUMENTS`; the downstream agent can still reason about the issue from prose alone.
|
|
204
|
+
- Do NOT include the matched identifier in any telemetry emission per TR7. The warning above is operator-facing stdout, not telemetry — the identifier is permitted in the warning so the operator can take corrective action.
|
|
205
|
+
|
|
206
|
+
The most common reasons (and what they mean):
|
|
207
|
+
|
|
208
|
+
| Reason | What it usually means |
|
|
209
|
+
|---|---|
|
|
210
|
+
| `MCP tool not found` | Linear MCP server is not registered for this session. Run `mcp__linear-server__authenticate`. |
|
|
211
|
+
| `403 Forbidden` | Token is valid but lacks access to the issue's workspace. Confirm Linear workspace membership. |
|
|
212
|
+
| `Network timeout` | Linear API unreachable. Try again, or work offline from prose only. |
|
|
213
|
+
| `Token expired` | OAuth token rotation needed. Re-run `mcp__linear-server__authenticate`. |
|
|
214
|
+
|
|
215
|
+
## Caller invocation contract
|
|
216
|
+
|
|
217
|
+
This skill is invoked via the `Skill` tool from inside another skill (not directly by the operator). Two known callers as of v1:
|
|
218
|
+
|
|
219
|
+
- `soleur:one-shot` Step 0a — parent fetches once, retains images for Steps 3+, substitutes `persist_safe_summary` into the Steps 1-2 Task subagent's prompt template.
|
|
220
|
+
- `soleur:brainstorm` Phase 0.4 — parent fetches once, retains images for Phase 2 Synthesis and Phase 3 Capture, embeds `persist_safe_summary` in Phase 0.5 domain-leader prompts.
|
|
221
|
+
|
|
222
|
+
The skill does NOT modify `soleur:plan`, `soleur:fix-issue`, or `soleur:work` in v1. Those are tracked as a v2 follow-up issue at plan-finalization time.
|
|
223
|
+
|
|
224
|
+
## Manual Test Runbook
|
|
225
|
+
|
|
226
|
+
The 10 spec acceptance-test scenarios. Operators run these against a real Linear workspace before marking the post-merge acceptance criteria done. Each step lists: input to type into Claude Code, expected disclosure, and post-condition to verify.
|
|
227
|
+
|
|
228
|
+
1. **Happy path — single-issue, description-only image.** Pick a real `SOL-*` issue whose description contains one Linear-CDN-hosted image (markdown shape ``). Type `fix <ID>` into a `soleur:one-shot`-routed prompt. Expected: disclosure `Detected <ID> — fetched issue + 1 images from description and 0 comments.` Visual check: the image is rendered inline in the current conversation. Persist check: the plan subagent's plan document at `knowledge-base/project/plans/...` contains zero `uploads.linear.app` matches (`grep -c` returns 0).
|
|
229
|
+
2. **Happy path — comments-only image.** Pick an issue with a text-only description and one image attached in a comment. Same invocation. Expected: `fetched issue + 1 images from description and 1 comments.`
|
|
230
|
+
3. **Text-only issue.** Pick an issue with no images anywhere. Expected: `text-only issue, no images.`
|
|
231
|
+
4. **Multi-issue input.** Type `compare <ID-1> and <ID-2>`. Expected: two disclosure lines, one per issue.
|
|
232
|
+
5. **404 issue.** Type `fix SOL-999999` (or any non-existent identifier). Expected: silent no-op, no warning printed (false-positive path).
|
|
233
|
+
6. **False-positive identifier.** Type `the PR-123 we shipped`. Expected: silent no-op for `PR-123` (404 → silently dropped). No warning, no MCP error surfacing to the operator.
|
|
234
|
+
7. **Comments cap.** Pick an issue with 15+ comments, several of which contain images. Expected: only 10 most-recent processed; the disclosure's `M_comments_with_images` count is at most 10.
|
|
235
|
+
8. **Persist-safe round-trip.** After a `soleur:brainstorm` invocation that triggered the skill, run `grep -c 'uploads.linear.app' knowledge-base/project/brainstorms/<latest>.md`. Expected: `0`.
|
|
236
|
+
9. **CI grep gate fires.** Create a fixture branch outside Claude Code, manually `git add` and `git commit` a file containing `https://uploads.linear.app/TEST-FIXTURE-NOT-REAL.png`, push, and open a PR. Expected: the `pii-grep` CI job fails the PR with a clear `::error::` annotation pointing at `knowledge-base/project/specs/archive/20261013-014038-feat-linear-issue-image-context/spec.md`.
|
|
237
|
+
10. **Telemetry redaction.** Run any skill that emits incident telemetry while the conversation has linear-fetch context. Inspect `.claude/incidents/*.jsonl` after the test run. Expected: zero lines contain a Linear identifier (`SOL-\d+` or similar) or `uploads.linear.app`.
|
|
238
|
+
|
|
239
|
+
If any scenario fails post-merge, file a P1 follow-up issue, leave `#3635` open, and do not mark the skill production-ready until the failure is reproduced and fixed.
|
|
240
|
+
|
|
241
|
+
## Sharp Edges
|
|
242
|
+
|
|
243
|
+
- The `LINEAR_CDN_PATTERNS` array in [scripts/redact-linear-urls.sh](./scripts/redact-linear-urls.sh) is intentionally extensible (currently one pattern: `uploads.linear.app`). If Linear introduces a new CDN hostname (`cdn.linear.app`, `linear-assets.com`), add a new pattern to the array AND update the CI `pii-grep` workflow regex in the same PR. The redaction primitive's unit-test fixtures must also gain a matching fixture per new pattern.
|
|
244
|
+
- The character class excludes single quote via the bash `$'\x27'` ANSI-C escape (so the regex literal contains `'`). This works on bash 5.x (Linux) and bash 3.2 (macOS) but the test runbook explicitly tests on both before declaring the script production-ready.
|
|
245
|
+
- `list_comments` `orderBy` direction is not exposed in the MCP schema; client-side `createdAt desc` sort + take-10 is the hard fallback to remain order-independent. Do not assume server-side direction.
|
|
246
|
+
- The skill must be invoked via the `Skill` tool, not run as a CLI. The `Skill` invocation places the image content blocks from `extract_images` into the caller's conversation; a standalone CLI run would lose the images entirely.
|
|
247
|
+
- `extract_images` may return zero images for an issue whose markdown contains `uploads.linear.app` URLs (e.g., an upstream Linear bug, transient CDN failure, expired URL inside the issue). The Phase D soft-anomaly disclosure exists precisely so this case is operator-visible and not silent.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Assert that a telemetry payload (or any text passed via stdin or as
|
|
3
|
+
# the first argument file path) contains no Linear identifiers, no Linear
|
|
4
|
+
# CDN URLs, and no UUID-style Linear IDs. Used to enforce spec TR7.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# echo "$payload" | bash assert-no-linear-telemetry.sh
|
|
8
|
+
# bash assert-no-linear-telemetry.sh /path/to/file.jsonl
|
|
9
|
+
#
|
|
10
|
+
# Exit 0 if clean. Exit 1 if any forbidden pattern matches. The first
|
|
11
|
+
# offending pattern is printed to stderr with the matched substring.
|
|
12
|
+
#
|
|
13
|
+
# Forbidden patterns:
|
|
14
|
+
# 1. Linear issue identifier: [A-Z]{2,}-[0-9]+ (matches SOL-39, LIN-12, etc.)
|
|
15
|
+
# 2. Linear CDN URL: uploads\.linear\.app
|
|
16
|
+
# 3. Linear UUID-style ID: 8-4-4-4-12 hex (Linear's internal issue IDs)
|
|
17
|
+
#
|
|
18
|
+
# Note: this helper is INTENTIONALLY strict. Operator-facing stdout (the
|
|
19
|
+
# Phase E warning line that names the failed identifier) is NOT routed
|
|
20
|
+
# through this assertion — only telemetry payloads emitted to
|
|
21
|
+
# .claude/hooks/lib/incidents.sh are gated. The skill currently has zero
|
|
22
|
+
# emit_incident call sites; this helper exists so a future maintainer
|
|
23
|
+
# adding one cannot regress TR7 silently.
|
|
24
|
+
#
|
|
25
|
+
# Known limitations (security-sentinel P2-1, P2-2):
|
|
26
|
+
# 1. Base64-encoded payloads are NOT decoded before pattern check. A
|
|
27
|
+
# caller that base64-encodes Linear identifiers or URLs in telemetry
|
|
28
|
+
# will silently pass this gate. If telemetry shapes start including
|
|
29
|
+
# encoded fields, add a base64-decode pre-pass (detect strings of
|
|
30
|
+
# shape `^[A-Za-z0-9+/=]{16,}$`, decode, recurse).
|
|
31
|
+
# 2. URL-fragment-only leaks (e.g., `?sig=<long_base64>&expires=<ts>`
|
|
32
|
+
# without the hostname) are NOT caught. A future maintainer pasting
|
|
33
|
+
# signed-URL query params separately from the host would bypass.
|
|
34
|
+
# Consider adding a fourth pattern matching `\?[a-zA-Z]+=[A-Za-z0-9_-]{32,}`.
|
|
35
|
+
# These limitations are acceptable for the current zero-emit_incident
|
|
36
|
+
# baseline; revisit if the skill grows real telemetry emissions.
|
|
37
|
+
|
|
38
|
+
set -eu
|
|
39
|
+
|
|
40
|
+
if [[ $# -ge 1 && -r "$1" ]]; then
|
|
41
|
+
input=$(cat "$1")
|
|
42
|
+
else
|
|
43
|
+
input=$(cat -)
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Pattern 1: Linear issue identifier shape.
|
|
47
|
+
if grep -qE '\b[A-Z]{2,}-[0-9]+\b' <<<"$input"; then
|
|
48
|
+
match=$(printf '%s' "$input" | grep -oE '\b[A-Z]{2,}-[0-9]+\b' | head -n 1)
|
|
49
|
+
echo "FAIL: telemetry payload contains Linear identifier shape: $match" >&2
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Pattern 2: Linear CDN hostname (any form, signed-URL fragments included).
|
|
54
|
+
if grep -qiE 'uploads\.linear\.app' <<<"$input"; then
|
|
55
|
+
echo "FAIL: telemetry payload contains uploads.linear.app reference" >&2
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Pattern 3: UUID-style ID (Linear's internal issue UUIDs).
|
|
60
|
+
if grep -qE '\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b' <<<"$input"; then
|
|
61
|
+
match=$(printf '%s' "$input" | grep -oE '\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b' | head -n 1)
|
|
62
|
+
echo "FAIL: telemetry payload contains UUID-style identifier: $match" >&2
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
exit 0
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Redact uploads.linear.app URLs from stdin. Writes redacted text to
|
|
3
|
+
# stdout; writes redaction count to stderr.
|
|
4
|
+
#
|
|
5
|
+
# Brand-survival: a regression here means a uploads.linear.app signed URL
|
|
6
|
+
# can leak into a committed artifact on a public-GitHub repo. See
|
|
7
|
+
# knowledge-base/project/specs/archive/20261013-014038-feat-linear-issue-image-context/spec.md FR7
|
|
8
|
+
# and the plan's User-Brand Impact section.
|
|
9
|
+
#
|
|
10
|
+
# Hostname matching is case-insensitive (DNS is case-insensitive — a URL like
|
|
11
|
+
# https://Uploads.Linear.App/x.png resolves to the same CDN host as the
|
|
12
|
+
# lowercase form and still serves the signed bearer credential). The hostname
|
|
13
|
+
# is encoded as bracketed character classes ([Hh][Tt]...) because BSD sed
|
|
14
|
+
# (macOS) does not portably support the `s///gI` case-insensitive flag, so
|
|
15
|
+
# we cannot rely on a flag in the substitution path.
|
|
16
|
+
#
|
|
17
|
+
# URL-path character class is a POSITIVE match against the RFC 3986 unreserved
|
|
18
|
+
# + reserved set (ASCII only). This is more conservative than the prior
|
|
19
|
+
# negated class:
|
|
20
|
+
# - Multi-byte UTF-8 sequences (U+2028, U+2029, NBSP, etc.) automatically
|
|
21
|
+
# terminate the match at the first non-ASCII byte. POSIX [:space:] is
|
|
22
|
+
# ASCII-only and would let the redactor consume past Unicode separators
|
|
23
|
+
# (security-sentinel P2-3 + cq-regex-unicode-separators-escape-only).
|
|
24
|
+
# - Markdown/HTML terminators (< > " ' ) ]) are not in the set, so URLs
|
|
25
|
+
# end correctly inside autolinks, HTML attributes, and markdown links.
|
|
26
|
+
#
|
|
27
|
+
# Adding a new CDN hostname (e.g., cdn.linear.app) requires:
|
|
28
|
+
# 1. A new entry in LINEAR_CDN_PATTERNS below.
|
|
29
|
+
# 2. An updated regex in .github/workflows/pr-quality-guards.yml pii-grep.
|
|
30
|
+
# 3. A matching fixture in redact-linear-urls.test.sh.
|
|
31
|
+
# The parity test (parity.test.sh, when added) enforces 1 and 2 stay in sync.
|
|
32
|
+
#
|
|
33
|
+
# set -e is on; pipefail is intentionally off because `grep -oE` returns
|
|
34
|
+
# exit 1 on zero matches — a benign condition we count and continue past.
|
|
35
|
+
|
|
36
|
+
set -eu
|
|
37
|
+
|
|
38
|
+
LINEAR_CDN_PATTERNS=(
|
|
39
|
+
$'[Hh][Tt][Tt][Pp][Ss]?://[Uu][Pp][Ll][Oo][Aa][Dd][Ss]\\.[Ll][Ii][Nn][Ee][Aa][Rr]\\.[Aa][Pp][Pp]/[A-Za-z0-9._~:/?#@!$&*+,;=%-]+'
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
input=$(cat -)
|
|
43
|
+
count=0
|
|
44
|
+
output="$input"
|
|
45
|
+
for pattern in "${LINEAR_CDN_PATTERNS[@]}"; do
|
|
46
|
+
matches=$(printf '%s' "$output" | grep -oE "$pattern" | wc -l | tr -d '[:space:]')
|
|
47
|
+
count=$((count + matches))
|
|
48
|
+
output=$(printf '%s' "$output" | sed -E "s#$pattern#[linear-image: REDACTED]#g")
|
|
49
|
+
done
|
|
50
|
+
printf '%s' "$output"
|
|
51
|
+
printf '%s' "$count" >&2
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Substitute a placeholder in a template (stdin) with a value (arg 1).
|
|
3
|
+
# Used by persist-safe-integration.test.sh to simulate the runtime
|
|
4
|
+
# substitution that one-shot Step 0a and brainstorm Phase 0.4 perform
|
|
5
|
+
# when threading persist_safe_summary into downstream prompts.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# echo "$template" | bash render-caller-template.sh "$summary"
|
|
9
|
+
#
|
|
10
|
+
# The placeholder is the literal string __PERSIST_SAFE_SUMMARY__ — chosen
|
|
11
|
+
# to be visually distinct from $ARGUMENTS (one-shot template) and {desc}
|
|
12
|
+
# (brainstorm template) so test fixtures can mirror either real template
|
|
13
|
+
# by writing the placeholder in the right spot.
|
|
14
|
+
#
|
|
15
|
+
# Implementation note: awk is used (not sed) so the substitution value
|
|
16
|
+
# can contain arbitrary characters including /, &, \, and newlines
|
|
17
|
+
# without escaping. The placeholder itself is 24 chars of fixed-shape
|
|
18
|
+
# alphanumeric + underscore — no regex metacharacters.
|
|
19
|
+
|
|
20
|
+
set -eu
|
|
21
|
+
|
|
22
|
+
VALUE="${1:?usage: render-caller-template.sh <value>}"
|
|
23
|
+
TEMPLATE=$(cat -)
|
|
24
|
+
PLACEHOLDER='__PERSIST_SAFE_SUMMARY__'
|
|
25
|
+
|
|
26
|
+
# Use awk for arbitrary-content substitution — no sed escaping needed.
|
|
27
|
+
printf '%s' "$TEMPLATE" | awk -v val="$VALUE" -v ph="$PLACEHOLDER" '
|
|
28
|
+
{
|
|
29
|
+
line = $0
|
|
30
|
+
while ((p = index(line, ph)) > 0) {
|
|
31
|
+
printf "%s%s", substr(line, 1, p-1), val
|
|
32
|
+
line = substr(line, p + length(ph))
|
|
33
|
+
}
|
|
34
|
+
print line
|
|
35
|
+
}
|
|
36
|
+
'
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Tests for assert-no-linear-telemetry.sh — TR7 telemetry-redaction gate.
|
|
3
|
+
#
|
|
4
|
+
# Run via: bash plugins/soleur/skills/linear-fetch/scripts/assert-no-linear-telemetry.test.sh
|
|
5
|
+
|
|
6
|
+
set -eu
|
|
7
|
+
|
|
8
|
+
# Owning trap (ADR-129). These files allocated tempfiles with no cleanup for as long as they
|
|
9
|
+
# sat under scripts/, where no runner reached them; relocating them into test/ put them in
|
|
10
|
+
# the lint's scope and surfaced it.
|
|
11
|
+
_LF_TMPS=()
|
|
12
|
+
_lf_cleanup() { [[ ${#_LF_TMPS[@]} -gt 0 ]] && rm -f "${_LF_TMPS[@]}"; return 0; }
|
|
13
|
+
trap _lf_cleanup EXIT INT TERM HUP
|
|
14
|
+
_lf_mktemp() { local t; t="$(mktemp)" || return 1; _LF_TMPS+=("$t"); printf '%s' "$t"; }
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../scripts" && pwd)"
|
|
18
|
+
SCRIPT="$SCRIPT_DIR/assert-no-linear-telemetry.sh"
|
|
19
|
+
|
|
20
|
+
PASS=0
|
|
21
|
+
FAIL=0
|
|
22
|
+
fail() { echo " FAIL: $1"; FAIL=$((FAIL+1)); }
|
|
23
|
+
pass() { echo " pass: $1"; PASS=$((PASS+1)); }
|
|
24
|
+
|
|
25
|
+
# Helper: pipe $1 through script, capture exit code.
|
|
26
|
+
run_assert() {
|
|
27
|
+
set +e
|
|
28
|
+
printf '%s' "$1" | bash "$SCRIPT" >/dev/null 2>/dev/null
|
|
29
|
+
RC=$?
|
|
30
|
+
set -e
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# ------------------------------------------------------------------------
|
|
34
|
+
# Clean cases — must exit 0.
|
|
35
|
+
# ------------------------------------------------------------------------
|
|
36
|
+
echo "Test 1: empty payload"
|
|
37
|
+
run_assert ""
|
|
38
|
+
[[ "$RC" == "0" ]] && pass "exit 0 on empty" || fail "rc=$RC"
|
|
39
|
+
|
|
40
|
+
echo "Test 2: generic telemetry text (no Linear refs)"
|
|
41
|
+
run_assert "linear-fetch applied"
|
|
42
|
+
[[ "$RC" == "0" ]] && pass "exit 0 on generic" || fail "rc=$RC"
|
|
43
|
+
|
|
44
|
+
echo "Test 3: JSON-like telemetry without Linear refs"
|
|
45
|
+
run_assert '{"rule": "hr-gdpr-gate", "action": "applied", "duration_ms": 12}'
|
|
46
|
+
[[ "$RC" == "0" ]] && pass "exit 0" || fail "rc=$RC"
|
|
47
|
+
|
|
48
|
+
# ------------------------------------------------------------------------
|
|
49
|
+
# Forbidden patterns — must exit 1.
|
|
50
|
+
# ------------------------------------------------------------------------
|
|
51
|
+
echo "Test 4: Linear identifier SOL-39"
|
|
52
|
+
run_assert "telemetry for SOL-39 processed"
|
|
53
|
+
[[ "$RC" == "1" ]] && pass "exit 1 on SOL-39" || fail "rc=$RC"
|
|
54
|
+
|
|
55
|
+
echo "Test 5: Linear identifier ENG-1234"
|
|
56
|
+
run_assert "ENG-1234 in payload"
|
|
57
|
+
[[ "$RC" == "1" ]] && pass "exit 1 on ENG-1234" || fail "rc=$RC"
|
|
58
|
+
|
|
59
|
+
echo "Test 6: uploads.linear.app URL"
|
|
60
|
+
run_assert "see https://uploads.linear.app/TEST-FIXTURE-NOT-REAL.png"
|
|
61
|
+
[[ "$RC" == "1" ]] && pass "exit 1 on CDN URL" || fail "rc=$RC"
|
|
62
|
+
|
|
63
|
+
echo "Test 7: uploads.linear.app case-insensitive"
|
|
64
|
+
run_assert "Uploads.Linear.App/X.PNG"
|
|
65
|
+
[[ "$RC" == "1" ]] && pass "exit 1 on case-insensitive CDN" || fail "rc=$RC"
|
|
66
|
+
|
|
67
|
+
echo "Test 8: UUID-style ID"
|
|
68
|
+
run_assert "issue 9e0a3888-fd38-49cd-87cb-83cdcecca199 done"
|
|
69
|
+
[[ "$RC" == "1" ]] && pass "exit 1 on UUID" || fail "rc=$RC"
|
|
70
|
+
|
|
71
|
+
# ------------------------------------------------------------------------
|
|
72
|
+
# Edge cases — should NOT trigger false positives.
|
|
73
|
+
# ------------------------------------------------------------------------
|
|
74
|
+
echo "Test 9: PR-123 alone should NOT trigger (matches identifier shape but no Linear ref)"
|
|
75
|
+
# Actually PR-123 DOES match [A-Z]{2,}-[0-9]+ — this is the spec's R2
|
|
76
|
+
# false-positive class. The assertion is intentionally conservative:
|
|
77
|
+
# any [A-Z]{2,}-[0-9]+ in telemetry is forbidden, even if it's a GitHub
|
|
78
|
+
# PR reference. Telemetry should use generic strings or specific
|
|
79
|
+
# whitelisted IDs (hashed/anonymized) instead.
|
|
80
|
+
run_assert "see PR-123 for context"
|
|
81
|
+
[[ "$RC" == "1" ]] && pass "exit 1 on PR-123 (conservative)" || fail "rc=$RC"
|
|
82
|
+
|
|
83
|
+
echo "Test 10: lowercase identifier sol-39 should NOT trigger (case-sensitive on prefix)"
|
|
84
|
+
run_assert "sol-39 is lowercase"
|
|
85
|
+
[[ "$RC" == "0" ]] && pass "exit 0 on lowercase" || fail "rc=$RC"
|
|
86
|
+
|
|
87
|
+
# ------------------------------------------------------------------------
|
|
88
|
+
# File-path arg mode.
|
|
89
|
+
# ------------------------------------------------------------------------
|
|
90
|
+
echo "Test 11: file-path argument with clean content"
|
|
91
|
+
tmp=$(_lf_mktemp)
|
|
92
|
+
printf 'linear-fetch applied\n' > "$tmp"
|
|
93
|
+
set +e
|
|
94
|
+
bash "$SCRIPT" "$tmp" >/dev/null 2>/dev/null
|
|
95
|
+
RC=$?
|
|
96
|
+
set -e
|
|
97
|
+
rm -f "$tmp"
|
|
98
|
+
[[ "$RC" == "0" ]] && pass "exit 0 on clean file" || fail "rc=$RC"
|
|
99
|
+
|
|
100
|
+
echo "Test 12: file-path argument with forbidden content"
|
|
101
|
+
tmp=$(_lf_mktemp)
|
|
102
|
+
printf 'SOL-39 in file\n' > "$tmp"
|
|
103
|
+
set +e
|
|
104
|
+
bash "$SCRIPT" "$tmp" >/dev/null 2>/dev/null
|
|
105
|
+
RC=$?
|
|
106
|
+
set -e
|
|
107
|
+
rm -f "$tmp"
|
|
108
|
+
[[ "$RC" == "1" ]] && pass "exit 1 on dirty file" || fail "rc=$RC"
|
|
109
|
+
|
|
110
|
+
# ------------------------------------------------------------------------
|
|
111
|
+
echo
|
|
112
|
+
echo "Results: $PASS passed, $FAIL failed"
|
|
113
|
+
exit $((FAIL > 0 ? 1 : 0))
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Cross-artifact parity test for the load-bearing redaction rail.
|
|
3
|
+
#
|
|
4
|
+
# The plan's User-Brand Impact section names a 2-layer defense (in-skill
|
|
5
|
+
# redaction + CI grep) "with no shared bypass." That guarantee depends on
|
|
6
|
+
# both files covering the SAME set of CDN hostnames. This test asserts
|
|
7
|
+
# the property: for each canonical hostname, both the redaction script
|
|
8
|
+
# and the CI workflow must contain a reference to it.
|
|
9
|
+
#
|
|
10
|
+
# Without this test, the only enforcement is the "Sharp Edges" SKILL.md
|
|
11
|
+
# note that says "update both sites." Reviewer agents flagged the bare-
|
|
12
|
+
# convention approach as schema-drift-prone (learning
|
|
13
|
+
# 2026-05-10-handshake-schema-drift-and-stale-precondition-budgets.md).
|
|
14
|
+
#
|
|
15
|
+
# Update CANONICAL_HOSTS below when LINEAR_CDN_PATTERNS gains a new
|
|
16
|
+
# hostname — the test will then enforce that the workflow grew the
|
|
17
|
+
# matching pattern in the same PR.
|
|
18
|
+
#
|
|
19
|
+
# Run via: bash plugins/soleur/skills/linear-fetch/scripts/parity.test.sh
|
|
20
|
+
|
|
21
|
+
set -eu
|
|
22
|
+
|
|
23
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../scripts" && pwd)"
|
|
24
|
+
REPO_ROOT="$(cd "$SCRIPT_DIR/../../../../.." && pwd)"
|
|
25
|
+
REDACTOR="$SCRIPT_DIR/redact-linear-urls.sh"
|
|
26
|
+
WORKFLOW="$REPO_ROOT/.github/workflows/pr-quality-guards.yml"
|
|
27
|
+
|
|
28
|
+
# Canonical hostname set the redactor and CI grep both must cover.
|
|
29
|
+
# When a new hostname (e.g., cdn.linear.app) is added to LINEAR_CDN_PATTERNS,
|
|
30
|
+
# add it here AND ensure the workflow's pii-grep regex covers it.
|
|
31
|
+
CANONICAL_HOSTS=("uploads.linear.app")
|
|
32
|
+
|
|
33
|
+
PASS=0
|
|
34
|
+
FAIL=0
|
|
35
|
+
fail() { echo " FAIL: $1"; FAIL=$((FAIL+1)); }
|
|
36
|
+
pass() { echo " pass: $1"; PASS=$((PASS+1)); }
|
|
37
|
+
|
|
38
|
+
# Build a case-insensitive bracket pattern for a lowercase hostname.
|
|
39
|
+
# Example: "uploads.linear.app" -> "[Uu][Pp][Ll][Oo][Aa][Dd][Ss]\.[Ll][Ii][Nn][Ee][Aa][Rr]\.[Aa][Pp][Pp]"
|
|
40
|
+
case_bracket_pattern() {
|
|
41
|
+
local host="$1"
|
|
42
|
+
local out=""
|
|
43
|
+
local i c upper
|
|
44
|
+
for ((i = 0; i < ${#host}; i++)); do
|
|
45
|
+
c="${host:$i:1}"
|
|
46
|
+
if [[ "$c" == "." ]]; then
|
|
47
|
+
# The redactor file stores hostnames inside a bash $'...' ANSI-C
|
|
48
|
+
# string, so a literal `.` in the regex is escaped as `\\.` (two
|
|
49
|
+
# backslashes followed by a dot — bash's ANSI-C parser collapses
|
|
50
|
+
# this to one backslash + dot at runtime). We grep the on-disk
|
|
51
|
+
# representation, so we need the double-backslash form here.
|
|
52
|
+
out+='\\.'
|
|
53
|
+
else
|
|
54
|
+
upper="${c^^}"
|
|
55
|
+
out+="[${upper}${c}]"
|
|
56
|
+
fi
|
|
57
|
+
done
|
|
58
|
+
printf '%s' "$out"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# Files exist sanity check.
|
|
62
|
+
[[ -r "$REDACTOR" ]] || { echo "ERROR: redactor not readable at $REDACTOR" >&2; exit 2; }
|
|
63
|
+
[[ -r "$WORKFLOW" ]] || { echo "ERROR: workflow not readable at $WORKFLOW" >&2; exit 2; }
|
|
64
|
+
|
|
65
|
+
for host in "${CANONICAL_HOSTS[@]}"; do
|
|
66
|
+
echo "Host: $host"
|
|
67
|
+
|
|
68
|
+
# Redactor encodes hostnames as [Cc][Hh]... bracketed case-insensitive
|
|
69
|
+
# sequences. Build the expected pattern and grep for it.
|
|
70
|
+
case_pat=$(case_bracket_pattern "$host")
|
|
71
|
+
if grep -qF "$case_pat" "$REDACTOR"; then
|
|
72
|
+
pass "redactor LINEAR_CDN_PATTERNS covers $host (matched: $case_pat)"
|
|
73
|
+
else
|
|
74
|
+
fail "redactor missing $host — expected to find literal '$case_pat'"
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# Workflow uses `grep -iE` so the literal lowercase form is what appears
|
|
78
|
+
# in the regex. (Other prose mentions in comments don't affect the gate's
|
|
79
|
+
# behavior but do satisfy this presence-check, which is fine — the test's
|
|
80
|
+
# job is to assert co-presence, not exhaustive line-by-line equivalence.)
|
|
81
|
+
if grep -qF "$host" "$WORKFLOW"; then
|
|
82
|
+
pass "workflow references $host"
|
|
83
|
+
else
|
|
84
|
+
fail "workflow does NOT reference $host — pii-grep would not catch leaks of this host"
|
|
85
|
+
fi
|
|
86
|
+
done
|
|
87
|
+
|
|
88
|
+
# Test 2: no orphan host in the workflow (a hostname appearing in the
|
|
89
|
+
# workflow's actual regex but NOT in CANONICAL_HOSTS would indicate the
|
|
90
|
+
# parity test itself is stale). Heuristic: extract `[a-z0-9-]+\.linear\.app`
|
|
91
|
+
# literals from the workflow's gate steps and assert each is in
|
|
92
|
+
# CANONICAL_HOSTS.
|
|
93
|
+
echo
|
|
94
|
+
echo "Workflow orphan-host check"
|
|
95
|
+
workflow_hosts=$(grep -oE '[a-z0-9-]+\\\.linear\\\.app' "$WORKFLOW" | sed -E 's/\\\././g' | sort -u || true)
|
|
96
|
+
canonical_set=$(printf '%s\n' "${CANONICAL_HOSTS[@]}" | sort -u)
|
|
97
|
+
orphan=""
|
|
98
|
+
while IFS= read -r wh; do
|
|
99
|
+
[[ -z "$wh" ]] && continue
|
|
100
|
+
if ! printf '%s\n' "$canonical_set" | grep -cFx >/dev/null "$wh"; then
|
|
101
|
+
orphan+="$wh "
|
|
102
|
+
fi
|
|
103
|
+
done <<< "$workflow_hosts"
|
|
104
|
+
if [[ -z "${orphan// /}" ]]; then
|
|
105
|
+
pass "no orphan hosts in workflow"
|
|
106
|
+
else
|
|
107
|
+
fail "workflow references hosts not in CANONICAL_HOSTS: $orphan"
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
echo
|
|
111
|
+
echo "Results: $PASS passed, $FAIL failed"
|
|
112
|
+
exit $((FAIL > 0 ? 1 : 0))
|