From 1b3ace2e7bd6b33792e76f95527129d3ed46cd34 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sat, 15 Aug 2026 02:07:16 -0400 Subject: [PATCH] feat(links): githubRefLink learns the stack kind MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stacks have no HTML page (probed /stacks/N, /stack/N, /pulls/stacks/N against a live stack — all 404; the stack API object carries url but no html_url), so kind 'stack' links the stacks REST URL with a 'stack #N' label — matching the reply-ref-link-guard's kind-aware suggestion. If GitHub ships a stacks UI page, both places swap. --- .gitignore | 106 ++++++++++++++++++++++++++++---- pnpm-lock.yaml | 89 +++++++++++++++------------ pnpm-workspace.yaml | 43 ++++++------- src/links/github.ts | 22 +++++-- test/unit/links/github.test.mts | 11 ++++ 5 files changed, 188 insertions(+), 83 deletions(-) diff --git a/.gitignore b/.gitignore index 7090543c0..c757d7305 100644 --- a/.gitignore +++ b/.gitignore @@ -316,6 +316,7 @@ pnpm-debug.log .agents/ .claude/agents/fleet/code-reviewer.md .claude/agents/fleet/fix.md +.claude/agents/fleet/offload.md .claude/agents/fleet/pr-feedback.md .claude/agents/fleet/refactor-cleaner.md .claude/agents/fleet/security-reviewer.md @@ -381,6 +382,7 @@ pnpm-debug.log .claude/hooks/fleet/_shared/es-polyfills.mts .claude/hooks/fleet/_shared/evasion-normalize.mts .claude/hooks/fleet/_shared/excluded-entry.mts +.claude/hooks/fleet/_shared/excluded-fleet-pack.cjs .claude/hooks/fleet/_shared/failing-tests-ledger.mts .claude/hooks/fleet/_shared/fleet-context.mts .claude/hooks/fleet/_shared/fleet-env.mts @@ -434,6 +436,7 @@ pnpm-debug.log .claude/hooks/fleet/_shared/sfw-ca.mts .claude/hooks/fleet/_shared/shell-command.mts .claude/hooks/fleet/_shared/snapshot-cache-path.cjs +.claude/hooks/fleet/_shared/snapshot-fleet-pack.cjs .claude/hooks/fleet/_shared/snapshot-loader.cjs .claude/hooks/fleet/_shared/snapshot-notes.md .claude/hooks/fleet/_shared/sparkle-auto-update.mts @@ -475,6 +478,7 @@ pnpm-debug.log .claude/hooks/fleet/agents-skills-mirror-nudge/index.mts .claude/hooks/fleet/agents-skills-mirror-nudge/package.json .claude/hooks/fleet/agents-skills-mirror-nudge/tsconfig.json +.claude/hooks/fleet/ai-balancer-proxy-start/index.mts .claude/hooks/fleet/ai-config-drift-nudge/README.md .claude/hooks/fleet/ai-config-drift-nudge/index.mts .claude/hooks/fleet/ai-config-drift-nudge/package.json @@ -635,10 +639,6 @@ pnpm-debug.log .claude/hooks/fleet/compound-lessons-nudge/index.mts .claude/hooks/fleet/compound-lessons-nudge/package.json .claude/hooks/fleet/compound-lessons-nudge/tsconfig.json -.claude/hooks/fleet/concurrent-cargo-build-guard/README.md -.claude/hooks/fleet/concurrent-cargo-build-guard/index.mts -.claude/hooks/fleet/concurrent-cargo-build-guard/package.json -.claude/hooks/fleet/concurrent-cargo-build-guard/tsconfig.json .claude/hooks/fleet/consumer-grep-nudge/README.md .claude/hooks/fleet/consumer-grep-nudge/index.mts .claude/hooks/fleet/consumer-grep-nudge/package.json @@ -838,6 +838,11 @@ pnpm-debug.log .claude/hooks/fleet/minimum-release-age-guard/index.mts .claude/hooks/fleet/minimum-release-age-guard/package.json .claude/hooks/fleet/minimum-release-age-guard/tsconfig.json +.claude/hooks/fleet/mixed-clock-recency-guard/README.md +.claude/hooks/fleet/mixed-clock-recency-guard/index.mts +.claude/hooks/fleet/mixed-clock-recency-guard/package.json +.claude/hooks/fleet/mixed-clock-recency-guard/tsconfig.json +.claude/hooks/fleet/model-fallback/index.mts .claude/hooks/fleet/model-policy-guard/README.md .claude/hooks/fleet/model-policy-guard/index.mts .claude/hooks/fleet/model-policy-guard/model-policy.mts @@ -988,6 +993,7 @@ pnpm-debug.log .claude/hooks/fleet/no-pm-exec-guard/index.mts .claude/hooks/fleet/no-pm-exec-guard/package.json .claude/hooks/fleet/no-pm-exec-guard/tsconfig.json +.claude/hooks/fleet/no-pr-assets-in-branch-guard/index.mts .claude/hooks/fleet/no-pr-from-default-branch-guard/README.md .claude/hooks/fleet/no-pr-from-default-branch-guard/index.mts .claude/hooks/fleet/no-pr-from-default-branch-guard/package.json @@ -1084,6 +1090,7 @@ pnpm-debug.log .claude/hooks/fleet/no-tsx-guard/index.mts .claude/hooks/fleet/no-tsx-guard/package.json .claude/hooks/fleet/no-tsx-guard/tsconfig.json +.claude/hooks/fleet/no-unasked-non-fleet-pr-guard/index.mts .claude/hooks/fleet/no-underscore-ident-guard/README.md .claude/hooks/fleet/no-underscore-ident-guard/index.mts .claude/hooks/fleet/no-underscore-ident-guard/package.json @@ -1651,6 +1658,7 @@ pnpm-debug.log .claude/skills/fleet/designing-interfaces/references/mcp-tools.md .claude/skills/fleet/designing-interfaces/references/motion.md .claude/skills/fleet/designing-interfaces/references/refinement-modes.md +.claude/skills/fleet/designing-interfaces/references/socket-product-styling.md .claude/skills/fleet/designing-interfaces/references/typography.md .claude/skills/fleet/designing-interfaces/references/visual-workflow.md .claude/skills/fleet/diagnosing-bugs/SKILL.md @@ -1725,6 +1733,11 @@ pnpm-debug.log .claude/skills/fleet/prose/references/phrases.md .claude/skills/fleet/prose/references/structures.md .claude/skills/fleet/pushing/SKILL.md +.claude/skills/fleet/recording-ui-walkthroughs/SKILL.md +.claude/skills/fleet/recording-ui-walkthroughs/mocking-vendor-screens.md +.claude/skills/fleet/recording-ui-walkthroughs/npm-mockup.mts +.claude/skills/fleet/recording-ui-walkthroughs/profiles/npm-create-token.json +.claude/skills/fleet/recording-ui-walkthroughs/record-walkthrough.mts .claude/skills/fleet/refreshing-history/SKILL.md .claude/skills/fleet/refreshing-history/run.mts .claude/skills/fleet/releasing-a-package/SKILL.md @@ -1879,6 +1892,8 @@ pnpm-debug.log .config/fleet/oxlint-plugin/fleet/no-namespace-import/package.json .config/fleet/oxlint-plugin/fleet/no-npx-dlx/index.mts .config/fleet/oxlint-plugin/fleet/no-npx-dlx/package.json +.config/fleet/oxlint-plugin/fleet/no-optional-param-before-options-bag/index.mts +.config/fleet/oxlint-plugin/fleet/no-optional-param-before-options-bag/package.json .config/fleet/oxlint-plugin/fleet/no-optional-positional-trap/index.mts .config/fleet/oxlint-plugin/fleet/no-optional-positional-trap/package.json .config/fleet/oxlint-plugin/fleet/no-options-param-mutation/index.mts @@ -1907,6 +1922,8 @@ pnpm-debug.log .config/fleet/oxlint-plugin/fleet/no-required-in-options-bag/package.json .config/fleet/oxlint-plugin/fleet/no-runtime-features-below-engine-floor/index.mts .config/fleet/oxlint-plugin/fleet/no-runtime-features-below-engine-floor/package.json +.config/fleet/oxlint-plugin/fleet/no-shop-metaphor-jargon/index.mts +.config/fleet/oxlint-plugin/fleet/no-shop-metaphor-jargon/package.json .config/fleet/oxlint-plugin/fleet/no-source-content-tests/index.mts .config/fleet/oxlint-plugin/fleet/no-source-content-tests/package.json .config/fleet/oxlint-plugin/fleet/no-source-sniffing/index.mts @@ -2064,6 +2081,7 @@ pnpm-debug.log .config/fleet/oxlint.config.mts .config/fleet/playwright/agent-banner-shield.svg .config/fleet/playwright/agent-banner.js +.config/fleet/playwright/agent-favicon.svg .config/fleet/playwright/challenge-screen.js .config/fleet/playwright/operator-note.js .config/fleet/pnpm-workspace.fleet.yaml @@ -2121,12 +2139,12 @@ pnpm-debug.log .git-hooks/pre-commit .git-hooks/pre-push .github/agent-ci.Dockerfile -.kimi-code/mcp.json +.github/zizmor.yml .mcp.json -assets/badge-follow-bluesky.svg -assets/badge-follow-x.svg -assets/socket-combomark-dark.svg -assets/socket-combomark-light.svg +assets/fleet/badge-follow-bluesky.svg +assets/fleet/badge-follow-x.svg +assets/fleet/socket-combomark-dark.svg +assets/fleet/socket-combomark-light.svg docs/agents.md/fleet/a-peers-claim-is-a-lead.md docs/agents.md/fleet/adversarial-self-review.md docs/agents.md/fleet/agent-delegation.md @@ -2154,7 +2172,6 @@ docs/agents.md/fleet/default-branch-resolution.md docs/agents.md/fleet/delegating-execution.md docs/agents.md/fleet/dependency-spec-pinning.md docs/agents.md/fleet/diagnosing-bugs.md -docs/agents.md/fleet/disabled-seam-pattern.md docs/agents.md/fleet/drift-watch.md docs/agents.md/fleet/ecosystem-impact-measurement.md docs/agents.md/fleet/error-messages.md @@ -2164,6 +2181,7 @@ docs/agents.md/fleet/file-size.md docs/agents.md/fleet/fleet-doctor.md docs/agents.md/fleet/fleet-pack-distribution.md docs/agents.md/fleet/format-before-lint.md +docs/agents.md/fleet/gated-extension-point.md docs/agents.md/fleet/generated-files-are-never-gated.md docs/agents.md/fleet/generated-outputs-are-untracked.md docs/agents.md/fleet/gh-token-hygiene.md @@ -2269,6 +2287,7 @@ docs/references/fleet/sfw-local-install.md opencode.json scripts/fleet/_shared/action-port-map.mts scripts/fleet/_shared/active-run-marker.mts +scripts/fleet/_shared/agent-offload.mts scripts/fleet/_shared/backoff.mts scripts/fleet/_shared/bot-directives.mts scripts/fleet/_shared/cargo-workspaces.mts @@ -2279,19 +2298,29 @@ scripts/fleet/_shared/check-steps-hooks.mts scripts/fleet/_shared/check-steps-paths.mts scripts/fleet/_shared/check-steps-release.mts scripts/fleet/_shared/check-steps.mts +scripts/fleet/_shared/chrome-cdp.mts +scripts/fleet/_shared/claude-model.mts scripts/fleet/_shared/claude-usage-breakdowns.mts scripts/fleet/_shared/claude-usage.mts +scripts/fleet/_shared/codex-model.mts +scripts/fleet/_shared/codex-usage.mts scripts/fleet/_shared/dispatch-scan.mts +scripts/fleet/_shared/fireconnect-claude.mts +scripts/fleet/_shared/fireconnect-config.mts +scripts/fleet/_shared/fireworks-usage.mts scripts/fleet/_shared/fixer-lock.mts scripts/fleet/_shared/fixture-names.mts scripts/fleet/_shared/fleet-canonical-splice.mts scripts/fleet/_shared/fleet-membership.mts scripts/fleet/_shared/fleet-source-present.mts scripts/fleet/_shared/format-scope.mts +scripts/fleet/_shared/gauge-ramp.mts +scripts/fleet/_shared/ghcr-package.mts scripts/fleet/_shared/git-mutex.mts scripts/fleet/_shared/git-porcelain.mts scripts/fleet/_shared/github-raw-url.mts scripts/fleet/_shared/github-tracked-surface.mts +scripts/fleet/_shared/gitmodules-pin-contract.mts scripts/fleet/_shared/gitmodules.mts scripts/fleet/_shared/go-workspaces.mts scripts/fleet/_shared/hook-wiring.mts @@ -2303,18 +2332,29 @@ scripts/fleet/_shared/lint-runners.mts scripts/fleet/_shared/managed-ruleset-identity.mts scripts/fleet/_shared/member-release-probe.mts scripts/fleet/_shared/mirror-lock.mts +scripts/fleet/_shared/model-choices.mts +scripts/fleet/_shared/model-list-cache.mts +scripts/fleet/_shared/model-targets.mts +scripts/fleet/_shared/never-walked-entries.mts scripts/fleet/_shared/odai.mts +scripts/fleet/_shared/offload-spend.mts scripts/fleet/_shared/open-url.mts scripts/fleet/_shared/outbound-surfaces.mts +scripts/fleet/_shared/pack-fetcher.mts scripts/fleet/_shared/pack-files.mts scripts/fleet/_shared/pack-inspect.mts +scripts/fleet/_shared/pack-ref.mts scripts/fleet/_shared/pack-structure.mts +scripts/fleet/_shared/picker.mts scripts/fleet/_shared/pinned-ref.mts scripts/fleet/_shared/playwright-law.mts scripts/fleet/_shared/pnpm-lockfile.mts +scripts/fleet/_shared/poll-with-decay.mts scripts/fleet/_shared/pr-body-law.mts scripts/fleet/_shared/process-lifecycle.mts scripts/fleet/_shared/prose-em-dash.mts +scripts/fleet/_shared/provider-credentials.mts +scripts/fleet/_shared/provider-models.mts scripts/fleet/_shared/quiescence.mts scripts/fleet/_shared/release-channels.mts scripts/fleet/_shared/release-gap-recovery.mts @@ -2323,6 +2363,7 @@ scripts/fleet/_shared/release-version-source.mts scripts/fleet/_shared/repo-checks.mts scripts/fleet/_shared/repo-filter.mts scripts/fleet/_shared/repo-setup.mts +scripts/fleet/_shared/report-url.mts scripts/fleet/_shared/review-comment-law.mts scripts/fleet/_shared/run-main.mts scripts/fleet/_shared/rust-tool-pins.mts @@ -2330,6 +2371,13 @@ scripts/fleet/_shared/scope-flags.mts scripts/fleet/_shared/security-posture-law.mts scripts/fleet/_shared/security-posture-probe.mts scripts/fleet/_shared/spawn-env-scan.mts +scripts/fleet/_shared/spend-projection.mts +scripts/fleet/_shared/spend-report-charts.mts +scripts/fleet/_shared/spend-report-html.mts +scripts/fleet/_shared/spend-report-path.mts +scripts/fleet/_shared/spend-report-theme.mts +scripts/fleet/_shared/swift-targets.mts +scripts/fleet/_shared/synthetic-quota.mts scripts/fleet/_shared/tar-executable.mts scripts/fleet/_shared/template-payload-scope.mts scripts/fleet/_shared/terminal-link.mts @@ -2340,6 +2388,12 @@ scripts/fleet/_shared/unix-path.mts scripts/fleet/_shared/untrack-offenders.mts scripts/fleet/agent-ci-skip-locks.mts scripts/fleet/ai-backends-status.mts +scripts/fleet/ai-balancer/image-assessor.mts +scripts/fleet/ai-balancer/image-inputs.mts +scripts/fleet/ai-balancer/measure-vision-fidelity.mts +scripts/fleet/ai-balancer/pick-image-assessor.mts +scripts/fleet/ai-balancer/proxy.mts +scripts/fleet/ai-balancer/transform-request.mts scripts/fleet/ai-codify/cli.mts scripts/fleet/ai-codify/codify-guidance.mts scripts/fleet/ai-lint-fix.mts @@ -2395,7 +2449,9 @@ scripts/fleet/check/action-pins-are-current.mts scripts/fleet/check/action-ports-are-lock-stepped.mts scripts/fleet/check/actions-are-segmented.mts scripts/fleet/check/actions-secrets-are-declared.mts +scripts/fleet/check/added-statements-are-covered.mts scripts/fleet/check/agent-ci-skip-locks-is-guarded.mts +scripts/fleet/check/agent-offload-routes-are-declared.mts scripts/fleet/check/agents-have-rule-citations.mts scripts/fleet/check/ai-spawns-have-paired-effort.mts scripts/fleet/check/app-token-minters-are-identical.mts @@ -2427,6 +2483,7 @@ scripts/fleet/check/claude-md-citations-resolve.mts scripts/fleet/check/claude-md-repo-section-is-a-bullet-index.mts scripts/fleet/check/claude-md-rules-are-enforced.mts scripts/fleet/check/claude-md-rules-are-informative.mts +scripts/fleet/check/claude-settings-fleet-markers-are-short.mts scripts/fleet/check/comment-markers-are-honeypot-inert.mts scripts/fleet/check/commits-are-signed.mts scripts/fleet/check/commits-have-no-ai-attribution.mts @@ -2457,6 +2514,7 @@ scripts/fleet/check/doc-references-resolve.mts scripts/fleet/check/docs-file-references-resolve.mts scripts/fleet/check/dual-use-declarations-are-complete.mts scripts/fleet/check/egress-allowlist-is-gh-aw-subset.mts +scripts/fleet/check/endpoints-are-outside-china-jurisdiction.mts scripts/fleet/check/enforcers-have-thorough-tests.mts scripts/fleet/check/entry-scripts-are-born-tested.mts scripts/fleet/check/entry-scripts-are-fail-soft.mts @@ -2500,6 +2558,7 @@ scripts/fleet/check/hook-verdicts-are-typed.mts scripts/fleet/check/hooks-have-no-guard-nudge-overlap.mts scripts/fleet/check/human-gate-lanes-are-runnable.mts scripts/fleet/check/ignored-files-are-untracked.mts +scripts/fleet/check/keychain-reads-are-test-safe.mts scripts/fleet/check/lint-configs-protect-verbatim.mts scripts/fleet/check/linters-are-oxlint-oxfmt-only.mts scripts/fleet/check/lock-step-headers-match.mts @@ -2529,6 +2588,7 @@ scripts/fleet/check/oxlint-plugin-loads.mts scripts/fleet/check/pack-bytes-have-no-private-refs.mts scripts/fleet/check/pack-contents-are-clean.mts scripts/fleet/check/pack-imports-are-lib-stable.mts +scripts/fleet/check/pack-reads-are-registry-only.mts scripts/fleet/check/package-files-are-allowlisted.mts scripts/fleet/check/package-manager-auto-update-is-disabled.mts scripts/fleet/check/package-manager-node-is-continuous.mts @@ -2545,6 +2605,7 @@ scripts/fleet/check/paths/scan-workflow.mts scripts/fleet/check/paths/state.mts scripts/fleet/check/paths/types.mts scripts/fleet/check/paths/walk.mts +scripts/fleet/check/payload-importers-are-preserved.mts scripts/fleet/check/pinned-labels-match-shas.mts scripts/fleet/check/platform-tails-match-naming-domain.mts scripts/fleet/check/playwright-launches-are-sanctioned.mts @@ -2575,6 +2636,7 @@ scripts/fleet/check/release-pins-are-canonical.mts scripts/fleet/check/release-publish-scripts-are-conventionally-named.mts scripts/fleet/check/release-tags-are-immutable.mts scripts/fleet/check/release-tags-match-provenance.mts +scripts/fleet/check/report-paths-are-helper-built.mts scripts/fleet/check/researching-recency-contract-is-current.mts scripts/fleet/check/review-stages-are-ordered.mts scripts/fleet/check/root-files-are-sanctioned.mts @@ -2632,6 +2694,7 @@ scripts/fleet/check/vite-is-rolldown-native.mts scripts/fleet/check/vitest-config-is-consolidated.mts scripts/fleet/check/webhooks-are-allowlisted.mts scripts/fleet/check/wheelhouse-controlled-files-are-classified.mts +scripts/fleet/check/workflow-env-is-action-supplied.mts scripts/fleet/check/workflow-envs-have-full-fleet-env.mts scripts/fleet/check/workflow-installs-have-the-socket-token.mts scripts/fleet/check/workflow-scripts-are-explicit-scope.mts @@ -2686,9 +2749,11 @@ scripts/fleet/doctor.mts scripts/fleet/estimate-ai-cost.mts scripts/fleet/external-tools/_shared.mts scripts/fleet/external-tools/add.mts +scripts/fleet/external-tools/clone-install.mts scripts/fleet/external-tools/delete.mts scripts/fleet/external-tools/edit.mts scripts/fleet/external-tools/github.mts +scripts/fleet/external-tools/install-cloned.mts scripts/fleet/external-tools/list.mts scripts/fleet/external-tools/locators.mts scripts/fleet/external-tools/prune.mts @@ -2699,10 +2764,13 @@ scripts/fleet/fetch-fleet-pack.mts scripts/fleet/fix-cpp.mts scripts/fleet/fix-go.mts scripts/fleet/fix-rust.mts +scripts/fleet/fix-swift.mts scripts/fleet/fix.mts +scripts/fleet/fleet-url-action.mts scripts/fleet/fmt-cpp.mts scripts/fleet/fmt-go.mts scripts/fleet/fmt-rust.mts +scripts/fleet/fmt-swift.mts scripts/fleet/format.mts scripts/fleet/fsync-dist.mts scripts/fleet/gen/agents-skills-mirror.mts @@ -2717,11 +2785,14 @@ scripts/fleet/gen/llms-txt.mts scripts/fleet/gen/package-exports.mts scripts/fleet/gen/repo-map.mts scripts/fleet/get-green.mts +scripts/fleet/gh-attach-upload.mts scripts/fleet/gh-auth.mts +scripts/fleet/gh-chrome-cdp.mts scripts/fleet/gh-heartbeat.mts scripts/fleet/git-partial-submodule.mts scripts/fleet/git-partial-submodule/commands.mts scripts/fleet/git-partial-submodule/internal.mts +scripts/fleet/gitmodules-contract.mts scripts/fleet/go-publish.mts scripts/fleet/grant-ruleset-bypass.mts scripts/fleet/grant-ruleset-bypass/messages.mts @@ -2794,6 +2865,7 @@ scripts/fleet/lint-github-settings/types.mts scripts/fleet/lint-go.mts scripts/fleet/lint-pr-comment.mts scripts/fleet/lint-rust.mts +scripts/fleet/lint-swift.mts scripts/fleet/lint.mts scripts/fleet/lockstep-emit-mirror-globs.mts scripts/fleet/lockstep-emit-schema.mts @@ -2818,6 +2890,8 @@ scripts/fleet/npm-auth-browser.mts scripts/fleet/npm-auth-cli.mts scripts/fleet/npm-auth.mts scripts/fleet/npm-publish.mts +scripts/fleet/offload-model.mts +scripts/fleet/offload-providers.mts scripts/fleet/optimizing-submodules/collect-submodule-consumers.mts scripts/fleet/patching-findings/cli.mts scripts/fleet/patching-findings/lib/patch-parse.mts @@ -2832,6 +2906,7 @@ scripts/fleet/pre-push-gate.mts scripts/fleet/preflight.mts scripts/fleet/prepare.mts scripts/fleet/prune-actions-caches.mts +scripts/fleet/prune-fleet-pack-releases.mts scripts/fleet/prune-workflow-runs.mts scripts/fleet/publish-pipeline.mts scripts/fleet/publish-shared.mts @@ -2848,6 +2923,7 @@ scripts/fleet/registry-infra/cargo/staged.mts scripts/fleet/registry-infra/cargo/trusted-publisher.mts scripts/fleet/registry-infra/dry-pack.mts scripts/fleet/registry-infra/gh-auth.mts +scripts/fleet/registry-infra/gh-device-code.mts scripts/fleet/registry-infra/go/shared.mts scripts/fleet/registry-infra/napi-matrix.mts scripts/fleet/registry-infra/npm/access-context-schema.mts @@ -2905,6 +2981,7 @@ scripts/fleet/registry-liveness-gate.d.mts scripts/fleet/registry-liveness-gate.mjs scripts/fleet/registry-publish-date.mts scripts/fleet/release-pipeline.mts +scripts/fleet/release-pipeline/deps.mts scripts/fleet/release-pipeline/gate-runners.mts scripts/fleet/release-pipeline/reconcile-gap-subject.mts scripts/fleet/release-pipeline/reconcile-gap.mts @@ -2913,7 +2990,6 @@ scripts/fleet/release-pipeline/release-runners/promote.mts scripts/fleet/release-pipeline/release-runners/scan-stage.mts scripts/fleet/release-pipeline/release-runners/staging.mts scripts/fleet/release-pipeline/release-runners/verify.mts -scripts/fleet/release-pipeline/seams.mts scripts/fleet/release-pipeline/staged-commit.mts scripts/fleet/release-pipeline/stages.mts scripts/fleet/release-pipeline/state.mts @@ -2947,6 +3023,7 @@ scripts/fleet/scanning-quality/lib/findings.mts scripts/fleet/scanning-vulns/cli.mts scripts/fleet/scanning-vulns/lib/collate.mts scripts/fleet/security.mts +scripts/fleet/serve-reports.mts scripts/fleet/setup/activate-node.mts scripts/fleet/setup/bootstrap-zero-dep-packages.d.mts scripts/fleet/setup/bootstrap-zero-dep-packages.mjs @@ -2955,10 +3032,10 @@ scripts/fleet/setup/claude-config.mts scripts/fleet/setup/developer-tools.mts scripts/fleet/setup/ecosystems.mts scripts/fleet/setup/external-tools.json +scripts/fleet/setup/fireconnect.mts scripts/fleet/setup/go.mts scripts/fleet/setup/hook-snapshot.mts scripts/fleet/setup/index.mts -scripts/fleet/setup/kimi-user-config.mts scripts/fleet/setup/lib/bootstrap-common.d.mts scripts/fleet/setup/lib/bootstrap-common.mjs scripts/fleet/setup/lib/check-firewall.mjs @@ -2976,7 +3053,6 @@ scripts/fleet/setup/lib/platform.mjs scripts/fleet/setup/lib/read-package-integrity.d.mts scripts/fleet/setup/lib/read-package-integrity.mjs scripts/fleet/setup/lib/read-pinned-version.mjs -scripts/fleet/setup/mcp.mts scripts/fleet/setup/python.mts scripts/fleet/setup/refero.mts scripts/fleet/setup/rust.mts @@ -2985,6 +3061,7 @@ scripts/fleet/setup/token.mts scripts/fleet/setup/tools-sfw.d.mts scripts/fleet/setup/tools-sfw.mjs scripts/fleet/setup/tools.mjs +scripts/fleet/setup/url-scheme.mts scripts/fleet/soak-bypass.mts scripts/fleet/soak-rules.mts scripts/fleet/socket-lib-cascade.mts @@ -3008,6 +3085,8 @@ scripts/fleet/socket-wheelhouse-schema/policy.mts scripts/fleet/socket-wheelhouse-schema/testing.mts scripts/fleet/socket-wheelhouse-schema/tooling.mts scripts/fleet/source-pricing-feed.mts +scripts/fleet/spend-forecast.mts +scripts/fleet/spend-report.mts scripts/fleet/spend-statusline.mts scripts/fleet/strip-ai-tags.mts scripts/fleet/sync-gh-aw-action-pins.mts @@ -3078,6 +3157,7 @@ test/fleet/_shared/lib/coverage-env.mts test/fleet/_shared/lib/env.mts test/fleet/_shared/lib/fake-git.mts test/fleet/_shared/lib/git-fixture.mts +test/fleet/_shared/lib/isolate-home-env.mts test/fleet/_shared/lib/matchers.mts test/fleet/_shared/lib/output.mts test/fleet/_shared/lib/package-bin.mts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4df5469d5..73ea90658 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -206,8 +206,8 @@ settings: catalogs: default: '@playwright/mcp': - specifier: 0.0.78 - version: 0.0.78 + specifier: 0.0.79 + version: 0.0.79 '@redwoodjs/agent-ci': specifier: 0.17.1 version: 0.17.1 @@ -329,8 +329,8 @@ catalogs: specifier: 4.0.2 version: 4.0.2 taze: - specifier: 19.17.2 - version: 19.17.2 + specifier: 20.0.0 + version: 20.0.0 typescript: specifier: 7.0.2 version: 7.0.2 @@ -374,7 +374,7 @@ overrides: ssri@>=12: 13.0.1 string-width@>=5: 8.2.2 tinyexec: 1.3.0 - typebox: 1.3.10 + typebox: 1.3.11 undici@<6: 6.28.0 update-notifier@>=4.0.0: 7.3.1 uuid: 11.1.1 @@ -476,7 +476,7 @@ patchedDependencies: minipass-sized@1.0.3: 2048620f836b8d07ca6b41a3500944fe7a43fb7542aa6d45bceb405afa513738 node-gyp@12.4.0: 140ba43d43d74f7d3577feb3f8a6efad544dbb0059784102b144a0e2daa437f9 pony-cause@2.1.11: 39b2eb2567818b7c60126d03e252dbbabd8738082fca850582300d45b0a8cfb8 - taze@19.17.2: 7c18a31c38b364e6289a527b92d7fc919760b2cb9795dc8e5dc11fd02b8498f6 + taze@20.0.0: c86e6ad40e739f1381b0d847ea27f334a26a834a7c837d0406ffdfed85f98f9a importers: @@ -526,7 +526,7 @@ importers: version: 0.5.1220 '@playwright/mcp': specifier: 'catalog:' - version: 0.0.78 + version: 0.0.79 '@redwoodjs/agent-ci': specifier: 'catalog:' version: 0.17.1(supports-color@10.2.2) @@ -754,7 +754,7 @@ importers: version: 3.2.0 taze: specifier: 'catalog:' - version: 19.17.2(patch_hash=7c18a31c38b364e6289a527b92d7fc919760b2cb9795dc8e5dc11fd02b8498f6) + version: 20.0.0(patch_hash=c86e6ad40e739f1381b0d847ea27f334a26a834a7c837d0406ffdfed85f98f9a) terminal-link: specifier: 2.1.1 version: 2.1.1 @@ -762,8 +762,8 @@ importers: specifier: 2.30.1 version: 2.30.1(typescript@7.0.2) typebox: - specifier: 1.3.10 - version: 1.3.10 + specifier: 1.3.11 + version: 1.3.11 typescript: specifier: 'catalog:' version: 7.0.2 @@ -3034,6 +3034,8 @@ importers: .config/fleet/oxlint-plugin/fleet/no-runtime-features-below-engine-floor: {} + .config/fleet/oxlint-plugin/fleet/no-shop-metaphor-jargon: {} + .config/fleet/oxlint-plugin/fleet/no-source-content-tests: {} .config/fleet/oxlint-plugin/fleet/no-source-sniffing: {} @@ -4069,8 +4071,8 @@ packages: engines: {node: '>=16'} hasBin: true - '@playwright/mcp@0.0.78': - resolution: {integrity: sha512-XLTUeA6mEN9sQ+hJ4dfG8EIkDbxS0K3Trc2RBkUJuf02TgE2FQRNTMtq/aJfhyRMINsRl/Ybc4sxcWLtFn4/TQ==} + '@playwright/mcp@0.0.79': + resolution: {integrity: sha512-VpqD4a3vFyGQMY9sh3UJiO6wjcurggkljKfAyCHL0QWGY5m6Ehr3MNsAAHPDHO//n13g0PCjpHatAOiulrqdZQ==} engines: {node: '>=18'} hasBin: true @@ -4440,6 +4442,9 @@ packages: '@types/node@26.1.2': resolution: {integrity: sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==} + '@types/node@26.2.0': + resolution: {integrity: sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==} + '@types/responselike@1.0.3': resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} @@ -6323,18 +6328,18 @@ packages: resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} engines: {node: '>=16.20.0'} - playwright-core@1.62.0-alpha-1783623505000: - resolution: {integrity: sha512-CPJZdsA/KGT2QQlekiV6Wt+QlQrZHVSZ6oiNtOI/bYYOIVLM8jfKGWTM4zQiyd4UN+40Cq4cA6lxmZHZbtPvJQ==} + playwright-core@1.62.1: + resolution: {integrity: sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==} engines: {node: '>=20'} hasBin: true - playwright-core@1.62.1: - resolution: {integrity: sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==} + playwright-core@1.63.0-alpha-2026-08-05: + resolution: {integrity: sha512-YussvUybTfBtyYbGXWh43f+5kNP03wg98M6mu4DphYET7PSbNVajsdLGjWE1xrsjqOw32i2wFlRP7U5mcOpMZg==} engines: {node: '>=20'} hasBin: true - playwright@1.62.0-alpha-1783623505000: - resolution: {integrity: sha512-6KV9h4PP3hqu4NaGdxxcijWfYh9LJcFI/R2sP4TTC4I5cFo3oRawN0ETlW5MkE3cQEgKhhoj0KUNz4sfpCT0Tg==} + playwright@1.63.0-alpha-2026-08-05: + resolution: {integrity: sha512-zbGZUK+JYkoDV3cUgfvh2czTBJL34Gmz5gHVI25xiIpvYSR17Q1M7TS8hnwECUe+IkKaeXbKrSyJTyogm2DVWw==} engines: {node: '>=20'} hasBin: true @@ -6652,8 +6657,8 @@ packages: resolution: {integrity: sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==} engines: {node: '>=18'} - taze@19.17.2: - resolution: {integrity: sha512-1WH+LUf5H0R07EF606fuP5TuHPVvtrMIPpn69EkqaOVJYg0foL8xnD+lEs0s19Zfmplul5nRd3TpbbF0twXCkw==} + taze@20.0.0: + resolution: {integrity: sha512-aygXyZ0wQrQGjuclEWE1qSyxnlVERKO51Re+xhHwgS0Ml2dqCIXpMjRrUdV1thJFOUwKJj9XPvv9ZVlAaV0CWg==} hasBin: true teex@1.0.1: @@ -6764,8 +6769,8 @@ packages: resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} engines: {node: '>= 18'} - typebox@1.3.10: - resolution: {integrity: sha512-L0MT00X96q0P30f1NrGULgaSbmu8hfTjWbLULeVoM+j5u0jR5wyefoDquX2NmRa39f0KiNIBo1wWSaVvHJTZlA==} + typebox@1.3.11: + resolution: {integrity: sha512-tZGKIS02Opbh4EYMmAEVuXl+y3EQJ9ZlkitLZ1CmFCY4ZOqr/xWR9dDSCFmIjNDICGMWkOqMh6WxGTyRXqcSGQ==} typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} @@ -6856,8 +6861,8 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - verkit@0.3.1: - resolution: {integrity: sha512-w2Eo8LSIIoW7qxNBzT7/17k+bh8plXo7G3dHjEIDqPlnluhzaxr9JX8F28VSYEtDvc1/a3WBDih6xNUZseebXg==} + verkit@0.3.2: + resolution: {integrity: sha512-zj/ob3UsvJGN0whEAKFp53REA5X66hvffVqoCtVQAakJKnKlH+/PcOfMoFwIG/o4rElqLv/ycAFlx8ZlXUorCg==} engines: {node: '>=18.12.0'} vite@8.2.0: @@ -7771,10 +7776,10 @@ snapshots: '@perryts/perry-linux-x64-musl': 0.5.1220 '@perryts/perry-win32-x64': 0.5.1220 - '@playwright/mcp@0.0.78': + '@playwright/mcp@0.0.79': dependencies: - playwright: 1.62.0-alpha-1783623505000 - playwright-core: 1.62.0-alpha-1783623505000 + playwright: 1.63.0-alpha-2026-08-05 + playwright-core: 1.63.0-alpha-2026-08-05 '@polka/url@1.0.0-next.29(patch_hash=60d82e95c5e67e66c41fe2987ddd4fc3f4992f12158e5c56838e7682e6ef72ea)': {} @@ -8007,7 +8012,7 @@ snapshots: dependencies: '@types/http-cache-semantics': 4.2.0 '@types/keyv': 3.1.4 - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/responselike': 1.0.3 '@types/chai@5.2.3': @@ -8035,7 +8040,7 @@ snapshots: '@types/keyv@3.1.4': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/mdast@4.0.4': dependencies: @@ -8047,9 +8052,13 @@ snapshots: dependencies: undici-types: 8.3.0 + '@types/node@26.2.0': + dependencies: + undici-types: 8.3.0 + '@types/responselike@1.0.3': dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@types/semver@7.8.0': {} @@ -9217,7 +9226,7 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 merge-stream: 2.0.0 supports-color: 10.2.2 @@ -10119,13 +10128,13 @@ snapshots: pkce-challenge@5.0.1: {} - playwright-core@1.62.0-alpha-1783623505000: {} - playwright-core@1.62.1: {} - playwright@1.62.0-alpha-1783623505000: + playwright-core@1.63.0-alpha-2026-08-05: {} + + playwright@1.63.0-alpha-2026-08-05: dependencies: - playwright-core: 1.62.0-alpha-1783623505000 + playwright-core: 1.63.0-alpha-2026-08-05 optionalDependencies: fsevents: 2.3.2 @@ -10182,7 +10191,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.1 - '@types/node': 26.1.2 + '@types/node': 26.2.0 long: 5.3.2 proxy-addr@2.0.7: @@ -10500,7 +10509,7 @@ snapshots: minizlib: 3.1.0 yallist: 5.0.0 - taze@19.17.2(patch_hash=7c18a31c38b364e6289a527b92d7fc919760b2cb9795dc8e5dc11fd02b8498f6): + taze@20.0.0(patch_hash=c86e6ad40e739f1381b0d847ea27f334a26a834a7c837d0406ffdfed85f98f9a): dependencies: '@antfu/ni': 30.3.0 '@henrygd/queue': 1.2.0 @@ -10514,7 +10523,7 @@ snapshots: tinyexec: 1.3.0 tinyglobby: 0.2.17 unconfig: 7.5.0 - verkit: 0.3.1 + verkit: 0.3.2 yaml: 2.9.0 teex@1.0.1: @@ -10630,7 +10639,7 @@ snapshots: media-typer: 1.1.0 mime-types: 3.0.2 - typebox@1.3.10: {} + typebox@1.3.11: {} typescript@5.9.3: {} @@ -10736,7 +10745,7 @@ snapshots: vary@1.1.2: {} - verkit@0.3.1: {} + verkit@0.3.2: {} vite@8.2.0(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(yaml@2.9.0): dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4323a7407..86cc95f21 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -12,11 +12,22 @@ packages: - '.claude/hooks/fleet/*' - '.claude/hooks/repo/*' enableGlobalVirtualStore: true - -# Catalog entries shared across hook workspaces. The hooks live in -# `.claude/hooks/*` and depend on the same Socket fleet packages the -# repo itself ships. Pinning them here keeps the entire hook tree in -# lockstep with the parent without each hook duplicating literal pins. + # vite 8.1.0 — dev dep (vitest's bundler). 8.1 adds experimental.bundledDev + # (NOT adopted — experimental, and the fleet runs stable-only). Published + # within the 7-day soak; exact-pinned so a future 8.1.1 still soaks. + # taze 19.16.0 — the dep updater itself; forced ahead of the soak by owner + # directive so the regenerated single-registry patch (patchedDependencies) + # tracks the current release. Exact-pinned so a future version re-soaks. + # shadscan 0.2.0 — deterministic UI audits for shadcn apps, used by the + # design skills; forced ahead of the soak by owner directive. Exact-pinned + # so a future version re-soaks. + # verkit — new dev-only transitive of taze 19.16.0 (same owner directive); + # exact-pinned so future versions re-soak. + # js-yaml 5.2.2 — HIGH security fix, GHSA-pm4m-ph32-ghv5: exponential parse + # time in flow collections. The canonical overrides entry forces it past + # markdownlint-cli2 0.23.1's vulnerable 5.2.1 exact-pin. Soak bypassed per + # the high-severity security exception; exact-pinned so a future version + # re-soaks. catalog: # agent-ci runs a repo's GitHub Actions workflows locally in Docker so a # change can be validated before it's pushed (see the `agent-ci` skill). @@ -33,6 +44,7 @@ catalog: # the soak window, so it carries a minimumReleaseAgeExclude entry below. '@shadscan/cli': 0.10.0 '@sinclair/typebox': 0.34.52 + 'ecc-agentshield': 1.4.0 # typebox 1.x — the unscoped rewrite of @sinclair/typebox. Both names are # pinned while the fleet migrates; the 0.x entry is deleted once no member # imports the scoped name. 1.3.10 is inside the 7-day soak, so it carries a @@ -57,7 +69,7 @@ catalog: '@socketsecurity/sdk': 4.1.4 '@socketsecurity/sdk-stable': 'npm:@socketsecurity/sdk@4.1.4' '@types/mdast': 4.0.4 - '@types/node': 26.2.0 + '@types/node': 26.1.2 '@types/semver': 7.8.0 '@types/shell-quote': 1.7.5 'compromise': 14.16.0 @@ -115,6 +127,7 @@ catalog: # @rolldown/binding-* + @oxc-project/types stay as soak-excluded # transitives (consumers depend on `rolldown` only). 'regjsparser': 0.13.2 + 'rolldown': 1.2.3 'semver': 7.8.5 'shell-quote': 1.10.0 'taze': 20.0.0 @@ -137,10 +150,8 @@ catalog: # @ultrathink/acorn-wasm name is npm-deprecated. '@vitiate/core': 0.3.1 '@typescript/native-preview': 7.0.0-dev.20260510.1 - 'ecc-agentshield': 1.4.0 'html5parser': 3.0.0 'npm-run-all2': 9.0.3 - 'rolldown': 1.2.3 # Source of truth for CI-provider + AI-agent env-var detection. devDep only: # the build-time codemod inlines its isCI/isAgent boolean expressions into # dist, so it never enters the runtime dependency tree. Published 2026-04-15, @@ -233,22 +244,6 @@ minimumReleaseAgeExclude: # npm freshpub typosquats, not a first-party oxc release. - '@sdxgen/*' - 'sdxgen' - # vite 8.1.0 — dev dep (vitest's bundler). 8.1 adds experimental.bundledDev - # (NOT adopted — experimental, and the fleet runs stable-only). Published - # within the 7-day soak; exact-pinned so a future 8.1.1 still soaks. - # taze 19.16.0 — the dep updater itself; forced ahead of the soak by owner - # directive so the regenerated single-registry patch (patchedDependencies) - # tracks the current release. Exact-pinned so a future version re-soaks. - # shadscan 0.2.0 — deterministic UI audits for shadcn apps, used by the - # design skills; forced ahead of the soak by owner directive. Exact-pinned - # so a future version re-soaks. - # verkit — new dev-only transitive of taze 19.16.0 (same owner directive); - # exact-pinned so future versions re-soak. - # js-yaml 5.2.2 — HIGH security fix, GHSA-pm4m-ph32-ghv5: exponential parse - # time in flow collections. The canonical overrides entry forces it past - # markdownlint-cli2 0.23.1's vulnerable 5.2.1 exact-pin. Soak bypassed per - # the high-severity security exception; exact-pinned so a future version - # re-soaks. # Refuse transitive (sub-) deps declared via git/tarball/local-tarball # specs. Direct git deps in this repo are still allowed; this only diff --git a/src/links/github.ts b/src/links/github.ts index d72f2cfce..4b3ba7470 100644 --- a/src/links/github.ts +++ b/src/links/github.ts @@ -25,23 +25,26 @@ import { getRepoUrlDetails } from '../packages/specs' * githubRefLink('https://github.com/PerryTS/perry', 793, 'issues') * // '[#793](https://github.com/PerryTS/perry/issues/793)' * + * githubRefLink('https://github.com/PerryTS/perry', 178, 'stack') + * // '[stack #178](https://api.github.com/repos/PerryTS/perry/stacks/178)' + * * githubRefLink('not-a-repo-url', 42) * // '#42' * ``` * * @param repoUrl - Repository URL (git/https form, e.g. from package.json * `repository.url`). - * @param n - Pull request or issue number. - * @param kind - `'pull'` for a PR link (default) or `'issues'` for an issue - * link. + * @param n - Pull request, issue, or stack number. + * @param kind - `'pull'` for a PR link (default), `'issues'` for an issue + * link, or `'stack'` for a stacked-PR link. * - * @returns A Markdown link `[#N](…)`, or the bare `#N` when `repoUrl` is - * unparseable. + * @returns A Markdown link `[#N](…)` (or `[stack #N](…)` for stacks), or the + * bare `#N` when `repoUrl` is unparseable. */ export function githubRefLink( repoUrl: string, n: number, - kind: 'pull' | 'issues' = 'pull', + kind: 'pull' | 'issues' | 'stack' = 'pull', ): string { const { project, user } = getRepoUrlDetails(repoUrl) // Refuse to emit a malformed `https://github.com///pull/N` when the URL @@ -49,5 +52,12 @@ export function githubRefLink( if (!user || !project) { return `#${n}` } + if (kind === 'stack') { + // Stacks have no HTML page (probed /stacks/N, /stack/N, /pulls/stacks/N + // against a live stack — all 404; the stack API object carries `url` + // but no `html_url`), so the REST URL is the canonical resolvable + // surface. If GitHub ships a stacks UI page, point this at it instead. + return `[stack #${n}](https://api.github.com/repos/${user}/${project}/stacks/${n})` + } return `[#${n}](https://github.com/${user}/${project}/${kind}/${n})` } diff --git a/test/unit/links/github.test.mts b/test/unit/links/github.test.mts index cf38dc75b..d45d84e06 100644 --- a/test/unit/links/github.test.mts +++ b/test/unit/links/github.test.mts @@ -27,6 +27,17 @@ describe('links/github — githubRefLink', () => { ) }) + it('builds a stack link to the stacks REST URL when kind is "stack"', () => { + // Stacks have no HTML page — the api.github.com URL is the canonical + // resolvable surface, and the label carries the `stack` prefix so the + // target isn't mistaken for a PR. + expect( + githubRefLink('https://github.com/PerryTS/perry', 178, 'stack'), + ).toBe( + '[stack #178](https://api.github.com/repos/PerryTS/perry/stacks/178)', + ) + }) + it('degrades to bare #N when the URL is unparseable', () => { expect(githubRefLink('not-a-repo-url', 42)).toBe('#42') // scp-style git@ URLs are not parsed by getRepoUrlDetails, so they also