@m2-ai/lattice-cli 0.0.0-stage → 0.8.7
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/DISCLOSURE +1 -0
- package/README.md +118 -2
- package/bundles/expo-mobile/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
- package/bundles/expo-mobile/.agents/skills/lattice-release-manager/SKILL.md +29 -0
- package/bundles/expo-mobile/.agents/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/expo-mobile/.claude/agents/lattice-feature-agent.md +10 -0
- package/bundles/expo-mobile/.claude/agents/lattice-release-manager.md +9 -0
- package/bundles/expo-mobile/.claude/hooks/README.md +9 -0
- package/bundles/expo-mobile/.claude/hooks/pre-commit-verify.mjs +10 -0
- package/bundles/expo-mobile/.claude/hooks/pre-tool-use.mjs +51 -0
- package/bundles/expo-mobile/.claude/rules/lattice-core.md +20 -0
- package/bundles/expo-mobile/.claude/settings.json +38 -0
- package/bundles/expo-mobile/.claude/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/expo-mobile/.codex/agents/lattice-feature-agent.toml +9 -0
- package/bundles/expo-mobile/.codex/agents/lattice-release-manager.toml +9 -0
- package/bundles/expo-mobile/.cursor/mcp.json +34 -0
- package/bundles/expo-mobile/.cursor/rules/lattice-core.mdc +35 -0
- package/bundles/expo-mobile/.cursor/rules.md +94 -0
- package/bundles/expo-mobile/.env.example +19 -0
- package/bundles/expo-mobile/.github/PULL_REQUEST_TEMPLATE.md +42 -0
- package/bundles/expo-mobile/.github/agents/lattice-feature-agent.agent.md +7 -0
- package/bundles/expo-mobile/.github/agents/lattice-release-manager.agent.md +7 -0
- package/bundles/expo-mobile/.github/copilot-instructions.md +37 -0
- package/bundles/expo-mobile/.github/instructions/lattice-core.instructions.md +11 -0
- package/bundles/expo-mobile/.github/workflows/ci.yml +26 -0
- package/bundles/expo-mobile/.gitmessage +24 -0
- package/bundles/expo-mobile/.lattice/config.json +9 -0
- package/bundles/expo-mobile/.lattice/dependency-security.json +91 -0
- package/bundles/expo-mobile/.lattice/prompts/01-feature.md +36 -0
- package/bundles/expo-mobile/.lattice/prompts/02-bugfix.md +32 -0
- package/bundles/expo-mobile/.lattice/prompts/03-refactor.md +30 -0
- package/bundles/expo-mobile/.lattice/prompts/04-test.md +31 -0
- package/bundles/expo-mobile/.lattice/prompts/05-polish.md +38 -0
- package/bundles/expo-mobile/.lattice/prompts/06-security.md +32 -0
- package/bundles/expo-mobile/.lattice/release-workflow.json +55 -0
- package/bundles/expo-mobile/.lattice/schemas/feature-handoff.schema.json +264 -0
- package/bundles/expo-mobile/.lattice/templates/feature-handoff.json +52 -0
- package/bundles/expo-mobile/.mcp.json +35 -0
- package/bundles/expo-mobile/AGENTS.md +58 -0
- package/bundles/expo-mobile/CLAUDE.md +75 -0
- package/bundles/expo-mobile/PROJECT_GUIDE.md +299 -0
- package/bundles/expo-mobile/README.md +39 -0
- package/bundles/expo-mobile/__tests__/home.test.tsx +22 -0
- package/bundles/expo-mobile/app/_layout.tsx +20 -0
- package/bundles/expo-mobile/app/index.tsx +72 -0
- package/bundles/expo-mobile/app.json +33 -0
- package/bundles/expo-mobile/components/ui/Button.tsx +75 -0
- package/bundles/expo-mobile/components/ui/Input.tsx +50 -0
- package/bundles/expo-mobile/components/ui/index.ts +2 -0
- package/bundles/expo-mobile/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
- package/bundles/expo-mobile/docs/rules/codex.md +62 -0
- package/bundles/expo-mobile/eslint.config.js +7 -0
- package/bundles/expo-mobile/lib/supabase/client.ts +22 -0
- package/bundles/expo-mobile/lib/supabase/realtime.ts +10 -0
- package/bundles/expo-mobile/lib/supabase/storage.ts +6 -0
- package/bundles/expo-mobile/package.json +65 -0
- package/bundles/expo-mobile/plugins/with-lattice-commons-io.cjs +42 -0
- package/bundles/expo-mobile/prompts/01-feature-implementation.md +48 -0
- package/bundles/expo-mobile/prompts/02-bug-fix.md +43 -0
- package/bundles/expo-mobile/prompts/03-safe-refactor.md +38 -0
- package/bundles/expo-mobile/prompts/04-test-first.md +41 -0
- package/bundles/expo-mobile/prompts/05-ui-polish.md +44 -0
- package/bundles/expo-mobile/prompts/06-security-review.md +39 -0
- package/bundles/expo-mobile/prompts/quality.md +143 -0
- package/bundles/expo-mobile/supabase/migrations/001_initial_schema.sql +66 -0
- package/bundles/expo-mobile/tsconfig.json +21 -0
- package/bundles/expo-mobile/types/database.types.ts +76 -0
- package/bundles/expo-mobile/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
- package/bundles/expo-supabase/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
- package/bundles/expo-supabase/.agents/skills/lattice-release-manager/SKILL.md +29 -0
- package/bundles/expo-supabase/.agents/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/expo-supabase/.claude/agents/lattice-feature-agent.md +10 -0
- package/bundles/expo-supabase/.claude/agents/lattice-release-manager.md +9 -0
- package/bundles/expo-supabase/.claude/hooks/README.md +9 -0
- package/bundles/expo-supabase/.claude/hooks/pre-commit-verify.mjs +10 -0
- package/bundles/expo-supabase/.claude/hooks/pre-tool-use.mjs +51 -0
- package/bundles/expo-supabase/.claude/rules/lattice-core.md +20 -0
- package/bundles/expo-supabase/.claude/settings.json +38 -0
- package/bundles/expo-supabase/.claude/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/expo-supabase/.codex/agents/lattice-feature-agent.toml +9 -0
- package/bundles/expo-supabase/.codex/agents/lattice-release-manager.toml +9 -0
- package/bundles/expo-supabase/.cursor/mcp.json +34 -0
- package/bundles/expo-supabase/.cursor/rules/lattice-core.mdc +35 -0
- package/bundles/expo-supabase/.cursor/rules.md +94 -0
- package/bundles/expo-supabase/.env.example +12 -0
- package/bundles/expo-supabase/.github/PULL_REQUEST_TEMPLATE.md +42 -0
- package/bundles/expo-supabase/.github/agents/lattice-feature-agent.agent.md +7 -0
- package/bundles/expo-supabase/.github/agents/lattice-release-manager.agent.md +7 -0
- package/bundles/expo-supabase/.github/copilot-instructions.md +37 -0
- package/bundles/expo-supabase/.github/instructions/lattice-core.instructions.md +11 -0
- package/bundles/expo-supabase/.github/workflows/ci.yml +26 -0
- package/bundles/expo-supabase/.gitmessage +24 -0
- package/bundles/expo-supabase/.lattice/config.json +9 -0
- package/bundles/expo-supabase/.lattice/dependency-security.json +91 -0
- package/bundles/expo-supabase/.lattice/prompts/01-feature.md +36 -0
- package/bundles/expo-supabase/.lattice/prompts/02-bugfix.md +32 -0
- package/bundles/expo-supabase/.lattice/prompts/03-refactor.md +30 -0
- package/bundles/expo-supabase/.lattice/prompts/04-test.md +31 -0
- package/bundles/expo-supabase/.lattice/prompts/05-polish.md +38 -0
- package/bundles/expo-supabase/.lattice/prompts/06-security.md +32 -0
- package/bundles/expo-supabase/.lattice/release-workflow.json +55 -0
- package/bundles/expo-supabase/.lattice/schemas/feature-handoff.schema.json +264 -0
- package/bundles/expo-supabase/.lattice/templates/feature-handoff.json +52 -0
- package/bundles/expo-supabase/.mcp.json +35 -0
- package/bundles/expo-supabase/AGENTS.md +58 -0
- package/bundles/expo-supabase/CLAUDE.md +75 -0
- package/bundles/expo-supabase/PROJECT_GUIDE.md +201 -0
- package/bundles/expo-supabase/README.md +38 -0
- package/bundles/expo-supabase/__tests__/home.test.tsx +22 -0
- package/bundles/expo-supabase/app/_layout.tsx +14 -0
- package/bundles/expo-supabase/app/index.tsx +72 -0
- package/bundles/expo-supabase/app.json +33 -0
- package/bundles/expo-supabase/components/ui/Button.tsx +75 -0
- package/bundles/expo-supabase/components/ui/Input.tsx +50 -0
- package/bundles/expo-supabase/components/ui/index.ts +2 -0
- package/bundles/expo-supabase/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
- package/bundles/expo-supabase/docs/rules/codex.md +62 -0
- package/bundles/expo-supabase/eslint.config.js +7 -0
- package/bundles/expo-supabase/lib/supabase/client.ts +22 -0
- package/bundles/expo-supabase/lib/supabase/realtime.ts +10 -0
- package/bundles/expo-supabase/lib/supabase/storage.ts +6 -0
- package/bundles/expo-supabase/package.json +60 -0
- package/bundles/expo-supabase/plugins/with-lattice-commons-io.cjs +42 -0
- package/bundles/expo-supabase/prompts/01-feature-implementation.md +8 -0
- package/bundles/expo-supabase/prompts/02-bug-fix.md +9 -0
- package/bundles/expo-supabase/prompts/03-safe-refactor.md +8 -0
- package/bundles/expo-supabase/prompts/04-test-first.md +7 -0
- package/bundles/expo-supabase/prompts/05-ui-polish.md +7 -0
- package/bundles/expo-supabase/prompts/06-security-review.md +7 -0
- package/bundles/expo-supabase/prompts/quality.md +143 -0
- package/bundles/expo-supabase/supabase/migrations/001_initial_schema.sql +66 -0
- package/bundles/expo-supabase/tsconfig.json +21 -0
- package/bundles/expo-supabase/types/database.types.ts +76 -0
- package/bundles/expo-supabase/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
- package/bundles/nextjs-landing/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
- package/bundles/nextjs-landing/.agents/skills/lattice-release-manager/SKILL.md +29 -0
- package/bundles/nextjs-landing/.agents/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/nextjs-landing/.claude/agents/lattice-feature-agent.md +10 -0
- package/bundles/nextjs-landing/.claude/agents/lattice-release-manager.md +9 -0
- package/bundles/nextjs-landing/.claude/hooks/README.md +9 -0
- package/bundles/nextjs-landing/.claude/hooks/pre-commit-verify.mjs +10 -0
- package/bundles/nextjs-landing/.claude/hooks/pre-tool-use.mjs +51 -0
- package/bundles/nextjs-landing/.claude/rules/lattice-core.md +20 -0
- package/bundles/nextjs-landing/.claude/settings.json +38 -0
- package/bundles/nextjs-landing/.claude/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/nextjs-landing/.codex/agents/lattice-feature-agent.toml +9 -0
- package/bundles/nextjs-landing/.codex/agents/lattice-release-manager.toml +9 -0
- package/bundles/nextjs-landing/.cursor/mcp.json +34 -0
- package/bundles/nextjs-landing/.cursor/rules/lattice-core.mdc +35 -0
- package/bundles/nextjs-landing/.cursor/rules.md +95 -0
- package/bundles/nextjs-landing/.env.example +24 -0
- package/bundles/nextjs-landing/.github/PULL_REQUEST_TEMPLATE.md +42 -0
- package/bundles/nextjs-landing/.github/agents/lattice-feature-agent.agent.md +7 -0
- package/bundles/nextjs-landing/.github/agents/lattice-release-manager.agent.md +7 -0
- package/bundles/nextjs-landing/.github/copilot-instructions.md +37 -0
- package/bundles/nextjs-landing/.github/instructions/lattice-core.instructions.md +11 -0
- package/bundles/nextjs-landing/.github/workflows/ci.yml +26 -0
- package/bundles/nextjs-landing/.gitmessage +24 -0
- package/bundles/nextjs-landing/.lattice/config.json +9 -0
- package/bundles/nextjs-landing/.lattice/dependency-security.json +46 -0
- package/bundles/nextjs-landing/.lattice/prompts/01-feature.md +36 -0
- package/bundles/nextjs-landing/.lattice/prompts/02-bugfix.md +32 -0
- package/bundles/nextjs-landing/.lattice/prompts/03-refactor.md +30 -0
- package/bundles/nextjs-landing/.lattice/prompts/04-test.md +31 -0
- package/bundles/nextjs-landing/.lattice/prompts/05-polish.md +38 -0
- package/bundles/nextjs-landing/.lattice/prompts/06-security.md +32 -0
- package/bundles/nextjs-landing/.lattice/release-workflow.json +55 -0
- package/bundles/nextjs-landing/.lattice/schemas/feature-handoff.schema.json +264 -0
- package/bundles/nextjs-landing/.lattice/templates/feature-handoff.json +52 -0
- package/bundles/nextjs-landing/.mcp.json +35 -0
- package/bundles/nextjs-landing/AGENTS.md +58 -0
- package/bundles/nextjs-landing/CLAUDE.md +76 -0
- package/bundles/nextjs-landing/PROJECT_GUIDE.md +216 -0
- package/bundles/nextjs-landing/README.md +39 -0
- package/bundles/nextjs-landing/app/api/example/[id]/route.ts +34 -0
- package/bundles/nextjs-landing/app/api/example/route.ts +24 -0
- package/bundles/nextjs-landing/app/api/health/route.ts +8 -0
- package/bundles/nextjs-landing/app/global-error.tsx +17 -0
- package/bundles/nextjs-landing/app/globals.css +55 -0
- package/bundles/nextjs-landing/app/layout.tsx +22 -0
- package/bundles/nextjs-landing/app/page.tsx +42 -0
- package/bundles/nextjs-landing/components/ui/button.tsx +39 -0
- package/bundles/nextjs-landing/components/ui/card.tsx +53 -0
- package/bundles/nextjs-landing/components/ui/index.ts +4 -0
- package/bundles/nextjs-landing/components/ui/input.tsx +23 -0
- package/bundles/nextjs-landing/components/ui/spinner.tsx +22 -0
- package/bundles/nextjs-landing/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
- package/bundles/nextjs-landing/docs/rules/codex.md +62 -0
- package/bundles/nextjs-landing/eslint.config.mjs +16 -0
- package/bundles/nextjs-landing/instrumentation-client.ts +30 -0
- package/bundles/nextjs-landing/instrumentation.ts +12 -0
- package/bundles/nextjs-landing/jest.config.mjs +16 -0
- package/bundles/nextjs-landing/jest.setup.js +1 -0
- package/bundles/nextjs-landing/lib/utils.ts +6 -0
- package/bundles/nextjs-landing/next-env.d.ts +5 -0
- package/bundles/nextjs-landing/next.config.ts +15 -0
- package/bundles/nextjs-landing/package.json +48 -0
- package/bundles/nextjs-landing/postcss.config.mjs +7 -0
- package/bundles/nextjs-landing/prompts/01-feature-implementation.md +9 -0
- package/bundles/nextjs-landing/prompts/02-bug-fix.md +10 -0
- package/bundles/nextjs-landing/prompts/03-safe-refactor.md +8 -0
- package/bundles/nextjs-landing/prompts/04-test-first.md +8 -0
- package/bundles/nextjs-landing/prompts/05-ui-polish.md +8 -0
- package/bundles/nextjs-landing/prompts/06-security-review.md +7 -0
- package/bundles/nextjs-landing/prompts/quality.md +269 -0
- package/bundles/nextjs-landing/sentry.edge.config.ts +15 -0
- package/bundles/nextjs-landing/sentry.server.config.ts +15 -0
- package/bundles/nextjs-landing/tsconfig.json +42 -0
- package/bundles/nextjs-landing/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
- package/bundles/nextjs-saas/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
- package/bundles/nextjs-saas/.agents/skills/lattice-release-manager/SKILL.md +29 -0
- package/bundles/nextjs-saas/.agents/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/nextjs-saas/.claude/agents/lattice-feature-agent.md +10 -0
- package/bundles/nextjs-saas/.claude/agents/lattice-release-manager.md +9 -0
- package/bundles/nextjs-saas/.claude/hooks/README.md +9 -0
- package/bundles/nextjs-saas/.claude/hooks/pre-commit-verify.mjs +10 -0
- package/bundles/nextjs-saas/.claude/hooks/pre-tool-use.mjs +51 -0
- package/bundles/nextjs-saas/.claude/rules/lattice-core.md +20 -0
- package/bundles/nextjs-saas/.claude/settings.json +38 -0
- package/bundles/nextjs-saas/.claude/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/nextjs-saas/.codex/agents/lattice-feature-agent.toml +9 -0
- package/bundles/nextjs-saas/.codex/agents/lattice-release-manager.toml +9 -0
- package/bundles/nextjs-saas/.cursor/mcp.json +34 -0
- package/bundles/nextjs-saas/.cursor/rules/lattice-core.mdc +35 -0
- package/bundles/nextjs-saas/.cursor/rules.md +95 -0
- package/bundles/nextjs-saas/.env.example +48 -0
- package/bundles/nextjs-saas/.github/PULL_REQUEST_TEMPLATE.md +42 -0
- package/bundles/nextjs-saas/.github/agents/lattice-feature-agent.agent.md +7 -0
- package/bundles/nextjs-saas/.github/agents/lattice-release-manager.agent.md +7 -0
- package/bundles/nextjs-saas/.github/copilot-instructions.md +37 -0
- package/bundles/nextjs-saas/.github/instructions/lattice-core.instructions.md +11 -0
- package/bundles/nextjs-saas/.github/workflows/ci.yml +26 -0
- package/bundles/nextjs-saas/.gitmessage +24 -0
- package/bundles/nextjs-saas/.lattice/config.json +9 -0
- package/bundles/nextjs-saas/.lattice/dependency-security.json +46 -0
- package/bundles/nextjs-saas/.lattice/prompts/01-feature.md +36 -0
- package/bundles/nextjs-saas/.lattice/prompts/02-bugfix.md +32 -0
- package/bundles/nextjs-saas/.lattice/prompts/03-refactor.md +30 -0
- package/bundles/nextjs-saas/.lattice/prompts/04-test.md +31 -0
- package/bundles/nextjs-saas/.lattice/prompts/05-polish.md +38 -0
- package/bundles/nextjs-saas/.lattice/prompts/06-security.md +32 -0
- package/bundles/nextjs-saas/.lattice/prompts/quality.md +269 -0
- package/bundles/nextjs-saas/.lattice/release-workflow.json +55 -0
- package/bundles/nextjs-saas/.lattice/schemas/feature-handoff.schema.json +264 -0
- package/bundles/nextjs-saas/.lattice/templates/feature-handoff.json +52 -0
- package/bundles/nextjs-saas/.mcp.json +35 -0
- package/bundles/nextjs-saas/AGENTS.md +58 -0
- package/bundles/nextjs-saas/CLAUDE.md +76 -0
- package/bundles/nextjs-saas/PROJECT_GUIDE.md +279 -0
- package/bundles/nextjs-saas/README.md +42 -0
- package/bundles/nextjs-saas/app/(auth)/forgot-password/page.tsx +101 -0
- package/bundles/nextjs-saas/app/(auth)/layout.tsx +7 -0
- package/bundles/nextjs-saas/app/(auth)/login/page.tsx +108 -0
- package/bundles/nextjs-saas/app/(auth)/reset-password/page.tsx +135 -0
- package/bundles/nextjs-saas/app/(auth)/signup/page.tsx +144 -0
- package/bundles/nextjs-saas/app/(dashboard)/dashboard/page.tsx +80 -0
- package/bundles/nextjs-saas/app/(dashboard)/layout.tsx +49 -0
- package/bundles/nextjs-saas/app/api/billing/checkout/route.ts +47 -0
- package/bundles/nextjs-saas/app/api/billing/portal/route.ts +29 -0
- package/bundles/nextjs-saas/app/api/example/[id]/route.ts +93 -0
- package/bundles/nextjs-saas/app/api/example/route.ts +61 -0
- package/bundles/nextjs-saas/app/api/health/route.ts +8 -0
- package/bundles/nextjs-saas/app/api/stripe/webhook/route.ts +57 -0
- package/bundles/nextjs-saas/app/api/user/route.ts +49 -0
- package/bundles/nextjs-saas/app/auth/callback/route.ts +16 -0
- package/bundles/nextjs-saas/app/auth/signout/route.ts +10 -0
- package/bundles/nextjs-saas/app/global-error.tsx +17 -0
- package/bundles/nextjs-saas/app/globals.css +55 -0
- package/bundles/nextjs-saas/app/layout.tsx +22 -0
- package/bundles/nextjs-saas/app/page.tsx +84 -0
- package/bundles/nextjs-saas/components/ui/button.tsx +39 -0
- package/bundles/nextjs-saas/components/ui/card.tsx +53 -0
- package/bundles/nextjs-saas/components/ui/index.ts +4 -0
- package/bundles/nextjs-saas/components/ui/input.tsx +23 -0
- package/bundles/nextjs-saas/components/ui/spinner.tsx +22 -0
- package/bundles/nextjs-saas/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
- package/bundles/nextjs-saas/docs/rules/codex.md +62 -0
- package/bundles/nextjs-saas/eslint.config.mjs +16 -0
- package/bundles/nextjs-saas/instrumentation-client.ts +30 -0
- package/bundles/nextjs-saas/instrumentation.ts +12 -0
- package/bundles/nextjs-saas/jest.config.mjs +16 -0
- package/bundles/nextjs-saas/jest.setup.js +1 -0
- package/bundles/nextjs-saas/lib/auth/password-recovery.ts +94 -0
- package/bundles/nextjs-saas/lib/stripe.ts +10 -0
- package/bundles/nextjs-saas/lib/supabase/admin.ts +14 -0
- package/bundles/nextjs-saas/lib/supabase/client.ts +8 -0
- package/bundles/nextjs-saas/lib/supabase/server.ts +27 -0
- package/bundles/nextjs-saas/lib/utils.ts +6 -0
- package/bundles/nextjs-saas/next-env.d.ts +5 -0
- package/bundles/nextjs-saas/next.config.ts +15 -0
- package/bundles/nextjs-saas/package.json +50 -0
- package/bundles/nextjs-saas/postcss.config.mjs +7 -0
- package/bundles/nextjs-saas/prompts/01-feature-implementation.md +92 -0
- package/bundles/nextjs-saas/prompts/02-bug-fix.md +78 -0
- package/bundles/nextjs-saas/prompts/03-safe-refactor.md +82 -0
- package/bundles/nextjs-saas/prompts/04-test-first.md +80 -0
- package/bundles/nextjs-saas/prompts/05-ui-polish.md +82 -0
- package/bundles/nextjs-saas/prompts/06-security-review.md +74 -0
- package/bundles/nextjs-saas/proxy.ts +61 -0
- package/bundles/nextjs-saas/sentry.edge.config.ts +15 -0
- package/bundles/nextjs-saas/sentry.server.config.ts +15 -0
- package/bundles/nextjs-saas/supabase/migrations/001_initial_schema.sql +66 -0
- package/bundles/nextjs-saas/supabase/migrations/002_billing.sql +17 -0
- package/bundles/nextjs-saas/tsconfig.json +42 -0
- package/bundles/nextjs-saas/types/database.types.ts +76 -0
- package/bundles/nextjs-saas/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
- package/bundles/nextjs-trpc/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
- package/bundles/nextjs-trpc/.agents/skills/lattice-release-manager/SKILL.md +29 -0
- package/bundles/nextjs-trpc/.agents/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/nextjs-trpc/.claude/agents/lattice-feature-agent.md +10 -0
- package/bundles/nextjs-trpc/.claude/agents/lattice-release-manager.md +9 -0
- package/bundles/nextjs-trpc/.claude/hooks/README.md +9 -0
- package/bundles/nextjs-trpc/.claude/hooks/pre-commit-verify.mjs +10 -0
- package/bundles/nextjs-trpc/.claude/hooks/pre-tool-use.mjs +51 -0
- package/bundles/nextjs-trpc/.claude/rules/lattice-core.md +20 -0
- package/bundles/nextjs-trpc/.claude/settings.json +38 -0
- package/bundles/nextjs-trpc/.claude/skills/lattice-verify/SKILL.md +27 -0
- package/bundles/nextjs-trpc/.codex/agents/lattice-feature-agent.toml +9 -0
- package/bundles/nextjs-trpc/.codex/agents/lattice-release-manager.toml +9 -0
- package/bundles/nextjs-trpc/.cursor/mcp.json +34 -0
- package/bundles/nextjs-trpc/.cursor/rules/lattice-core.mdc +35 -0
- package/bundles/nextjs-trpc/.cursor/rules.md +95 -0
- package/bundles/nextjs-trpc/.env.example +21 -0
- package/bundles/nextjs-trpc/.github/PULL_REQUEST_TEMPLATE.md +42 -0
- package/bundles/nextjs-trpc/.github/agents/lattice-feature-agent.agent.md +7 -0
- package/bundles/nextjs-trpc/.github/agents/lattice-release-manager.agent.md +7 -0
- package/bundles/nextjs-trpc/.github/copilot-instructions.md +37 -0
- package/bundles/nextjs-trpc/.github/instructions/lattice-core.instructions.md +11 -0
- package/bundles/nextjs-trpc/.github/workflows/ci.yml +26 -0
- package/bundles/nextjs-trpc/.gitmessage +24 -0
- package/bundles/nextjs-trpc/.lattice/config.json +9 -0
- package/bundles/nextjs-trpc/.lattice/dependency-security.json +46 -0
- package/bundles/nextjs-trpc/.lattice/prompts/01-feature.md +36 -0
- package/bundles/nextjs-trpc/.lattice/prompts/02-bugfix.md +32 -0
- package/bundles/nextjs-trpc/.lattice/prompts/03-refactor.md +30 -0
- package/bundles/nextjs-trpc/.lattice/prompts/04-test.md +31 -0
- package/bundles/nextjs-trpc/.lattice/prompts/05-polish.md +38 -0
- package/bundles/nextjs-trpc/.lattice/prompts/06-security.md +32 -0
- package/bundles/nextjs-trpc/.lattice/release-workflow.json +55 -0
- package/bundles/nextjs-trpc/.lattice/schemas/feature-handoff.schema.json +264 -0
- package/bundles/nextjs-trpc/.lattice/templates/feature-handoff.json +52 -0
- package/bundles/nextjs-trpc/.mcp.json +35 -0
- package/bundles/nextjs-trpc/AGENTS.md +58 -0
- package/bundles/nextjs-trpc/CLAUDE.md +76 -0
- package/bundles/nextjs-trpc/PROJECT_GUIDE.md +187 -0
- package/bundles/nextjs-trpc/README.md +49 -0
- package/bundles/nextjs-trpc/app/api/trpc/[trpc]/route.ts +12 -0
- package/bundles/nextjs-trpc/app/global-error.tsx +17 -0
- package/bundles/nextjs-trpc/app/globals.css +55 -0
- package/bundles/nextjs-trpc/app/layout.tsx +19 -0
- package/bundles/nextjs-trpc/app/page.tsx +16 -0
- package/bundles/nextjs-trpc/app/providers.tsx +24 -0
- package/bundles/nextjs-trpc/components/ui/button.tsx +39 -0
- package/bundles/nextjs-trpc/components/ui/card.tsx +53 -0
- package/bundles/nextjs-trpc/components/ui/index.ts +4 -0
- package/bundles/nextjs-trpc/components/ui/input.tsx +23 -0
- package/bundles/nextjs-trpc/components/ui/spinner.tsx +22 -0
- package/bundles/nextjs-trpc/components/user-list.tsx +17 -0
- package/bundles/nextjs-trpc/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
- package/bundles/nextjs-trpc/docs/rules/codex.md +62 -0
- package/bundles/nextjs-trpc/eslint.config.mjs +16 -0
- package/bundles/nextjs-trpc/instrumentation-client.ts +20 -0
- package/bundles/nextjs-trpc/instrumentation.ts +12 -0
- package/bundles/nextjs-trpc/jest.config.mjs +16 -0
- package/bundles/nextjs-trpc/jest.setup.js +1 -0
- package/bundles/nextjs-trpc/lib/db.ts +17 -0
- package/bundles/nextjs-trpc/lib/trpc/react.tsx +7 -0
- package/bundles/nextjs-trpc/lib/utils.ts +6 -0
- package/bundles/nextjs-trpc/next-env.d.ts +5 -0
- package/bundles/nextjs-trpc/next.config.ts +15 -0
- package/bundles/nextjs-trpc/package.json +62 -0
- package/bundles/nextjs-trpc/postcss.config.mjs +7 -0
- package/bundles/nextjs-trpc/prisma/schema.prisma +41 -0
- package/bundles/nextjs-trpc/prisma.config.ts +10 -0
- package/bundles/nextjs-trpc/prompts/01-feature-implementation.md +9 -0
- package/bundles/nextjs-trpc/prompts/02-bug-fix.md +9 -0
- package/bundles/nextjs-trpc/prompts/03-safe-refactor.md +8 -0
- package/bundles/nextjs-trpc/prompts/04-test-first.md +8 -0
- package/bundles/nextjs-trpc/prompts/05-ui-polish.md +7 -0
- package/bundles/nextjs-trpc/prompts/06-security-review.md +7 -0
- package/bundles/nextjs-trpc/prompts/quality.md +269 -0
- package/bundles/nextjs-trpc/sentry.edge.config.ts +15 -0
- package/bundles/nextjs-trpc/sentry.server.config.ts +15 -0
- package/bundles/nextjs-trpc/server/routers/_app.test.ts +60 -0
- package/bundles/nextjs-trpc/server/routers/_app.ts +25 -0
- package/bundles/nextjs-trpc/server/trpc.ts +12 -0
- package/bundles/nextjs-trpc/tsconfig.json +42 -0
- package/bundles/nextjs-trpc/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
- package/dist/agent-install-session.d.ts +17 -0
- package/dist/agent-install-session.d.ts.map +1 -0
- package/dist/agent-install-session.js +106 -0
- package/dist/agent-install-session.js.map +1 -0
- package/dist/agent-install-session.test.d.ts +2 -0
- package/dist/agent-install-session.test.d.ts.map +1 -0
- package/dist/agent-install-session.test.js +62 -0
- package/dist/agent-install-session.test.js.map +1 -0
- package/dist/agent-install.d.ts +41 -0
- package/dist/agent-install.d.ts.map +1 -0
- package/dist/agent-install.js +42 -0
- package/dist/agent-install.js.map +1 -0
- package/dist/agent-install.test.d.ts +2 -0
- package/dist/agent-install.test.d.ts.map +1 -0
- package/dist/agent-install.test.js +58 -0
- package/dist/agent-install.test.js.map +1 -0
- package/dist/apply-merge.test.d.ts +2 -0
- package/dist/apply-merge.test.d.ts.map +1 -0
- package/dist/apply-merge.test.js +123 -0
- package/dist/apply-merge.test.js.map +1 -0
- package/dist/bundle-download.d.ts +23 -0
- package/dist/bundle-download.d.ts.map +1 -0
- package/dist/bundle-download.js +180 -0
- package/dist/bundle-download.js.map +1 -0
- package/dist/bundle-download.test.d.ts +2 -0
- package/dist/bundle-download.test.d.ts.map +1 -0
- package/dist/bundle-download.test.js +200 -0
- package/dist/bundle-download.test.js.map +1 -0
- package/dist/bundle-rollback.test.d.ts +2 -0
- package/dist/bundle-rollback.test.d.ts.map +1 -0
- package/dist/bundle-rollback.test.js +127 -0
- package/dist/bundle-rollback.test.js.map +1 -0
- package/dist/bundle-scaffold.test.d.ts +2 -0
- package/dist/bundle-scaffold.test.d.ts.map +1 -0
- package/dist/bundle-scaffold.test.js +105 -0
- package/dist/bundle-scaffold.test.js.map +1 -0
- package/dist/commands.d.ts +132 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +2012 -0
- package/dist/commands.js.map +1 -0
- package/dist/credential-store.d.ts +27 -0
- package/dist/credential-store.d.ts.map +1 -0
- package/dist/credential-store.js +48 -0
- package/dist/credential-store.js.map +1 -0
- package/dist/credential-store.test.d.ts +2 -0
- package/dist/credential-store.test.d.ts.map +1 -0
- package/dist/credential-store.test.js +80 -0
- package/dist/credential-store.test.js.map +1 -0
- package/dist/delivered-project-files.d.ts +31 -0
- package/dist/delivered-project-files.d.ts.map +1 -0
- package/dist/delivered-project-files.js +158 -0
- package/dist/delivered-project-files.js.map +1 -0
- package/dist/delivered-project-files.test.d.ts +2 -0
- package/dist/delivered-project-files.test.d.ts.map +1 -0
- package/dist/delivered-project-files.test.js +107 -0
- package/dist/delivered-project-files.test.js.map +1 -0
- package/dist/doctor-agents.test.d.ts +2 -0
- package/dist/doctor-agents.test.d.ts.map +1 -0
- package/dist/doctor-agents.test.js +65 -0
- package/dist/doctor-agents.test.js.map +1 -0
- package/dist/hermes-install.d.ts +102 -0
- package/dist/hermes-install.d.ts.map +1 -0
- package/dist/hermes-install.js +641 -0
- package/dist/hermes-install.js.map +1 -0
- package/dist/hermes-install.test.d.ts +2 -0
- package/dist/hermes-install.test.d.ts.map +1 -0
- package/dist/hermes-install.test.js +866 -0
- package/dist/hermes-install.test.js.map +1 -0
- package/dist/index.d.ts +115 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5311 -0
- package/dist/index.js.map +1 -0
- package/dist/openclaw-install.d.ts +67 -0
- package/dist/openclaw-install.d.ts.map +1 -0
- package/dist/openclaw-install.js +358 -0
- package/dist/openclaw-install.js.map +1 -0
- package/dist/openclaw-install.test.d.ts +2 -0
- package/dist/openclaw-install.test.d.ts.map +1 -0
- package/dist/openclaw-install.test.js +296 -0
- package/dist/openclaw-install.test.js.map +1 -0
- package/dist/password-recovery-bundle.test.d.ts +2 -0
- package/dist/password-recovery-bundle.test.d.ts.map +1 -0
- package/dist/password-recovery-bundle.test.js +132 -0
- package/dist/password-recovery-bundle.test.js.map +1 -0
- package/dist/project-bundle-env.d.ts +19 -0
- package/dist/project-bundle-env.d.ts.map +1 -0
- package/dist/project-bundle-env.js +111 -0
- package/dist/project-bundle-env.js.map +1 -0
- package/dist/project-bundle-env.test.d.ts +2 -0
- package/dist/project-bundle-env.test.d.ts.map +1 -0
- package/dist/project-bundle-env.test.js +93 -0
- package/dist/project-bundle-env.test.js.map +1 -0
- package/dist/project-path-confinement.test.d.ts +2 -0
- package/dist/project-path-confinement.test.d.ts.map +1 -0
- package/dist/project-path-confinement.test.js +222 -0
- package/dist/project-path-confinement.test.js.map +1 -0
- package/dist/security/api.d.ts +18 -0
- package/dist/security/api.d.ts.map +1 -0
- package/dist/security/api.js +238 -0
- package/dist/security/api.js.map +1 -0
- package/dist/security/api.test.d.ts +2 -0
- package/dist/security/api.test.d.ts.map +1 -0
- package/dist/security/api.test.js +220 -0
- package/dist/security/api.test.js.map +1 -0
- package/dist/security/artifact.d.ts +10 -0
- package/dist/security/artifact.d.ts.map +1 -0
- package/dist/security/artifact.js +283 -0
- package/dist/security/artifact.js.map +1 -0
- package/dist/security/artifact.test.d.ts +2 -0
- package/dist/security/artifact.test.d.ts.map +1 -0
- package/dist/security/artifact.test.js +229 -0
- package/dist/security/artifact.test.js.map +1 -0
- package/dist/security/commands.d.ts +42 -0
- package/dist/security/commands.d.ts.map +1 -0
- package/dist/security/commands.js +825 -0
- package/dist/security/commands.js.map +1 -0
- package/dist/security/commands.test.d.ts +2 -0
- package/dist/security/commands.test.d.ts.map +1 -0
- package/dist/security/commands.test.js +1051 -0
- package/dist/security/commands.test.js.map +1 -0
- package/dist/security/connection.d.ts +19 -0
- package/dist/security/connection.d.ts.map +1 -0
- package/dist/security/connection.js +145 -0
- package/dist/security/connection.js.map +1 -0
- package/dist/security/connection.test.d.ts +2 -0
- package/dist/security/connection.test.d.ts.map +1 -0
- package/dist/security/connection.test.js +62 -0
- package/dist/security/connection.test.js.map +1 -0
- package/dist/security/index-routing.test.d.ts +2 -0
- package/dist/security/index-routing.test.d.ts.map +1 -0
- package/dist/security/index-routing.test.js +169 -0
- package/dist/security/index-routing.test.js.map +1 -0
- package/dist/security/journal.d.ts +26 -0
- package/dist/security/journal.d.ts.map +1 -0
- package/dist/security/journal.js +441 -0
- package/dist/security/journal.js.map +1 -0
- package/dist/security/journal.test.d.ts +2 -0
- package/dist/security/journal.test.d.ts.map +1 -0
- package/dist/security/journal.test.js +226 -0
- package/dist/security/journal.test.js.map +1 -0
- package/dist/security/package-verifier.d.ts +15 -0
- package/dist/security/package-verifier.d.ts.map +1 -0
- package/dist/security/package-verifier.js +65 -0
- package/dist/security/package-verifier.js.map +1 -0
- package/dist/security/package-verifier.test.d.ts +2 -0
- package/dist/security/package-verifier.test.d.ts.map +1 -0
- package/dist/security/package-verifier.test.js +57 -0
- package/dist/security/package-verifier.test.js.map +1 -0
- package/dist/security/runtime.d.ts +43 -0
- package/dist/security/runtime.d.ts.map +1 -0
- package/dist/security/runtime.js +81 -0
- package/dist/security/runtime.js.map +1 -0
- package/dist/security/runtime.test.d.ts +2 -0
- package/dist/security/runtime.test.d.ts.map +1 -0
- package/dist/security/runtime.test.js +88 -0
- package/dist/security/runtime.test.js.map +1 -0
- package/dist/security/types.d.ts +169 -0
- package/dist/security/types.d.ts.map +1 -0
- package/dist/security/types.js +3 -0
- package/dist/security/types.js.map +1 -0
- package/dist/security-runtime/LICENSE +202 -0
- package/dist/security-runtime/NOTICE +16 -0
- package/dist/security-runtime/artifact-manifest.json +960 -0
- package/dist/security-runtime/bin/vsg.mjs +5 -0
- package/dist/security-runtime/lattice-catalog.json +176585 -0
- package/dist/security-runtime/lattice-runtime.mjs +90 -0
- package/dist/security-runtime/licensing/candidates/apache-source-license-evidence.json +478 -0
- package/dist/security-runtime/licensing/candidates/betterleaks-generic-api-key.json +76 -0
- package/dist/security-runtime/licensing/candidates/betterleaks-jwt.json +74 -0
- package/dist/security-runtime/licensing/candidates/blackberry-additional-source-declaration-evidence.json +276 -0
- package/dist/security-runtime/licensing/candidates/blackberry-source-declaration-evidence.json +369 -0
- package/dist/security-runtime/licensing/candidates/cado-source-declaration-evidence.json +283 -0
- package/dist/security-runtime/licensing/candidates/commercial-rule-candidate.json +280 -0
- package/dist/security-runtime/licensing/candidates/commercial-runtime-release.json +389 -0
- package/dist/security-runtime/licensing/candidates/data-feed-evidence.json +259 -0
- package/dist/security-runtime/licensing/candidates/gitlab-sast-rule-identities.json +178 -0
- package/dist/security-runtime/licensing/candidates/gitlab-sast-source-evidence.json +1824 -0
- package/dist/security-runtime/licensing/candidates/gitlab-sast-source-notice-bundle.json +45 -0
- package/dist/security-runtime/licensing/candidates/malpedia-source-license-evidence.json +41 -0
- package/dist/security-runtime/licensing/candidates/rule-license-evidence.json +376 -0
- package/dist/security-runtime/licensing/candidates/runner-image-composition.json +1500 -0
- package/dist/security-runtime/licensing/candidates/selected-runtime-coverage.json +91 -0
- package/dist/security-runtime/licensing/candidates/yara-forge-20260927.json +58502 -0
- package/dist/security-runtime/licensing/commercial-components.json +379 -0
- package/dist/security-runtime/licensing/notices/betterleaks-1.9.0-MIT.txt +21 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/28a9529c7d0bb4dc51f4bf5c116a3d16ef247a052f7591466768ddf563fd1cf5.txt +428 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/33acf42afdd03163d75fe856cb431e70710e0b5deede3362e6d1c4697cfe1c6a.txt +28 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986.txt +674 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/4fecb8fcaf80fd9a6315bca5225ee43377015b46a0459c2925495be885cab19a.txt +21 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/811515f8723aa4007de2fbb75a364127fdec51cda534b87a7ea8f2fef2f96dd7.txt +24 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/814442c3987a2c0411171ad8ad43118e8c08f85c9c5d1dcdecc9787c7ca8689b.txt +664 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/8a959b2413d0c83ca1b3ce9153076c649abf2e4bbfebbb493fb24c2074a1eb8a.txt +38 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/995182e185856186fbbe49f150409ae026aa4cda7e94f83c6ed737cbb77fa9c7.txt +23 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/9b8e1305e46d1dd4011b6ed933c9f6223e08c9c4625001c5fd75a34fa930f616.txt +202 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/a01f1a28424bfe7f49a23d339a01847cfa9ace3864d5e7295051772a4bae2271.txt +38 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/a5681bf9b05db14d86776930017c647ad9e6e56ff6bbcfdf21e5848288dfaf1b.txt +165 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/a5b8bd9ae96c630bbf229d61c5c5def20274e00be39abfd2fab4d7879ceab462.txt +24 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/ada32b3747ce108d5e8bab7918af94abbd03f2fe2a46304f74c6333bbfd914ed.txt +8 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4.txt +201 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/c738ae413cf561f174e34f6961f8ca458aae2369a73640dda6234c629b98bcc4.txt +2732 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/ce41c9a2c986277f7f9ab146a2195c1888a5d8da062e22d7c9c88666bb7c38cd.txt +17 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/d5f4c36a0528e01cfdd9e4fc60879201d3af49b41c520200643d321fe53da5f9.txt +17 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/e08c368ccd455f85c7fb9e04830e730f26e9dbb5c0f77bc88e09a5b0cb37df5b.txt +38 -0
- package/dist/security-runtime/licensing/notices/candidate-sources/sha256/e9efb2f7daf11bb6379c06c16b870dddcecc4a10f8704bb8aad807529c8b3c97.txt +8 -0
- package/dist/security-runtime/licensing/notices/gitleaks-generic-origin-782f3104-MIT.txt +21 -0
- package/dist/security-runtime/package.json +17 -0
- package/dist/security-runtime/playbook/README.md +76 -0
- package/dist/security-runtime/playbook/access-control.md +56 -0
- package/dist/security-runtime/playbook/ai-features.md +53 -0
- package/dist/security-runtime/playbook/desktop-python.md +59 -0
- package/dist/security-runtime/playbook/input-handling.md +59 -0
- package/dist/security-runtime/playbook/mobile-expo.md +59 -0
- package/dist/security-runtime/playbook/payments.md +53 -0
- package/dist/security-runtime/playbook/privacy-account-recovery.md +59 -0
- package/dist/security-runtime/playbook/secrets-config.md +47 -0
- package/dist/security-runtime/playbook/supabase.md +48 -0
- package/dist/security-runtime/playbook/supply-chain.md +62 -0
- package/dist/security-runtime/playbook/webhooks-integrations.md +52 -0
- package/dist/security-runtime/rules/vsg-ai-key-in-client.yaml +41 -0
- package/dist/security-runtime/rules/vsg-ai-output-raw-html.yaml +35 -0
- package/dist/security-runtime/rules/vsg-angular-sanitizer-bypass.yaml +23 -0
- package/dist/security-runtime/rules/vsg-expo-token-in-asyncstorage.yaml +22 -0
- package/dist/security-runtime/rules/vsg-flask-public-bind.yaml +32 -0
- package/dist/security-runtime/rules/vsg-nextjs-action-write-no-auth.yaml +144 -0
- package/dist/security-runtime/rules/vsg-nextjs-inline-action-write-no-auth.yaml +161 -0
- package/dist/security-runtime/rules/vsg-nextjs-route-write-no-auth.yaml +193 -0
- package/dist/security-runtime/rules/vsg-nosql-where-injection.yaml +36 -0
- package/dist/security-runtime/rules/vsg-python-pickle-load.yaml +26 -0
- package/dist/security-runtime/rules/vsg-python-requests-verify-false.yaml +34 -0
- package/dist/security-runtime/rules/vsg-python-subprocess-shell.yaml +23 -0
- package/dist/security-runtime/rules/vsg-stripe-client-price.yaml +51 -0
- package/dist/security-runtime/rules/vsg-stripe-webhook-no-signature.yaml +31 -0
- package/dist/security-runtime/rules/vsg-stripe-webhook-pages-no-signature.yaml +51 -0
- package/dist/security-runtime/rules/vsg-supabase-service-role-in-client.yaml +27 -0
- package/dist/security-runtime/rules/vsg-supabase-service-role-public-env.yaml +24 -0
- package/dist/security-runtime/rules/vsg-xml-external-entities.yaml +19 -0
- package/dist/security-runtime/src/agent/brief.mjs +95 -0
- package/dist/security-runtime/src/agent/discover.mjs +108 -0
- package/dist/security-runtime/src/agent/exec.mjs +64 -0
- package/dist/security-runtime/src/agent/ingest.mjs +213 -0
- package/dist/security-runtime/src/agent/report.mjs +94 -0
- package/dist/security-runtime/src/agent/schema.mjs +62 -0
- package/dist/security-runtime/src/agent/tokenize.mjs +38 -0
- package/dist/security-runtime/src/checks/README.md +8 -0
- package/dist/security-runtime/src/checks/_lib/gitfiles.mjs +35 -0
- package/dist/security-runtime/src/checks/_lib/lockfiles.mjs +135 -0
- package/dist/security-runtime/src/checks/_lib/osv.mjs +6 -0
- package/dist/security-runtime/src/checks/_lib/secrets.mjs +381 -0
- package/dist/security-runtime/src/checks/_lib/targets.mjs +79 -0
- package/dist/security-runtime/src/checks/agent-review/index.mjs +52 -0
- package/dist/security-runtime/src/checks/agent-surface/config.mjs +223 -0
- package/dist/security-runtime/src/checks/agent-surface/index.mjs +113 -0
- package/dist/security-runtime/src/checks/agent-surface/instructions.mjs +87 -0
- package/dist/security-runtime/src/checks/agent-surface/patterns.mjs +68 -0
- package/dist/security-runtime/src/checks/agent-surface/unicode.mjs +88 -0
- package/dist/security-runtime/src/checks/code/auth-helpers.mjs +659 -0
- package/dist/security-runtime/src/checks/code/index.mjs +617 -0
- package/dist/security-runtime/src/checks/code/opengrep-container.mjs +85 -0
- package/dist/security-runtime/src/checks/code/opengrep-runner.mjs +86 -0
- package/dist/security-runtime/src/checks/code/selected-opengrep-runner.mjs +112 -0
- package/dist/security-runtime/src/checks/dep-change/guarddog.mjs +142 -0
- package/dist/security-runtime/src/checks/dep-change/index.mjs +316 -0
- package/dist/security-runtime/src/checks/dep-change/registries.mjs +199 -0
- package/dist/security-runtime/src/checks/deps-vuln/index.mjs +305 -0
- package/dist/security-runtime/src/checks/desktop-config/index.mjs +112 -0
- package/dist/security-runtime/src/checks/dns-mail/index.mjs +71 -0
- package/dist/security-runtime/src/checks/iac/index.mjs +83 -0
- package/dist/security-runtime/src/checks/install-posture/index.mjs +123 -0
- package/dist/security-runtime/src/checks/licenses/index.mjs +143 -0
- package/dist/security-runtime/src/checks/live-basic/index.mjs +77 -0
- package/dist/security-runtime/src/checks/live-js-secrets/index.mjs +100 -0
- package/dist/security-runtime/src/checks/malware/clamav.mjs +17 -0
- package/dist/security-runtime/src/checks/malware/defender.mjs +43 -0
- package/dist/security-runtime/src/checks/malware/index.mjs +186 -0
- package/dist/security-runtime/src/checks/malware/targets.mjs +147 -0
- package/dist/security-runtime/src/checks/malware/yara-runner.mjs +201 -0
- package/dist/security-runtime/src/checks/malware/yara.mjs +124 -0
- package/dist/security-runtime/src/checks/mobile-config/index.mjs +173 -0
- package/dist/security-runtime/src/checks/mobile-config/mobsf.mjs +105 -0
- package/dist/security-runtime/src/checks/posture/index.mjs +133 -0
- package/dist/security-runtime/src/checks/project-scripts/index.mjs +187 -0
- package/dist/security-runtime/src/checks/sbom/index.mjs +98 -0
- package/dist/security-runtime/src/checks/secrets-build/index.mjs +63 -0
- package/dist/security-runtime/src/checks/secrets-history/index.mjs +112 -0
- package/dist/security-runtime/src/checks/secrets-tree/env.mjs +120 -0
- package/dist/security-runtime/src/checks/secrets-tree/index.mjs +73 -0
- package/dist/security-runtime/src/checks/supabase-static/index.mjs +240 -0
- package/dist/security-runtime/src/checks/supabase-static/sql.mjs +557 -0
- package/dist/security-runtime/src/checks/workflows/index.mjs +93 -0
- package/dist/security-runtime/src/cli/deep.mjs +13 -0
- package/dist/security-runtime/src/cli/doctor.mjs +82 -0
- package/dist/security-runtime/src/cli/index.mjs +60 -0
- package/dist/security-runtime/src/cli/live-common.mjs +27 -0
- package/dist/security-runtime/src/cli/parse.mjs +56 -0
- package/dist/security-runtime/src/cli/portfolio.mjs +34 -0
- package/dist/security-runtime/src/cli/release.mjs +28 -0
- package/dist/security-runtime/src/cli/report.mjs +18 -0
- package/dist/security-runtime/src/cli/run-common.mjs +54 -0
- package/dist/security-runtime/src/cli/scan.mjs +12 -0
- package/dist/security-runtime/src/cli/setup.mjs +59 -0
- package/dist/security-runtime/src/cli/url.mjs +38 -0
- package/dist/security-runtime/src/core/accept.mjs +141 -0
- package/dist/security-runtime/src/core/archive.mjs +114 -0
- package/dist/security-runtime/src/core/base-ref.mjs +43 -0
- package/dist/security-runtime/src/core/checks.mjs +39 -0
- package/dist/security-runtime/src/core/detect.mjs +90 -0
- package/dist/security-runtime/src/core/errors.mjs +5 -0
- package/dist/security-runtime/src/core/fetch.mjs +139 -0
- package/dist/security-runtime/src/core/findings.mjs +177 -0
- package/dist/security-runtime/src/core/gate.mjs +131 -0
- package/dist/security-runtime/src/core/installer.mjs +255 -0
- package/dist/security-runtime/src/core/lock.mjs +38 -0
- package/dist/security-runtime/src/core/nested.mjs +107 -0
- package/dist/security-runtime/src/core/paths.mjs +20 -0
- package/dist/security-runtime/src/core/pipeline.mjs +196 -0
- package/dist/security-runtime/src/core/registry.mjs +81 -0
- package/dist/security-runtime/src/core/report.mjs +128 -0
- package/dist/security-runtime/src/core/runner.mjs +86 -0
- package/dist/security-runtime/src/core/sarif.mjs +141 -0
- package/dist/security-runtime/src/lattice/artifact.mjs +1201 -0
- package/dist/security-runtime/src/lattice/execution.mjs +45 -0
- package/dist/security-runtime/src/lattice/export.mjs +215 -0
- package/dist/security-runtime/src/lattice/provenance.mjs +70 -0
- package/dist/security-runtime/src/lattice/runtime.mjs +158 -0
- package/dist/security-runtime/src/lattice/selected-runtime.mjs +189 -0
- package/dist/security-runtime/src/lattice/source-acquirer.mjs +51 -0
- package/dist/security-runtime/src/lattice/source-fetcher.mjs +88 -0
- package/dist/security-runtime/src/lattice/transport.mjs +232 -0
- package/dist/security-runtime/src/live/analyze.mjs +101 -0
- package/dist/security-runtime/src/live/exposure.mjs +79 -0
- package/dist/security-runtime/src/live/secrets.mjs +31 -0
- package/dist/security-runtime/src/live/session.mjs +98 -0
- package/dist/security-runtime/src/live/targets.mjs +81 -0
- package/dist/security-runtime/src/portfolio/index.mjs +116 -0
- package/dist/security-runtime/tools/registry/betterleaks.json +29 -0
- package/dist/security-runtime/tools/registry/guarddog.json +9 -0
- package/dist/security-runtime/tools/registry/mobsf.json +10 -0
- package/dist/security-runtime/tools/registry/opengrep.json +28 -0
- package/dist/security-runtime/tools/registry/osv-scanner.json +14 -0
- package/dist/security-runtime/tools/registry/semgrep-rules.json +21 -0
- package/dist/security-runtime/tools/registry/trivy.json +30 -0
- package/dist/security-runtime/tools/registry/yara-forge-exclusions.json +14 -0
- package/dist/security-runtime/tools/registry/yara-forge.json +22 -0
- package/dist/security-runtime/tools/registry/yara-runner.json +10 -0
- package/dist/security-runtime/tools/registry/yara-x.json +24 -0
- package/dist/security-runtime/tools/registry/zizmor.json +30 -0
- package/dist/spinner.d.ts +16 -0
- package/dist/spinner.d.ts.map +1 -0
- package/dist/spinner.js +72 -0
- package/dist/spinner.js.map +1 -0
- package/dist/verify.test.d.ts +2 -0
- package/dist/verify.test.d.ts.map +1 -0
- package/dist/verify.test.js +98 -0
- package/dist/verify.test.js.map +1 -0
- package/package.json +73 -4
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// Gate (REQ-005): blocking policy and required checks as data tables, verdict semantics.
|
|
2
|
+
import { SEVERITIES } from './findings.mjs';
|
|
3
|
+
|
|
4
|
+
const atLeast = (f, min) => SEVERITIES.indexOf(f.severity) <= SEVERITIES.indexOf(min);
|
|
5
|
+
const strong = (f) => f.confidence === 'high' || f.confidence === 'confirmed';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Default blocking policy (build spec Data Contract). One row per finding category; blocks(f) returns a reason or null.
|
|
9
|
+
* Checks express policy inputs through severity and confidence: e.g. a vsg rule marked blocking emits confidence "confirmed";
|
|
10
|
+
* a secret only in history that is validated inactive is emitted below High; a reproduced agent finding is "confirmed".
|
|
11
|
+
*/
|
|
12
|
+
export const BLOCKING_POLICY = [
|
|
13
|
+
// Medium and below (low-signal generic matches, public-by-design info) are reported, never blocking (REQ-037).
|
|
14
|
+
{ category: 'secret', blocks: (f) => (atLeast(f, 'high') ? 'Secret in the working tree, build output or served JavaScript' : null) },
|
|
15
|
+
{ category: 'secret-history', blocks: (f) => (atLeast(f, 'high') ? 'Secret in git history (High)' : null) },
|
|
16
|
+
{ category: 'malicious-package', blocks: () => 'Known malicious package' },
|
|
17
|
+
{
|
|
18
|
+
category: 'dependency-vuln',
|
|
19
|
+
blocks: (f) => (f.exploited.kev ? 'Vulnerability listed in CISA KEV'
|
|
20
|
+
: f.severity === 'critical' ? 'Critical dependency vulnerability'
|
|
21
|
+
: f.severity === 'high' && f.fix ? 'High dependency vulnerability with a fixed version' : null),
|
|
22
|
+
},
|
|
23
|
+
{ category: 'dependency-change', blocks: (f) => (atLeast(f, 'high') ? 'Suspicious dependency change' : null) },
|
|
24
|
+
{ category: 'code', blocks: (f) => (atLeast(f, 'high') && strong(f) ? 'Blocking code rule (error level, high confidence)' : null) },
|
|
25
|
+
{ category: 'supabase', blocks: (f) => (atLeast(f, 'high') ? 'Supabase exposure' : null) },
|
|
26
|
+
{ category: 'workflow', blocks: (f) => (atLeast(f, 'high') && strong(f) ? 'CI workflow risk (High severity, high confidence)' : null) },
|
|
27
|
+
{ category: 'agent-surface', blocks: (f) => (atLeast(f, 'high') ? 'Critical or High agent-surface finding' : null) },
|
|
28
|
+
// Critical: any AV engine, a YARA rule scored 70 or more, or two YARA rules on one file. Medium: a lone low-score YARA heuristic (REQ-037).
|
|
29
|
+
{ category: 'malware', blocks: (f) => (atLeast(f, 'high') ? 'Malware detection' : null) },
|
|
30
|
+
{ category: 'replay', blocks: () => 'Cross-account replay succeeded' },
|
|
31
|
+
{ category: 'live', blocks: (f) => (atLeast(f, 'high') ? 'High-impact live-site exposure' : null) },
|
|
32
|
+
{ category: 'iac', blocks: (f) => (atLeast(f, 'high') ? 'High container or infrastructure misconfiguration' : null) },
|
|
33
|
+
{ category: 'release', blocks: (f) => (atLeast(f, 'high') ? 'Release build, typecheck or test failure' : null) },
|
|
34
|
+
{
|
|
35
|
+
category: 'agent-finding',
|
|
36
|
+
blocks: (f) => (f.severity === 'critical' && f.confidence !== 'confirmed' ? 'Unreproduced Critical agent finding: needs confirmation'
|
|
37
|
+
: atLeast(f, 'high') && f.confidence === 'confirmed' ? 'Reproduced High or Critical agent finding' : null),
|
|
38
|
+
},
|
|
39
|
+
// posture, license, config and other categories never block by default
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Required checks per mode. `when` is a detection or config condition ('always' if omitted); '@mode' includes another mode's set.
|
|
44
|
+
* Check ids are the contract between this table and src/checks/<id>/.
|
|
45
|
+
*/
|
|
46
|
+
export const REQUIRED_CHECKS = {
|
|
47
|
+
scan: [
|
|
48
|
+
{ id: 'deps-vuln' }, { id: 'secrets-tree' }, { id: 'code' }, { id: 'agent-surface' },
|
|
49
|
+
{ id: 'workflows', when: 'workflows' }, { id: 'dep-change', when: 'lockfiles' },
|
|
50
|
+
],
|
|
51
|
+
deep: [
|
|
52
|
+
'@scan', { id: 'secrets-history' }, { id: 'malware' }, { id: 'licenses' },
|
|
53
|
+
{ id: 'supabase-static', when: 'supabase' }, { id: 'agent-review' },
|
|
54
|
+
],
|
|
55
|
+
url: [{ id: 'live-basic' }, { id: 'live-js-secrets' }],
|
|
56
|
+
release: ['@deep', '@url', { id: 'project-scripts' }, { id: 'sbom' }],
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const CONDITIONS = {
|
|
60
|
+
always: () => true,
|
|
61
|
+
workflows: (d) => d.workflows.length > 0,
|
|
62
|
+
lockfiles: (d) => d.lockfiles.length > 0,
|
|
63
|
+
supabase: (d) => d.supabase,
|
|
64
|
+
accounts: (_d, x) => !!x.hasAccounts,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
function expand(mode, detection, extra, seen = new Set()) {
|
|
68
|
+
if (seen.has(mode)) return [];
|
|
69
|
+
seen.add(mode);
|
|
70
|
+
const ids = [];
|
|
71
|
+
for (const row of REQUIRED_CHECKS[mode] ?? []) {
|
|
72
|
+
if (typeof row === 'string') ids.push(...expand(row.slice(1), detection, extra, seen));
|
|
73
|
+
else if (CONDITIONS[row.when ?? 'always'](detection, extra)) ids.push(row.id);
|
|
74
|
+
}
|
|
75
|
+
return ids;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Returns { required: [id], removed: [{ id, reason }] } after applying vsg.config.json requiredChecks.remove. */
|
|
79
|
+
export function requiredFor(mode, detection, { config, hasAccounts = false } = {}) {
|
|
80
|
+
const ids = [...new Set(expand(mode, detection, { hasAccounts }))];
|
|
81
|
+
const removeList = config?.requiredChecks?.remove ?? [];
|
|
82
|
+
const removed = removeList.filter((r) => ids.includes(r.check)).map((r) => ({ id: r.check, reason: r.reason }));
|
|
83
|
+
const gone = new Set(removed.map((r) => r.id));
|
|
84
|
+
return { required: ids.filter((id) => !gone.has(id)), removed };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Sets blocking and blockReason from the policy. Accepted findings never block. */
|
|
88
|
+
export function applyPolicy(findings, policy = BLOCKING_POLICY) {
|
|
89
|
+
for (const f of findings) {
|
|
90
|
+
const row = policy.find((p) => p.category === f.category);
|
|
91
|
+
const reason = f.status === 'accepted' ? null : row?.blocks(f) ?? null;
|
|
92
|
+
f.blocking = !!reason;
|
|
93
|
+
f.blockReason = reason ?? '';
|
|
94
|
+
}
|
|
95
|
+
return findings;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function countsOf(findings) {
|
|
99
|
+
const counts = Object.fromEntries(SEVERITIES.map((s) => [s, 0]));
|
|
100
|
+
let blocking = 0;
|
|
101
|
+
let accepted = 0;
|
|
102
|
+
for (const f of findings) {
|
|
103
|
+
counts[f.severity]++;
|
|
104
|
+
if (f.blocking) blocking++;
|
|
105
|
+
if (f.status === 'accepted') accepted++;
|
|
106
|
+
}
|
|
107
|
+
return { ...counts, total: findings.length, blocking, accepted };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* BLOCKED if any finding blocks; otherwise INCOMPLETE if a required check did not run (not_run or missing);
|
|
112
|
+
* otherwise PASS. A required check that is not_applicable is satisfied. PASS is never returned with a required check not run.
|
|
113
|
+
*/
|
|
114
|
+
export function verdictFor(findings, coverage) {
|
|
115
|
+
if (findings.some((f) => f.blocking)) return 'BLOCKED';
|
|
116
|
+
if (coverage.some((c) => c.required && c.status === 'not_run')) return 'INCOMPLETE';
|
|
117
|
+
return 'PASS';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export const EXIT_CODES = { PASS: 0, BLOCKED: 1, INCOMPLETE: 2 };
|
|
121
|
+
|
|
122
|
+
/** First output line: the result in words. */
|
|
123
|
+
export function headline(verdict, counts, coverage) {
|
|
124
|
+
const missing = coverage.filter((c) => c.required && c.status === 'not_run').length;
|
|
125
|
+
const plural = (n, w) => `${n} ${w}${n === 1 ? '' : 's'}`;
|
|
126
|
+
if (verdict === 'BLOCKED') {
|
|
127
|
+
return `BLOCKED: ${plural(counts.blocking, 'must-fix finding')}${missing ? ` and ${plural(missing, 'required check')} did not run` : ''}`;
|
|
128
|
+
}
|
|
129
|
+
if (verdict === 'INCOMPLETE') return `INCOMPLETE: ${plural(missing, 'required check')} did not run`;
|
|
130
|
+
return 'PASS: no must-fix findings and every required check ran';
|
|
131
|
+
}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// Verified installer: download, check SHA-256 BEFORE extracting, extract to a staging directory, then move into the tools cache.
|
|
2
|
+
// Never touches PATH or system settings.
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { extractArchive, listTarGz, listZip, safeJoin } from './archive.mjs';
|
|
6
|
+
import { InstallError } from './errors.mjs';
|
|
7
|
+
import { vfetch } from './fetch.mjs';
|
|
8
|
+
import { sha256 } from './findings.mjs';
|
|
9
|
+
import { platformKey, toolsDir } from './paths.mjs';
|
|
10
|
+
import { runProcess } from './runner.mjs';
|
|
11
|
+
|
|
12
|
+
const MARKER = '.vsg-installed.json';
|
|
13
|
+
const MARKER_VERSION = 2;
|
|
14
|
+
const ARCHIVE = '.vsg-verified-archive';
|
|
15
|
+
const ARCHIVE_MARKER = '.vsg-archive-only.json';
|
|
16
|
+
export const installDir = (tool, platform) => {
|
|
17
|
+
const hostPlatform = platformFor(tool);
|
|
18
|
+
return platform && platform !== hostPlatform
|
|
19
|
+
? path.join(toolsDir(), '_platforms', platform, tool.name, tool.version)
|
|
20
|
+
: path.join(toolsDir(), tool.name, tool.version);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** Hash every file in an installed tree. The marker itself is excluded. */
|
|
24
|
+
function contentManifest(root) {
|
|
25
|
+
const files = {};
|
|
26
|
+
const walk = (dir, rel = '') => {
|
|
27
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
28
|
+
const child = path.join(dir, entry.name);
|
|
29
|
+
const childRel = rel ? path.join(rel, entry.name) : entry.name;
|
|
30
|
+
if (childRel === MARKER || childRel === ARCHIVE) continue;
|
|
31
|
+
if (entry.isDirectory()) walk(child, childRel);
|
|
32
|
+
else if (entry.isFile()) files[childRel.split(path.sep).join('/')] = sha256(fs.readFileSync(child));
|
|
33
|
+
else throw new Error(`installed tool contains unsupported entry "${childRel}"`);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
walk(root);
|
|
37
|
+
return Object.fromEntries(Object.entries(files).sort(([a], [b]) => a.localeCompare(b)));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const sameManifest = (a, b) => {
|
|
41
|
+
const ak = Object.keys(a).sort();
|
|
42
|
+
const bk = Object.keys(b).sort();
|
|
43
|
+
return ak.length === bk.length && ak.every((k, i) => k === bk[i] && a[k] === b[k]);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const archiveManifest = (buf, kind) => {
|
|
47
|
+
const entries = kind === 'zip' ? listZip(buf) : kind === 'tar.gz' ? listTarGz(buf) : null;
|
|
48
|
+
if (!entries) throw new Error(`unsupported archive type "${kind}"`);
|
|
49
|
+
const files = {};
|
|
50
|
+
for (const entry of entries) {
|
|
51
|
+
if (entry.dir) continue;
|
|
52
|
+
let name;
|
|
53
|
+
try {
|
|
54
|
+
const root = path.resolve('__vsg_archive_manifest_root__');
|
|
55
|
+
const absolute = safeJoin(root, entry.name);
|
|
56
|
+
name = path.relative(root, absolute).split(path.sep).join('/');
|
|
57
|
+
if (!name) throw new Error('empty path');
|
|
58
|
+
} catch {
|
|
59
|
+
throw new Error(`unsafe archive entry "${entry.name}"`);
|
|
60
|
+
}
|
|
61
|
+
if (name === MARKER || name === ARCHIVE) throw new Error(`unsafe archive entry "${entry.name}"`);
|
|
62
|
+
if (files[name] !== undefined) throw new Error(`duplicate archive entry "${name}"`);
|
|
63
|
+
files[name] = sha256(entry.data());
|
|
64
|
+
}
|
|
65
|
+
return Object.fromEntries(Object.entries(files).sort(([a], [b]) => a.localeCompare(b)));
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The platform whose build is installed for a tool on this host: the host's own, else the tool's containerPlatform
|
|
70
|
+
* (a build that runs in a Linux container, for example YARA-X on Windows, where the native binary is not used).
|
|
71
|
+
*/
|
|
72
|
+
export function platformFor(tool) {
|
|
73
|
+
const host = platformKey();
|
|
74
|
+
return tool.platforms?.[host] ? host : (tool.containerPlatform ?? host);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Returns { path, dir, platform } for an installed tool on this host, or null. */
|
|
78
|
+
export function resolveTool(tool, platform = platformFor(tool)) {
|
|
79
|
+
const entry = tool.platforms?.[platform];
|
|
80
|
+
if (!entry) return null;
|
|
81
|
+
const dir = installDir(tool, platform);
|
|
82
|
+
try {
|
|
83
|
+
const marker = JSON.parse(fs.readFileSync(path.join(dir, MARKER), 'utf8'));
|
|
84
|
+
const bin = safeJoin(dir, entry.bin);
|
|
85
|
+
if (marker.schemaVersion !== MARKER_VERSION || marker.name !== tool.name || marker.version !== tool.version || marker.archiveSha256 !== entry.sha256 || !marker.files) return null;
|
|
86
|
+
if (marker.platform && marker.platform !== platform) return null;
|
|
87
|
+
if (platform !== platformFor(tool) && marker.platform !== platform) return null;
|
|
88
|
+
const expected = entry.archive === 'none'
|
|
89
|
+
? { [entry.bin.replace(/\\/g, '/')]: entry.sha256 }
|
|
90
|
+
: (() => {
|
|
91
|
+
const archive = fs.readFileSync(path.join(dir, ARCHIVE));
|
|
92
|
+
if (sha256(archive) !== entry.sha256) throw new Error('verified archive changed');
|
|
93
|
+
return archiveManifest(archive, entry.archive);
|
|
94
|
+
})();
|
|
95
|
+
if (!sameManifest(marker.files, expected) || !sameManifest(marker.files, contentManifest(dir))) return null;
|
|
96
|
+
if (!Object.prototype.hasOwnProperty.call(marker.files, entry.bin.replace(/\\/g, '/')) || !fs.lstatSync(bin).isFile()) return null;
|
|
97
|
+
return { path: bin, dir, platform };
|
|
98
|
+
} catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Returns a checksum-bound compressed archive and its complete file manifest.
|
|
105
|
+
* This intentionally does not trust or require extracted files: Windows can
|
|
106
|
+
* keep a rules package compressed and let a pinned Linux runner extract it.
|
|
107
|
+
*/
|
|
108
|
+
export function resolveVerifiedArchive(tool, platform = platformFor(tool)) {
|
|
109
|
+
const entry = tool.platforms?.[platform];
|
|
110
|
+
if (!entry || entry.archive === 'none') return null;
|
|
111
|
+
const dir = installDir(tool, platform);
|
|
112
|
+
try {
|
|
113
|
+
const archive = path.join(dir, ARCHIVE);
|
|
114
|
+
const bytes = fs.readFileSync(archive);
|
|
115
|
+
if (sha256(bytes) !== entry.sha256) return null;
|
|
116
|
+
const archiveOnly = fs.existsSync(path.join(dir, ARCHIVE_MARKER));
|
|
117
|
+
const markerPath = archiveOnly ? path.join(dir, ARCHIVE_MARKER) : path.join(dir, MARKER);
|
|
118
|
+
const marker = JSON.parse(fs.readFileSync(markerPath, 'utf8'));
|
|
119
|
+
if (marker.schemaVersion !== (archiveOnly ? 1 : MARKER_VERSION) || marker.name !== tool.name || marker.version !== tool.version || marker.archiveSha256 !== entry.sha256 || !marker.files) return null;
|
|
120
|
+
if (marker.platform && marker.platform !== platform) return null;
|
|
121
|
+
if (platform !== platformFor(tool) && marker.platform !== platform) return null;
|
|
122
|
+
const expected = archiveManifest(bytes, entry.archive);
|
|
123
|
+
if (!sameManifest(marker.files, expected)) return null;
|
|
124
|
+
return { path: archive, dir, platform, archive: entry.archive, sha256: entry.sha256, files: expected };
|
|
125
|
+
} catch {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Runs the registry's verify command and checks its output. Returns { ok, output }. */
|
|
131
|
+
export async function verifyTool(tool, resolved) {
|
|
132
|
+
if (!resolved) return { ok: false, output: 'installation contents are missing or changed; run vsg setup --repair' };
|
|
133
|
+
if (!tool.verify) return { ok: true, output: '' };
|
|
134
|
+
// a build for another platform (a container build on this host) cannot run here: it is verified by its checksum only
|
|
135
|
+
if (resolved.platform && resolved.platform !== platformKey()) return { ok: true, output: 'checksum verified; runs in a container on this host' };
|
|
136
|
+
const r = await runProcess({ command: resolved.path, args: tool.verify.args, timeoutMs: 30_000 });
|
|
137
|
+
const output = `${r.stdout}\n${r.stderr}`.trim();
|
|
138
|
+
return { ok: r.status === 'ran' && output.includes(tool.verify.expect), output: output.split('\n')[0] ?? '' };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Installs one binary-distributed tool. Returns { status: 'installed'|'already', path }.
|
|
143
|
+
* Throws InstallError on a missing platform build, checksum mismatch, unsafe archive or failed verification.
|
|
144
|
+
*/
|
|
145
|
+
export async function installTool(tool, { force = false, log = () => {}, fetchOpts = {}, platform } = {}) {
|
|
146
|
+
const key = platform ?? platformFor(tool);
|
|
147
|
+
const entry = tool.platforms?.[key];
|
|
148
|
+
if (!entry) throw new InstallError(`${tool.name} has no build for ${key}. Add one to its registry file.`);
|
|
149
|
+
if (!force) {
|
|
150
|
+
const existing = resolveTool(tool, key);
|
|
151
|
+
if (existing) return { status: 'already', path: existing.path };
|
|
152
|
+
const markerPath = path.join(installDir(tool, key), MARKER);
|
|
153
|
+
if (fs.existsSync(markerPath)) throw new InstallError(`${tool.name} has a legacy or unverified installation. Run vsg setup --repair to replace it.`);
|
|
154
|
+
}
|
|
155
|
+
const host = new URL(entry.url).hostname;
|
|
156
|
+
log(`Downloading ${tool.name} ${tool.version} from ${host}`);
|
|
157
|
+
const res = await vfetch(entry.url, { timeoutMs: 600_000, allowHosts: [host], ...fetchOpts });
|
|
158
|
+
if (!res.ok) throw new InstallError(`Download of ${tool.name} failed with HTTP ${res.status}. Retry later.`);
|
|
159
|
+
const actual = sha256(res.body);
|
|
160
|
+
if (actual !== entry.sha256) {
|
|
161
|
+
throw new InstallError(`Checksum mismatch for ${tool.name} ${tool.version}: expected ${entry.sha256}, got ${actual}. The download was refused and nothing was extracted.`);
|
|
162
|
+
}
|
|
163
|
+
const dir = installDir(tool, key);
|
|
164
|
+
const staging = `${dir}.partial-${process.pid}`;
|
|
165
|
+
const aside = `${dir}.old-${process.pid}`; // the previous install waits here until the new one is in place and verified
|
|
166
|
+
fs.rmSync(staging, { recursive: true, force: true });
|
|
167
|
+
fs.rmSync(aside, { recursive: true, force: true });
|
|
168
|
+
let movedAside = false;
|
|
169
|
+
const restoreOld = () => {
|
|
170
|
+
if (!movedAside) return;
|
|
171
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
172
|
+
fs.renameSync(aside, dir);
|
|
173
|
+
movedAside = false;
|
|
174
|
+
};
|
|
175
|
+
try {
|
|
176
|
+
if (entry.archive === 'none') {
|
|
177
|
+
const bin = safeJoin(staging, entry.bin);
|
|
178
|
+
fs.mkdirSync(path.dirname(bin), { recursive: true });
|
|
179
|
+
fs.writeFileSync(bin, res.body);
|
|
180
|
+
} else {
|
|
181
|
+
extractArchive(res.body, entry.archive, staging);
|
|
182
|
+
}
|
|
183
|
+
const bin = safeJoin(staging, entry.bin);
|
|
184
|
+
if (!fs.existsSync(bin)) throw new InstallError(`${tool.name}: expected binary "${entry.bin}" was not found in the download.`);
|
|
185
|
+
if (process.platform !== 'win32' && key.startsWith(process.platform)) fs.chmodSync(bin, 0o755);
|
|
186
|
+
if (entry.archive !== 'none') fs.writeFileSync(path.join(staging, ARCHIVE), res.body);
|
|
187
|
+
const files = contentManifest(staging);
|
|
188
|
+
fs.writeFileSync(path.join(staging, MARKER), JSON.stringify({ schemaVersion: MARKER_VERSION, name: tool.name, version: tool.version, platform: key, archiveSha256: entry.sha256, sha256: entry.sha256, files, installedAt: new Date().toISOString() }));
|
|
189
|
+
fs.mkdirSync(path.dirname(dir), { recursive: true });
|
|
190
|
+
if (fs.existsSync(dir)) { fs.renameSync(dir, aside); movedAside = true; }
|
|
191
|
+
fs.renameSync(staging, dir);
|
|
192
|
+
} catch (e) {
|
|
193
|
+
fs.rmSync(staging, { recursive: true, force: true });
|
|
194
|
+
try { restoreOld(); } catch { /* the old install stays in ${dir}.old-<pid> */ }
|
|
195
|
+
throw e;
|
|
196
|
+
}
|
|
197
|
+
const resolved = resolveTool(tool, key);
|
|
198
|
+
if (!resolved) {
|
|
199
|
+
const hadOld = movedAside;
|
|
200
|
+
if (hadOld) restoreOld();
|
|
201
|
+
else fs.rmSync(dir, { recursive: true, force: true });
|
|
202
|
+
throw new InstallError(`${tool.name} was installed but its extracted contents did not match the verified archive. Run vsg setup --repair.`);
|
|
203
|
+
}
|
|
204
|
+
const check = await verifyTool(tool, resolved);
|
|
205
|
+
if (!check.ok) {
|
|
206
|
+
const hadOld = movedAside;
|
|
207
|
+
if (hadOld) restoreOld();
|
|
208
|
+
else fs.rmSync(dir, { recursive: true, force: true });
|
|
209
|
+
throw new InstallError(`${tool.name} was installed but its version check failed (wanted "${tool.verify.expect}", got "${check.output}"). It was removed${hadOld ? ' and the previous install was restored' : ''}.`);
|
|
210
|
+
}
|
|
211
|
+
fs.rmSync(aside, { recursive: true, force: true });
|
|
212
|
+
return { status: 'installed', path: resolved.path };
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Downloads and verifies an archive without extracting it onto the host. */
|
|
216
|
+
export async function installVerifiedArchive(tool, { force = false, log = () => {}, fetchOpts = {}, platform } = {}) {
|
|
217
|
+
const key = platform ?? platformFor(tool);
|
|
218
|
+
const entry = tool.platforms?.[key];
|
|
219
|
+
if (!entry || entry.archive === 'none') throw new InstallError(`${tool.name} has no archive for ${key}.`);
|
|
220
|
+
if (!force) {
|
|
221
|
+
const existing = resolveVerifiedArchive(tool, key);
|
|
222
|
+
if (existing) return { status: 'already', path: existing.path };
|
|
223
|
+
}
|
|
224
|
+
const host = new URL(entry.url).hostname;
|
|
225
|
+
log(`Downloading ${tool.name} ${tool.version} from ${host}`);
|
|
226
|
+
const res = await vfetch(entry.url, { timeoutMs: 600_000, allowHosts: [host], ...fetchOpts });
|
|
227
|
+
if (!res.ok) throw new InstallError(`Download of ${tool.name} failed with HTTP ${res.status}. Retry later.`);
|
|
228
|
+
const actual = sha256(res.body);
|
|
229
|
+
if (actual !== entry.sha256) throw new InstallError(`Checksum mismatch for ${tool.name} ${tool.version}: expected ${entry.sha256}, got ${actual}. The download was refused and nothing was stored.`);
|
|
230
|
+
const files = archiveManifest(res.body, entry.archive);
|
|
231
|
+
const dir = installDir(tool, key);
|
|
232
|
+
const staging = `${dir}.partial-${process.pid}`;
|
|
233
|
+
const aside = `${dir}.old-${process.pid}`;
|
|
234
|
+
fs.rmSync(staging, { recursive: true, force: true });
|
|
235
|
+
fs.rmSync(aside, { recursive: true, force: true });
|
|
236
|
+
let movedAside = false;
|
|
237
|
+
try {
|
|
238
|
+
fs.mkdirSync(staging, { recursive: true });
|
|
239
|
+
fs.writeFileSync(path.join(staging, ARCHIVE), res.body);
|
|
240
|
+
fs.writeFileSync(path.join(staging, ARCHIVE_MARKER), JSON.stringify({ schemaVersion: 1, name: tool.name, version: tool.version, platform: key, archiveSha256: entry.sha256, files, installedAt: new Date().toISOString() }));
|
|
241
|
+
fs.mkdirSync(path.dirname(dir), { recursive: true });
|
|
242
|
+
if (fs.existsSync(dir)) { fs.renameSync(dir, aside); movedAside = true; }
|
|
243
|
+
fs.renameSync(staging, dir);
|
|
244
|
+
if (!resolveVerifiedArchive(tool, key)) throw new InstallError(`${tool.name} archive failed its post-install integrity check.`);
|
|
245
|
+
fs.rmSync(aside, { recursive: true, force: true });
|
|
246
|
+
return { status: 'installed', path: path.join(dir, ARCHIVE) };
|
|
247
|
+
} catch (e) {
|
|
248
|
+
fs.rmSync(staging, { recursive: true, force: true });
|
|
249
|
+
if (movedAside) {
|
|
250
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
251
|
+
fs.renameSync(aside, dir);
|
|
252
|
+
}
|
|
253
|
+
throw e;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Output-directory lock. A second concurrent run on the same directory exits 3.
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { LockError } from './errors.mjs';
|
|
5
|
+
|
|
6
|
+
const STALE_MS = 6 * 60 * 60 * 1000;
|
|
7
|
+
|
|
8
|
+
const alive = (pid) => {
|
|
9
|
+
try { process.kill(pid, 0); return true; } catch (e) { return e.code === 'EPERM'; }
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/** Creates the output directory (self-ignored by a .gitignore containing *), takes the lock, returns { release }. */
|
|
13
|
+
export function acquireLock(outDir) {
|
|
14
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
15
|
+
const ignore = path.join(outDir, '.gitignore');
|
|
16
|
+
if (!fs.existsSync(ignore)) fs.writeFileSync(ignore, '*\n');
|
|
17
|
+
const lock = path.join(outDir, '.lock');
|
|
18
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
19
|
+
try {
|
|
20
|
+
fs.mkdirSync(lock);
|
|
21
|
+
fs.writeFileSync(path.join(lock, 'pid'), String(process.pid));
|
|
22
|
+
return { release: () => fs.rmSync(lock, { recursive: true, force: true }) };
|
|
23
|
+
} catch (e) {
|
|
24
|
+
if (e.code !== 'EEXIST') throw e;
|
|
25
|
+
let pid = NaN;
|
|
26
|
+
let age = 0;
|
|
27
|
+
try {
|
|
28
|
+
pid = Number(fs.readFileSync(path.join(lock, 'pid'), 'utf8'));
|
|
29
|
+
age = Date.now() - fs.statSync(lock).mtimeMs;
|
|
30
|
+
} catch { /* unreadable lock: treat as stale */ }
|
|
31
|
+
if (Number.isFinite(pid) && pid > 0 && alive(pid) && age < STALE_MS) {
|
|
32
|
+
throw new LockError(`Another vsg run holds the lock on ${outDir} (pid ${pid}). Wait for it to finish, or delete ${lock} if it crashed.`);
|
|
33
|
+
}
|
|
34
|
+
fs.rmSync(lock, { recursive: true, force: true }); // stale: owner is gone
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
throw new LockError(`Could not take the lock on ${outDir}. Delete ${lock} and retry.`);
|
|
38
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// Nested repositories: coding agents leave full checkouts (git worktrees, clones) inside a working copy, usually gitignored.
|
|
2
|
+
// Scanners that deliberately ignore .gitignore would read each copy and report every finding once per copy, so those directories are
|
|
3
|
+
// skipped everywhere and reported once. A directory below the scan root counts as a nested repository when it holds a `.git` entry
|
|
4
|
+
// (a directory, or a file that points at a worktree's git directory) and the outer repository tracks nothing inside it.
|
|
5
|
+
// Tracked content is always scanned: a `.git` file planted inside a tracked folder cannot hide that folder.
|
|
6
|
+
import { spawnSync } from 'node:child_process';
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
|
|
10
|
+
const SKIP_DIRS = new Set(['node_modules', '.git', '.vsg', '.next', '.expo', '.venv', 'venv', '__pycache__', '.turbo', '.cache', 'coverage', 'dist', 'build', '.pnpm-store']);
|
|
11
|
+
const MAX_DEPTH = 10;
|
|
12
|
+
// Coding agents keep their checkouts in folders such as .claude/worktrees and .codex-worktrees. A checkout whose .git entry was removed
|
|
13
|
+
// (a half-cleaned worktree) is still a full copy of the project, so every untracked folder inside such a hidden container counts as nested too.
|
|
14
|
+
const isContainer = (rel) => {
|
|
15
|
+
const parts = rel.split('/');
|
|
16
|
+
const last = parts.at(-1);
|
|
17
|
+
return /^\..*worktrees$/i.test(last) || (/^worktrees$/i.test(last) && (parts.at(-2) ?? '').startsWith('.'));
|
|
18
|
+
};
|
|
19
|
+
const GIT = ['-c', 'core.fsmonitor=false', '--no-optional-locks'];
|
|
20
|
+
|
|
21
|
+
/** Tracked layout of the outer repository, relative to root: { dirs (every directory holding tracked files), gitlinks (submodules) }, or null when git cannot say. */
|
|
22
|
+
function trackedIndex(root) {
|
|
23
|
+
const r = spawnSync('git', [...GIT, 'ls-files', '-s', '-z'], { cwd: root, encoding: 'utf8', maxBuffer: 256 * 1024 * 1024, windowsHide: true });
|
|
24
|
+
if (r.error || r.status !== 0) return null;
|
|
25
|
+
const dirs = new Set();
|
|
26
|
+
const gitlinks = new Set();
|
|
27
|
+
for (const entry of r.stdout.split('\0')) {
|
|
28
|
+
const m = /^(\d+) \S+ \d\t(.+)$/.exec(entry);
|
|
29
|
+
if (!m) continue;
|
|
30
|
+
const p = m[2];
|
|
31
|
+
if (m[1] === '160000') { gitlinks.add(p); continue; }
|
|
32
|
+
for (let i = p.indexOf('/'); i > 0; i = p.indexOf('/', i + 1)) dirs.add(p.slice(0, i));
|
|
33
|
+
}
|
|
34
|
+
return { dirs, gitlinks };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** True when root sits inside a git work tree (its own .git or a parent's). */
|
|
38
|
+
const insideGit = (root) => spawnSync('git', [...GIT, 'rev-parse', '--is-inside-work-tree'], { cwd: root, encoding: 'utf8', windowsHide: true }).stdout?.trim() === 'true';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Nested repositories below `root`: [{ path (relative, posix), kind: 'repo' | 'submodule' }], sorted.
|
|
42
|
+
* Does not enter node_modules and similar, and stops descending at a nested repository.
|
|
43
|
+
* If the outer repository exists but git cannot list it, nothing is skipped: scanning too much is safe, hiding code is not.
|
|
44
|
+
*/
|
|
45
|
+
export function findNestedRepos(root) {
|
|
46
|
+
root = path.resolve(root);
|
|
47
|
+
const found = [];
|
|
48
|
+
let index; // undefined: not asked yet; null: no outer repository; false: git failed
|
|
49
|
+
const outer = () => {
|
|
50
|
+
if (index !== undefined) return index;
|
|
51
|
+
return (index = insideGit(root) ? (trackedIndex(root) ?? false) : null);
|
|
52
|
+
};
|
|
53
|
+
let failed = false;
|
|
54
|
+
const walk = (dir, rel, depth, inContainer = false) => {
|
|
55
|
+
if (depth > MAX_DEPTH || failed) return;
|
|
56
|
+
let entries;
|
|
57
|
+
try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
|
58
|
+
if (rel && (inContainer || entries.some((e) => e.name === '.git'))) {
|
|
59
|
+
const ix = outer();
|
|
60
|
+
if (ix === false) { failed = true; return; }
|
|
61
|
+
if (ix === null || !ix.dirs.has(rel)) {
|
|
62
|
+
found.push({ path: rel, kind: ix?.gitlinks.has(rel) ? 'submodule' : 'repo' });
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// the outer repository tracks files here: not a nested repository, keep looking inside
|
|
66
|
+
}
|
|
67
|
+
for (const e of entries) {
|
|
68
|
+
if (e.isSymbolicLink() || !e.isDirectory() || SKIP_DIRS.has(e.name)) continue;
|
|
69
|
+
walk(path.join(dir, e.name), rel ? `${rel}/${e.name}` : e.name, depth + 1, isContainer(rel));
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
walk(root, '', 0);
|
|
73
|
+
return failed ? [] : found.sort((a, b) => a.path.localeCompare(b.path));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Which of `rels` (root-relative directories) git ignores while the repository tracks nothing in them. check-ignore never reports tracked
|
|
78
|
+
* files, but a directory holding a force-added file is still reported as ignored, so tracked directories are removed here.
|
|
79
|
+
* Returns [] when git cannot say (nothing is then skipped).
|
|
80
|
+
*/
|
|
81
|
+
export function ignoredUntracked(root, rels) {
|
|
82
|
+
if (!rels.length) return [];
|
|
83
|
+
const r = spawnSync('git', [...GIT, 'check-ignore', '-z', '--stdin'], { cwd: root, input: rels.join('\0'), encoding: 'utf8', maxBuffer: 64 * 1024 * 1024, windowsHide: true });
|
|
84
|
+
if (r.error || (r.status !== 0 && r.status !== 1)) return [];
|
|
85
|
+
const ignored = r.stdout.split('\0').filter(Boolean);
|
|
86
|
+
if (!ignored.length) return [];
|
|
87
|
+
const ix = trackedIndex(root);
|
|
88
|
+
return ix ? ignored.filter((p) => !ix.dirs.has(p) && !ix.gitlinks.has(p)) : [];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Trailing `git ls-files` arguments that keep git out of nested checkouts. Without them `ls-files --others` lists every file of every
|
|
93
|
+
* untracked worktree (2.3 million entries, 105 s, on a working copy with 100 of them); with them it takes under a second.
|
|
94
|
+
*/
|
|
95
|
+
export const excludeNested = (nested) => (nested?.length ? ['--', '.', ...nested.map((n) => `:(exclude,literal)${n.path}`)] : []);
|
|
96
|
+
|
|
97
|
+
/** One line for report.md and coverage evidence, or '' when nothing was skipped. */
|
|
98
|
+
export function nestedSummary(nested) {
|
|
99
|
+
if (!nested?.length) return '';
|
|
100
|
+
const first = nested.slice(0, 10).map((n) => (n.kind === 'submodule' ? `${n.path} (submodule, scan it separately)` : n.path));
|
|
101
|
+
return `Skipped ${nested.length} nested git ${nested.length === 1 ? 'repository or worktree' : 'repositories or worktrees'} (not part of this repository): ${first.join(', ')}${nested.length > 10 ? `, and ${nested.length - 10} more` : ''}.`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// listFiles() is called by many checks with only a path; detect() primes this so they all skip the same directories.
|
|
105
|
+
const primed = new Map();
|
|
106
|
+
export const primeNested = (root, nested) => primed.set(path.resolve(root), nested);
|
|
107
|
+
export const primedNested = (root) => primed.get(path.resolve(root));
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
export const packageRoot = fileURLToPath(new URL('../..', import.meta.url));
|
|
6
|
+
export const defaultRegistryDir = path.join(packageRoot, 'tools', 'registry');
|
|
7
|
+
export const defaultChecksDir = path.join(packageRoot, 'src', 'checks');
|
|
8
|
+
export const platformKey = () => `${process.platform}-${process.arch}`;
|
|
9
|
+
|
|
10
|
+
export function vsgHome() {
|
|
11
|
+
return process.env.VSG_HOME || path.join(os.homedir(), '.vsg');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function toolsDir() {
|
|
15
|
+
if (process.env.VSG_TOOLS_DIR) return process.env.VSG_TOOLS_DIR;
|
|
16
|
+
if (process.platform === 'win32') {
|
|
17
|
+
return path.join(process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'), 'vsg', 'tools');
|
|
18
|
+
}
|
|
19
|
+
return path.join(process.env.XDG_CACHE_HOME || path.join(os.homedir(), '.cache'), 'vsg', 'tools');
|
|
20
|
+
}
|