@nurix/etna 0.19.42 → 0.19.43
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/bin/etna.js +14 -0
- package/data/harness-index.json +5 -1
- package/data/harnesses/apollo/.prettierignore +29 -0
- package/data/harnesses/apollo/.prettierrc.json +3 -0
- package/data/harnesses/apollo/.vscode/settings.json +19 -0
- package/data/harnesses/apollo/CLAUDE.md +162 -0
- package/data/harnesses/apollo/agents/brainstorm.md +144 -0
- package/data/harnesses/apollo/agents/change-review.md +251 -0
- package/data/harnesses/apollo/agents/lld-mode.md +56 -0
- package/data/harnesses/apollo/agents/maintenance.md +229 -0
- package/data/harnesses/apollo/agents/performance-review.md +223 -0
- package/data/harnesses/apollo/agents/retro.md +46 -0
- package/data/harnesses/apollo/codex/agents/brainstorm.toml +142 -0
- package/data/harnesses/apollo/codex/agents/change-review.toml +249 -0
- package/data/harnesses/apollo/codex/agents/lld-mode.toml +52 -0
- package/data/harnesses/apollo/codex/agents/maintenance.toml +228 -0
- package/data/harnesses/apollo/codex/agents/performance-review.toml +222 -0
- package/data/harnesses/apollo/codex/agents/retro.toml +45 -0
- package/data/harnesses/apollo/docs/README.md +28 -0
- package/data/harnesses/apollo/docs/history/CHANGELOG.md +26 -0
- package/data/harnesses/apollo/docs/history/backlog.md +19 -0
- package/data/harnesses/apollo/docs/memory/main.md +15 -0
- package/data/harnesses/apollo/docs/structure.md +54 -0
- package/data/harnesses/apollo/harness.json +18 -0
- package/data/harnesses/apollo/hooks/generate-ownership-index.mjs +148 -0
- package/data/harnesses/apollo/hooks/hooks.json +16 -0
- package/data/harnesses/apollo/rules/changelog.md +19 -0
- package/data/harnesses/apollo/rules/database.md +123 -0
- package/data/harnesses/apollo/rules/express.md +33 -0
- package/data/harnesses/apollo/rules/frontend.md +32 -0
- package/data/harnesses/apollo/rules/general.md +62 -0
- package/data/harnesses/apollo/rules/nomenclature.md +34 -0
- package/data/harnesses/apollo/rules/pnpm.md +57 -0
- package/data/harnesses/apollo/rules/testing.md +23 -0
- package/data/harnesses/apollo/rules/verification.md +67 -0
- package/data/harnesses/apollo/skills/boundary/SKILL.md +69 -0
- package/data/harnesses/apollo/skills/boundary/references/index.md +16 -0
- package/data/harnesses/apollo/skills/boundary/references/mechanisms.md +99 -0
- package/data/harnesses/apollo/skills/boundary/references/packs/async-messaging.md +81 -0
- package/data/harnesses/apollo/skills/boundary/references/packs/auth.md +93 -0
- package/data/harnesses/apollo/skills/boundary/references/packs/build-config-runtime.md +93 -0
- package/data/harnesses/apollo/skills/boundary/references/packs/cloudflare.md +93 -0
- package/data/harnesses/apollo/skills/boundary/references/packs/frontend.md +93 -0
- package/data/harnesses/apollo/skills/boundary/references/packs/generic-tail.md +55 -0
- package/data/harnesses/apollo/skills/boundary/references/packs/persistence.md +93 -0
- package/data/harnesses/apollo/skills/boundary/references/packs/wire-api.md +87 -0
- package/data/harnesses/apollo/skills/brainstorm/README.md +56 -0
- package/data/harnesses/apollo/skills/brainstorm/SKILL.md +173 -0
- package/data/harnesses/apollo/skills/brainstorm/references/doctrine.md +98 -0
- package/data/harnesses/apollo/skills/brainstorm/references/harvest.md +86 -0
- package/data/harnesses/apollo/skills/brainstorm/references/session-schema.md +186 -0
- package/data/harnesses/apollo/skills/brainstorm/scripts/detector.mjs +460 -0
- package/data/harnesses/apollo/skills/design/SKILL.md +100 -0
- package/data/harnesses/apollo/skills/design/components/charts.md +76 -0
- package/data/harnesses/apollo/skills/design/components/collections.md +132 -0
- package/data/harnesses/apollo/skills/design/components/feedback.md +47 -0
- package/data/harnesses/apollo/skills/design/components/hooks.md +35 -0
- package/data/harnesses/apollo/skills/design/components/index.md +143 -0
- package/data/harnesses/apollo/skills/design/components/inputs.md +327 -0
- package/data/harnesses/apollo/skills/design/components/layout.md +52 -0
- package/data/harnesses/apollo/skills/design/components/media.md +66 -0
- package/data/harnesses/apollo/skills/design/components/motion.md +82 -0
- package/data/harnesses/apollo/skills/design/components/navigation.md +29 -0
- package/data/harnesses/apollo/skills/design/components/overlays.md +72 -0
- package/data/harnesses/apollo/skills/design/components/setup.md +40 -0
- package/data/harnesses/apollo/skills/design/components/typography.md +46 -0
- package/data/harnesses/apollo/skills/design/components/utils.md +37 -0
- package/data/harnesses/apollo/skills/design/data/blueprints/browse.md +38 -0
- package/data/harnesses/apollo/skills/design/data/blueprints/creation-flow.md +38 -0
- package/data/harnesses/apollo/skills/design/data/blueprints/dashboard.md +38 -0
- package/data/harnesses/apollo/skills/design/data/blueprints/grid.md +38 -0
- package/data/harnesses/apollo/skills/design/data/blueprints/queue.md +38 -0
- package/data/harnesses/apollo/skills/design/data/blueprints/record-detail.md +38 -0
- package/data/harnesses/apollo/skills/design/data/blueprints/settings.md +38 -0
- package/data/harnesses/apollo/skills/design/data/chart-styling/Readme.md +33 -0
- package/data/harnesses/apollo/skills/design/data/chart-styling/carbon-accessible-alert-semantic.md +19 -0
- package/data/harnesses/apollo/skills/design/data/chart-styling/carbon-monochrome-sequential-trend.md +19 -0
- package/data/harnesses/apollo/skills/design/data/chart-styling/datadog-classic-six-aligned.md +19 -0
- package/data/harnesses/apollo/skills/design/data/chart-styling/datawrapper-tiered-gray-hierarchy.md +19 -0
- package/data/harnesses/apollo/skills/design/data/chart-styling/econ-red-rule-horizontal.md +19 -0
- package/data/harnesses/apollo/skills/design/data/chart-styling/financial-diverging-threshold-overlay.md +19 -0
- package/data/harnesses/apollo/skills/design/data/chart-styling/ft-vocabulary-ranked-muted.md +19 -0
- package/data/harnesses/apollo/skills/design/data/chart-styling/grafana-dark-threshold-bands.md +19 -0
- package/data/harnesses/apollo/skills/design/data/chart-styling/material-rounded-explicit-label.md +19 -0
- package/data/harnesses/apollo/skills/design/data/chart-styling/nyt-ghost-grid-direct-label.md +19 -0
- package/data/harnesses/apollo/skills/design/data/chart-styling/plot-currentcolor-inherit.md +19 -0
- package/data/harnesses/apollo/skills/design/data/chart-styling/saas-gradient-glow-area.md +19 -0
- package/data/harnesses/apollo/skills/design/data/chart-styling/shadcn-composable-css-vars.md +19 -0
- package/data/harnesses/apollo/skills/design/data/charts/census.csv +58 -0
- package/data/harnesses/apollo/skills/design/data/checklists/browse.md +21 -0
- package/data/harnesses/apollo/skills/design/data/checklists/creation-flow.md +20 -0
- package/data/harnesses/apollo/skills/design/data/checklists/dashboard.md +21 -0
- package/data/harnesses/apollo/skills/design/data/checklists/grid.md +21 -0
- package/data/harnesses/apollo/skills/design/data/checklists/queue.md +21 -0
- package/data/harnesses/apollo/skills/design/data/checklists/record-detail.md +21 -0
- package/data/harnesses/apollo/skills/design/data/checklists/settings.md +21 -0
- package/data/harnesses/apollo/skills/design/data/chrome/board-column.md +68 -0
- package/data/harnesses/apollo/skills/design/data/chrome/data-table.md +63 -0
- package/data/harnesses/apollo/skills/design/data/chrome/side-panel.md +60 -0
- package/data/harnesses/apollo/skills/design/data/chrome/sidebar.md +78 -0
- package/data/harnesses/apollo/skills/design/data/chrome/stat-cards.md +62 -0
- package/data/harnesses/apollo/skills/design/data/chrome/topbar.md +65 -0
- package/data/harnesses/apollo/skills/design/data/color/accent-presets.md +90 -0
- package/data/harnesses/apollo/skills/design/data/color/aesop-earth-mute.md +91 -0
- package/data/harnesses/apollo/skills/design/data/color/arc-peach-play.md +90 -0
- package/data/harnesses/apollo/skills/design/data/color/attio-hunter-teal.md +90 -0
- package/data/harnesses/apollo/skills/design/data/color/carbon-cyan-signal.md +90 -0
- package/data/harnesses/apollo/skills/design/data/color/clay-parchment.md +90 -0
- package/data/harnesses/apollo/skills/design/data/color/duolingo-feather.md +90 -0
- package/data/harnesses/apollo/skills/design/data/color/geist-mono-signal.md +90 -0
- package/data/harnesses/apollo/skills/design/data/color/linear-graphite-violet.md +90 -0
- package/data/harnesses/apollo/skills/design/data/color/mercury-onyx-cobalt.md +90 -0
- package/data/harnesses/apollo/skills/design/data/color/notion-paper-ink.md +90 -0
- package/data/harnesses/apollo/skills/design/data/color/radix-slate-iris.md +90 -0
- package/data/harnesses/apollo/skills/design/data/color/raycast-void-spectrum.md +90 -0
- package/data/harnesses/apollo/skills/design/data/color/spectrum-celery-fuchsia.md +90 -0
- package/data/harnesses/apollo/skills/design/data/color/stripe-blurple-ruby.md +90 -0
- package/data/harnesses/apollo/skills/design/data/color/superhuman-cod-picton.md +89 -0
- package/data/harnesses/apollo/skills/design/data/corpora/operations-review/companies.csv +15 -0
- package/data/harnesses/apollo/skills/design/data/corpora/operations-review/corpus.md +87 -0
- package/data/harnesses/apollo/skills/design/data/corpora/operations-review/people.csv +25 -0
- package/data/harnesses/apollo/skills/design/data/corpora/procurement-approvals/companies.csv +15 -0
- package/data/harnesses/apollo/skills/design/data/corpora/procurement-approvals/corpus.md +83 -0
- package/data/harnesses/apollo/skills/design/data/corpora/procurement-approvals/people.csv +25 -0
- package/data/harnesses/apollo/skills/design/data/corpora/revenue-analytics/companies.csv +15 -0
- package/data/harnesses/apollo/skills/design/data/corpora/revenue-analytics/corpus.md +89 -0
- package/data/harnesses/apollo/skills/design/data/corpora/revenue-analytics/people.csv +25 -0
- package/data/harnesses/apollo/skills/design/data/elevation/ant-design-directional-shadow.md +19 -0
- package/data/harnesses/apollo/skills/design/data/elevation/apple-liquid-glass-material.md +18 -0
- package/data/harnesses/apollo/skills/design/data/elevation/atlassian-surface-shadow-pairing.md +20 -0
- package/data/harnesses/apollo/skills/design/data/elevation/fluent-2-key-ambient-ramp.md +20 -0
- package/data/harnesses/apollo/skills/design/data/elevation/github-primer-sparing-shadow.md +19 -0
- package/data/harnesses/apollo/skills/design/data/elevation/ibm-carbon-layer-and-border.md +19 -0
- package/data/harnesses/apollo/skills/design/data/elevation/linear-dark-surface-ladder.md +17 -0
- package/data/harnesses/apollo/skills/design/data/elevation/material-2-key-ambient-dp-ramp.md +19 -0
- package/data/harnesses/apollo/skills/design/data/elevation/material-3-tonal-elevation.md +21 -0
- package/data/harnesses/apollo/skills/design/data/elevation/neobrutalist-hard-offset.md +19 -0
- package/data/harnesses/apollo/skills/design/data/elevation/neumorphic-soft-dual-shadow.md +18 -0
- package/data/harnesses/apollo/skills/design/data/elevation/notion-warm-minimal-hairline.md +17 -0
- package/data/harnesses/apollo/skills/design/data/elevation/polaris-elevation-inset-bevel.md +21 -0
- package/data/harnesses/apollo/skills/design/data/elevation/radix-themes-alpha-ring-scale.md +19 -0
- package/data/harnesses/apollo/skills/design/data/elevation/shadcn-neutral-derived-radius.md +19 -0
- package/data/harnesses/apollo/skills/design/data/elevation/stripe-brand-tinted-dual-shadow.md +18 -0
- package/data/harnesses/apollo/skills/design/data/elevation/tailwind-default-utility-scale.md +19 -0
- package/data/harnesses/apollo/skills/design/data/elevation/vercel-geist-shadow-as-border.md +20 -0
- package/data/harnesses/apollo/skills/design/data/gradients/amber-attention-fill.md +16 -0
- package/data/harnesses/apollo/skills/design/data/gradients/cloud-shadow-wash.md +16 -0
- package/data/harnesses/apollo/skills/design/data/gradients/confident-lavender-wash.md +16 -0
- package/data/harnesses/apollo/skills/design/data/gradients/ember-ship-flare.md +18 -0
- package/data/harnesses/apollo/skills/design/data/gradients/full-metal-wash.md +16 -0
- package/data/harnesses/apollo/skills/design/data/gradients/indigo-ruby-cta-band.md +18 -0
- package/data/harnesses/apollo/skills/design/data/gradients/linear-graphite-wash.md +18 -0
- package/data/harnesses/apollo/skills/design/data/gradients/marble-quartz-wash.md +16 -0
- package/data/harnesses/apollo/skills/design/data/gradients/midnight-aurora-panel.md +16 -0
- package/data/harnesses/apollo/skills/design/data/gradients/neutral-volume-fill.md +16 -0
- package/data/harnesses/apollo/skills/design/data/gradients/revenue-uptrend-fill.md +16 -0
- package/data/harnesses/apollo/skills/design/data/gradients/risk-decline-fill.md +16 -0
- package/data/harnesses/apollo/skills/design/data/gradients/signal-blue-develop.md +18 -0
- package/data/harnesses/apollo/skills/design/data/gradients/slate-mist-wash.md +16 -0
- package/data/harnesses/apollo/skills/design/data/gradients/stripe-atmosphere-mesh.md +18 -0
- package/data/harnesses/apollo/skills/design/data/gradients/teal-signal-accent.md +16 -0
- package/data/harnesses/apollo/skills/design/data/gradients/violet-magenta-promo.md +16 -0
- package/data/harnesses/apollo/skills/design/data/iconography.md +199 -0
- package/data/harnesses/apollo/skills/design/data/motion/accordion-expand.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/destructive-hold-confirm.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/drag-dismiss-momentum.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/empty-state-arrive.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/hover-lift.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/modal-center-arrive.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/number-ticker-roll.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/onboarding-bounce.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/panel-slide.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/press-feedback.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/progress-linear-loop.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/route-crossfade.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/rubber-band-overscroll.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/skeleton-shimmer.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/stagger-arrive.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/toast-enter-stack.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/tooltip-chain-instant.md +18 -0
- package/data/harnesses/apollo/skills/design/data/motion/trigger-anchored-reveal.md +18 -0
- package/data/harnesses/apollo/skills/design/data/tells.csv +34 -0
- package/data/harnesses/apollo/skills/design/data/typography/anton-work-sans.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/archivo-black-archivo.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/bitter-karla.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/dm-serif-dm-sans.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/fraunces-inter.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/geist-geist-mono.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/hubot-sans-mona-sans.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/ibm-plex-sans-operator-single-family.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/instrument-serif-instrument-sans.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/inter-operator-single-family.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/libre-baskerville-libre-franklin.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/newsreader-inter.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/playfair-display-source-sans.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/public-sans-operator-single-family.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/sohne-inter-fintech.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/source-serif-source-sans.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/space-grotesk-work-sans-space-mono.md +17 -0
- package/data/harnesses/apollo/skills/design/data/typography/spectral-manrope.md +17 -0
- package/data/harnesses/apollo/skills/design/data/voices/bright-collaborator.md +29 -0
- package/data/harnesses/apollo/skills/design/data/voices/direct-operator.md +29 -0
- package/data/harnesses/apollo/skills/design/data/voices/earnest-helper.md +29 -0
- package/data/harnesses/apollo/skills/design/data/voices/editorial-composed.md +29 -0
- package/data/harnesses/apollo/skills/design/data/voices/quiet-concierge.md +29 -0
- package/data/harnesses/apollo/skills/design/data/voices/warm-guide.md +29 -0
- package/data/harnesses/apollo/skills/design/design-md/SCHEMA.md +179 -0
- package/data/harnesses/apollo/skills/design/design-md/index.csv +67 -0
- package/data/harnesses/apollo/skills/design/design-md/library/airbnb.md +207 -0
- package/data/harnesses/apollo/skills/design/design-md/library/airtable.md +205 -0
- package/data/harnesses/apollo/skills/design/design-md/library/anthropic-claude.md +203 -0
- package/data/harnesses/apollo/skills/design/design-md/library/apple.md +206 -0
- package/data/harnesses/apollo/skills/design/design-md/library/binance.md +210 -0
- package/data/harnesses/apollo/skills/design/design-md/library/bmw.md +210 -0
- package/data/harnesses/apollo/skills/design/design-md/library/cal.md +209 -0
- package/data/harnesses/apollo/skills/design/design-md/library/clay.md +204 -0
- package/data/harnesses/apollo/skills/design/design-md/library/clickhouse.md +205 -0
- package/data/harnesses/apollo/skills/design/design-md/library/cohere.md +205 -0
- package/data/harnesses/apollo/skills/design/design-md/library/coinbase.md +198 -0
- package/data/harnesses/apollo/skills/design/design-md/library/composio.md +198 -0
- package/data/harnesses/apollo/skills/design/design-md/library/cursor.md +197 -0
- package/data/harnesses/apollo/skills/design/design-md/library/elevenlabs.md +199 -0
- package/data/harnesses/apollo/skills/design/design-md/library/expo.md +200 -0
- package/data/harnesses/apollo/skills/design/design-md/library/figma.md +199 -0
- package/data/harnesses/apollo/skills/design/design-md/library/framer.md +202 -0
- package/data/harnesses/apollo/skills/design/design-md/library/hashicorp.md +205 -0
- package/data/harnesses/apollo/skills/design/design-md/library/ibm.md +205 -0
- package/data/harnesses/apollo/skills/design/design-md/library/intercom.md +204 -0
- package/data/harnesses/apollo/skills/design/design-md/library/kraken.md +200 -0
- package/data/harnesses/apollo/skills/design/design-md/library/linear-app.md +198 -0
- package/data/harnesses/apollo/skills/design/design-md/library/lovable.md +199 -0
- package/data/harnesses/apollo/skills/design/design-md/library/meta.md +204 -0
- package/data/harnesses/apollo/skills/design/design-md/library/minimax.md +204 -0
- package/data/harnesses/apollo/skills/design/design-md/library/mintlify.md +210 -0
- package/data/harnesses/apollo/skills/design/design-md/library/miro.md +209 -0
- package/data/harnesses/apollo/skills/design/design-md/library/mistral-ai.md +201 -0
- package/data/harnesses/apollo/skills/design/design-md/library/mongodb.md +201 -0
- package/data/harnesses/apollo/skills/design/design-md/library/notion.md +204 -0
- package/data/harnesses/apollo/skills/design/design-md/library/nvidia.md +215 -0
- package/data/harnesses/apollo/skills/design/design-md/library/ollama.md +213 -0
- package/data/harnesses/apollo/skills/design/design-md/library/opencode-ai.md +216 -0
- package/data/harnesses/apollo/skills/design/design-md/library/posthog.md +218 -0
- package/data/harnesses/apollo/skills/design/design-md/library/raycast.md +214 -0
- package/data/harnesses/apollo/skills/design/design-md/library/replicate.md +202 -0
- package/data/harnesses/apollo/skills/design/design-md/library/resend.md +203 -0
- package/data/harnesses/apollo/skills/design/design-md/library/revolut.md +203 -0
- package/data/harnesses/apollo/skills/design/design-md/library/runwayml.md +203 -0
- package/data/harnesses/apollo/skills/design/design-md/library/sanity.md +200 -0
- package/data/harnesses/apollo/skills/design/design-md/library/sentry.md +201 -0
- package/data/harnesses/apollo/skills/design/design-md/library/shopify.md +202 -0
- package/data/harnesses/apollo/skills/design/design-md/library/slack.md +202 -0
- package/data/harnesses/apollo/skills/design/design-md/library/spacex.md +206 -0
- package/data/harnesses/apollo/skills/design/design-md/library/spotify.md +206 -0
- package/data/harnesses/apollo/skills/design/design-md/library/stripe.md +196 -0
- package/data/harnesses/apollo/skills/design/design-md/library/supabase.md +196 -0
- package/data/harnesses/apollo/skills/design/design-md/library/superhuman.md +194 -0
- package/data/harnesses/apollo/skills/design/design-md/library/tesla.md +198 -0
- package/data/harnesses/apollo/skills/design/design-md/library/theverge.md +199 -0
- package/data/harnesses/apollo/skills/design/design-md/library/together-ai.md +193 -0
- package/data/harnesses/apollo/skills/design/design-md/library/uber.md +195 -0
- package/data/harnesses/apollo/skills/design/design-md/library/vercel.md +195 -0
- package/data/harnesses/apollo/skills/design/design-md/library/voltagent.md +197 -0
- package/data/harnesses/apollo/skills/design/design-md/library/warp.md +196 -0
- package/data/harnesses/apollo/skills/design/design-md/library/webflow.md +197 -0
- package/data/harnesses/apollo/skills/design/design-md/library/wired.md +197 -0
- package/data/harnesses/apollo/skills/design/design-md/library/wise.md +198 -0
- package/data/harnesses/apollo/skills/design/design-md/library/x-ai.md +199 -0
- package/data/harnesses/apollo/skills/design/design-md/library/zapier.md +198 -0
- package/data/harnesses/apollo/skills/design/design-md/nurix.md +214 -0
- package/data/harnesses/apollo/skills/design/design-md/variants/editorial-luxury.md +184 -0
- package/data/harnesses/apollo/skills/design/design-md/variants/expressive-saas.md +216 -0
- package/data/harnesses/apollo/skills/design/design-md/variants/quiet-premium.md +211 -0
- package/data/harnesses/apollo/skills/design/design-md/variants/terse-dense-operator.md +212 -0
- package/data/harnesses/apollo/skills/design/design-md/variants/warm-approachable.md +216 -0
- package/data/harnesses/apollo/skills/design/references/compose.md +23 -0
- package/data/harnesses/apollo/skills/design/references/content.md +28 -0
- package/data/harnesses/apollo/skills/design/references/emission.md +21 -0
- package/data/harnesses/apollo/skills/design/references/existing-apps.md +27 -0
- package/data/harnesses/apollo/skills/design/references/intake.md +36 -0
- package/data/harnesses/apollo/skills/design/references/object-pass.md +24 -0
- package/data/harnesses/apollo/skills/design/references/ship-gate.md +29 -0
- package/data/harnesses/apollo/skills/design/references/ux-patterns/Readme.md +195 -0
- package/data/harnesses/apollo/skills/design/references/ux-patterns/ai-layer.md +49 -0
- package/data/harnesses/apollo/skills/design/references/ux-patterns/attributes-lifecycle.md +43 -0
- package/data/harnesses/apollo/skills/design/references/ux-patterns/container-choice.md +44 -0
- package/data/harnesses/apollo/skills/design/references/ux-patterns/creation-paths.md +46 -0
- package/data/harnesses/apollo/skills/design/references/ux-patterns/dashboards.md +42 -0
- package/data/harnesses/apollo/skills/design/references/ux-patterns/modes.md +42 -0
- package/data/harnesses/apollo/skills/design/references/ux-patterns/object-model.md +46 -0
- package/data/harnesses/apollo/skills/design/references/ux-patterns/page-archetype.md +48 -0
- package/data/harnesses/apollo/skills/design/references/ux-patterns/promotion-demotion.md +37 -0
- package/data/harnesses/apollo/skills/design/references/ux-patterns/settings.md +42 -0
- package/data/harnesses/apollo/skills/design/references/ux-patterns/standard-pages.md +46 -0
- package/data/harnesses/apollo/skills/design/references/ux-patterns/state-matrix.md +41 -0
- package/data/harnesses/apollo/skills/design/references/ux-patterns/table-mechanics.md +48 -0
- package/data/harnesses/apollo/skills/design/references/ux-patterns/verbs.md +45 -0
- package/data/harnesses/apollo/skills/design/references/ux-patterns/viewer-context.md +40 -0
- package/data/harnesses/apollo/skills/design/scripts/README-validator.md +27 -0
- package/data/harnesses/apollo/skills/design/scripts/select-chart.mjs +596 -0
- package/data/harnesses/apollo/skills/design/scripts/validate-design-md.mjs +1198 -0
- package/data/harnesses/apollo/skills/documentation/SKILL.md +132 -0
- package/data/harnesses/apollo/skills/documentation/references/examples.md +279 -0
- package/data/harnesses/apollo/skills/documentation/references/frontmatter.md +44 -0
- package/data/harnesses/apollo/skills/documentation/references/instruction-style.md +49 -0
- package/data/harnesses/apollo/skills/documentation/references/style-guide.md +351 -0
- package/data/harnesses/apollo/skills/documentation/references/untemplated.md +38 -0
- package/data/harnesses/apollo/skills/documentation/scripts/doc-lint.mjs +140 -0
- package/data/harnesses/apollo/skills/documentation/templates/Readme.md +32 -0
- package/data/harnesses/apollo/skills/documentation/templates/api-reference.md +20 -0
- package/data/harnesses/apollo/skills/documentation/templates/architecture-decision.md +121 -0
- package/data/harnesses/apollo/skills/documentation/templates/backlog.md +33 -0
- package/data/harnesses/apollo/skills/documentation/templates/behavioral-checklist.md +79 -0
- package/data/harnesses/apollo/skills/documentation/templates/changelog-entry.md +57 -0
- package/data/harnesses/apollo/skills/documentation/templates/changelog-index.md +41 -0
- package/data/harnesses/apollo/skills/documentation/templates/docs-readme.md +72 -0
- package/data/harnesses/apollo/skills/documentation/templates/domain-model.md +30 -0
- package/data/harnesses/apollo/skills/documentation/templates/environment-registry.md +15 -0
- package/data/harnesses/apollo/skills/documentation/templates/feature.md +149 -0
- package/data/harnesses/apollo/skills/documentation/templates/glossary.md +11 -0
- package/data/harnesses/apollo/skills/documentation/templates/memory-main.md +25 -0
- package/data/harnesses/apollo/skills/documentation/templates/migration-runbook.md +34 -0
- package/data/harnesses/apollo/skills/documentation/templates/non-goals.md +11 -0
- package/data/harnesses/apollo/skills/documentation/templates/operations-procedure.md +36 -0
- package/data/harnesses/apollo/skills/documentation/templates/plan.md +71 -0
- package/data/harnesses/apollo/skills/documentation/templates/protected-files.md +37 -0
- package/data/harnesses/apollo/skills/documentation/templates/root-readme.md +104 -0
- package/data/harnesses/apollo/skills/documentation/templates/security-overview.md +27 -0
- package/data/harnesses/apollo/skills/documentation/templates/structure.md +65 -0
- package/data/harnesses/apollo/skills/documentation/templates/system-overview.md +32 -0
- package/data/harnesses/apollo/skills/documentation/templates/testing-strategy.md +29 -0
- package/data/harnesses/apollo/skills/test-plan/SKILL.md +83 -0
- package/data/harnesses/apollo/skills/workflow-mapper/SKILL.md +451 -0
- package/data/harnesses/apollo/skills/workflow-mapper/references/patterns.md +214 -0
- package/data/harnesses/code/agents/maintenance.md +2 -2
- package/data/harnesses/code/codex/agents/maintenance.toml +2 -2
- package/data/harnesses/code/harness.json +3 -2
- package/data/harnesses/delivery/agents/maintenance.md +2 -2
- package/data/harnesses/delivery/codex/agents/maintenance.toml +2 -2
- package/data/harnesses/delivery/harness.json +3 -2
- package/data/harnesses/discover/harness.json +2 -1
- package/data/harnesses/discussion/harness.json +1 -0
- package/data/harnesses/etna/agents/maintenance.md +2 -2
- package/data/harnesses/etna/codex/agents/maintenance.toml +2 -2
- package/data/harnesses/etna/harness.json +3 -2
- package/data/harnesses/hr/harness.json +1 -0
- package/data/harnesses/kb-agi/harness.json +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Session schema — the single format authority
|
|
2
|
+
|
|
3
|
+
Load when: bootstrapping a session, writing any working-surface file, dispatching the twin, or
|
|
4
|
+
interpreting detector output. The detector (`scripts/detector.mjs`) is the mechanical half of this
|
|
5
|
+
contract — every rule below that carries a rule ID is machine-checked; everything else is the
|
|
6
|
+
twin's semantic judgment.
|
|
7
|
+
|
|
8
|
+
## Folder layout
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
docs/research/{topic}-brainstorm/ ← open session (kebab-case topic slug)
|
|
12
|
+
├── state.md ← anchor + aspect map (twin-written)
|
|
13
|
+
├── thesis.md ← composed claim → argument → what changed (twin-written)
|
|
14
|
+
├── forks.md ← open questions with close conditions (twin-written)
|
|
15
|
+
├── ledger.md ← commitments (twin-written)
|
|
16
|
+
├── basis/ ← frozen entry material (facilitator-written once, at intake)
|
|
17
|
+
├── fragments/ ← harvest-native fragments (twin-written; materialize on
|
|
18
|
+
│ first real content, drafted in destination format)
|
|
19
|
+
└── ops/ ← untracked capture layer (deleted at stop)
|
|
20
|
+
├── .gitignore ← contains `*` — ops/ never enters git [BS-OPS-01/02]
|
|
21
|
+
├── capture.md ← facilitator's raw append ledger (its ONLY write)
|
|
22
|
+
├── sync-log.md ← paired twin-dispatch log
|
|
23
|
+
└── manifest.md ← harvest manifest (created by the stop pipeline)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
On a passed harvest the folder **moves** to `docs/history/brainstorms/{topic}/` (ops/ deleted
|
|
27
|
+
first) — the move is the completion marker; the user then deletes or commits it. A folder still
|
|
28
|
+
under `docs/research/` is by definition unfinished.
|
|
29
|
+
|
|
30
|
+
**Write protocol (one writer per file):** the facilitator appends to `ops/capture.md` and writes
|
|
31
|
+
the initial `basis/` copy plus the sync-log *dispatch* lines — nothing else, ever. The twin writes
|
|
32
|
+
every other file, at gates. The user may hand-edit anything; the twin diffs each file against its
|
|
33
|
+
own last compose before rewriting and folds foreign edits as first-class user signal.
|
|
34
|
+
|
|
35
|
+
## state.md
|
|
36
|
+
|
|
37
|
+
```markdown
|
|
38
|
+
# State
|
|
39
|
+
|
|
40
|
+
- Status: open | stopping | harvested
|
|
41
|
+
- Posture: mid-probe on the sync-layer aspect, three forks open
|
|
42
|
+
- Started: 2026-07-08
|
|
43
|
+
- Sitting: single | multi
|
|
44
|
+
- Last compose: 2026-07-08T14:30Z | never
|
|
45
|
+
|
|
46
|
+
## Aspect map
|
|
47
|
+
|
|
48
|
+
- persistence — how session state survives restarts → F1, D3
|
|
49
|
+
- onboarding — the first-run experience → thesis
|
|
50
|
+
- risks — failure modes and mitigations → none yet
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- `Status` transitions only forward: `open → stopping → harvested` (the twin flips `stopping` when
|
|
54
|
+
the stop pipeline begins, `harvested` at the move). [BS-STATE-01]
|
|
55
|
+
- The aspect map is derived per idea from the basis and edited by the user. Each aspect carries
|
|
56
|
+
`→` refs to the content covering it: fork IDs (`F#`), ledger IDs (`D#`), `thesis`,
|
|
57
|
+
`fragment:{name}`, or `none yet` (an open coverage gap — informational mid-session
|
|
58
|
+
[BS-ASPECT-01], blocking at the manifest gate [BS-ASPECT-02]). Ref *presence* is the detector's
|
|
59
|
+
half; whether the content actually covers the aspect is the twin's.
|
|
60
|
+
|
|
61
|
+
## thesis.md
|
|
62
|
+
|
|
63
|
+
```markdown
|
|
64
|
+
# {Topic} — thesis
|
|
65
|
+
|
|
66
|
+
Current as of: 2026-07-08T14:30Z
|
|
67
|
+
|
|
68
|
+
## Claim
|
|
69
|
+
## Argument
|
|
70
|
+
## What changed
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Composed prose, rewritten whole at every compose, never appended. The three sections and the
|
|
74
|
+
stamp are mandatory [BS-THESIS-01]; the stamp must equal state.md's `Last compose`
|
|
75
|
+
[BS-COMPOSE-01]. At the manifest gate, `Last compose` must be later than the newest
|
|
76
|
+
`ops/capture.md` entry — a compose over unsynced capture is stale [BS-COMPOSE-02].
|
|
77
|
+
|
|
78
|
+
## forks.md
|
|
79
|
+
|
|
80
|
+
```markdown
|
|
81
|
+
## F3 — Should reads wait for a compose? [open]
|
|
82
|
+
|
|
83
|
+
Full self-contained prose in the user's framing.
|
|
84
|
+
|
|
85
|
+
- Raised by: user | twin (S4) | probe | harvest
|
|
86
|
+
- Closes when: a pick between wait-for-fresh and read-stale-with-warning
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
- IDs `F1, F2, …` unique, never reused [BS-FORK-01]. Status marker: `[open]` or
|
|
90
|
+
`[parked → {destination}]`. Every fork carries `Closes when:` [BS-FORK-01].
|
|
91
|
+
- `Raised by: twin (S#)` must cite a reconciled sync-log entry [BS-SYNC-02].
|
|
92
|
+
- **A resolved fork's entry is deleted** by the twin — the resolving ledger entry's `Resolves:`
|
|
93
|
+
field is the record. forks.md holds only open and parked forks; a ledger `Resolves: F3`
|
|
94
|
+
coexisting with an open F3 is an inconsistency [BS-FORK-02]. Parked forks survive to the
|
|
95
|
+
manifest, which must route each one [BS-MANIFEST-01].
|
|
96
|
+
- The manifest gate requires zero `[open]` forks [BS-FORK-03].
|
|
97
|
+
|
|
98
|
+
## ledger.md
|
|
99
|
+
|
|
100
|
+
```markdown
|
|
101
|
+
## D4 — Sessions initialize in dump or interview
|
|
102
|
+
|
|
103
|
+
- Decision: every session opens in dump or interview; probe and converge are mid-session moves.
|
|
104
|
+
- Why: a first-time user cannot be asked to pick a posture they have no vocabulary for.
|
|
105
|
+
Declined: free initial posture — observed cold-starts stall in probe; re-evaluate if
|
|
106
|
+
session-replay evals show experienced users fighting the default.
|
|
107
|
+
- How to apply: the facilitator's start calibration offers only the two entry moves.
|
|
108
|
+
- Resolves: F2
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
- IDs `D1, D2, …` unique, append-only [BS-LEDGER-01]. `Decision`, `Why`, `How to apply` are
|
|
112
|
+
mandatory; `Resolves:` when the commitment closes forks. Amendments and reversals are
|
|
113
|
+
annotations plus a new entry ("Reversed by D9" on the old; D9 names what it reverses) — never a
|
|
114
|
+
rewrite. Declined options live inside `Why` per [doctrine.md](doctrine.md).
|
|
115
|
+
|
|
116
|
+
## ops/capture.md
|
|
117
|
+
|
|
118
|
+
The facilitator's per-turn append — its one write duty. Lowest possible bar: raw, unpolished,
|
|
119
|
+
everything session-relevant from *both* sides (user substance and facilitator substance —
|
|
120
|
+
diagnoses, informed rejections, definitions, reasoning chains), including residue judged not
|
|
121
|
+
worth pillar filing. Format:
|
|
122
|
+
|
|
123
|
+
```markdown
|
|
124
|
+
---
|
|
125
|
+
### T14 · 2026-07-08T14:22Z
|
|
126
|
+
|
|
127
|
+
<raw notes for this turn>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Turn IDs `T#` ascending with an ISO timestamp — the timestamp is what compose-freshness checks
|
|
131
|
+
against [BS-COMPOSE-02]. Never distill here; distillation is the twin's job.
|
|
132
|
+
|
|
133
|
+
## ops/sync-log.md
|
|
134
|
+
|
|
135
|
+
Paired-written, one pair per twin dispatch:
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
S4 | gate: on-demand | dispatched: 2026-07-08T14:25Z | scope: full reconcile + compose
|
|
139
|
+
S4 → reconciled | 2026-07-08T14:29Z | 4 edits · 2 new forks · 6 open · untouched: risks
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The **facilitator** writes the dispatch line as it dispatches; the **twin** appends the result
|
|
143
|
+
line (`reconciled` or `failed`) on return — no single author holds both sides. Every dispatch
|
|
144
|
+
line must acquire a result line; only the newest entry may be unpaired (in flight) [BS-SYNC-01].
|
|
145
|
+
A `failed` result is surfaced to the user at the next turn break and re-run at the next gate.
|
|
146
|
+
|
|
147
|
+
## ops/manifest.md
|
|
148
|
+
|
|
149
|
+
Created by the stop pipeline; gates the harvest apply:
|
|
150
|
+
|
|
151
|
+
```markdown
|
|
152
|
+
# Harvest manifest — {topic}
|
|
153
|
+
|
|
154
|
+
Round: 1
|
|
155
|
+
Status: proposed | approved | applied
|
|
156
|
+
|
|
157
|
+
| # | What | Source | Destination | Action |
|
|
158
|
+
|---|------|--------|-------------|--------|
|
|
159
|
+
| 1 | consolidated source of truth | thesis + fragments + ledger | docs/features/{x}.md | create |
|
|
160
|
+
| 2 | parked fork F7 | forks.md | docs/architecture/open-questions.md | append |
|
|
161
|
+
|
|
162
|
+
## Uselessness test
|
|
163
|
+
|
|
164
|
+
- Result: pass | fail
|
|
165
|
+
- Cold-reader allowed paths: <the destination docs above>
|
|
166
|
+
- Gaps: none | <named gaps → next Round>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Every parked fork and every fragment must have a row [BS-MANIFEST-01]. `Status: approved` is set
|
|
170
|
+
only after the user approves; gap fixes re-enter as a new `Round` with the same approval
|
|
171
|
+
requirement. After apply, no destination doc may link into the session folder [BS-HARVEST-01];
|
|
172
|
+
the move to history requires a recorded passing uselessness test [BS-USELESS-01].
|
|
173
|
+
|
|
174
|
+
## Detector
|
|
175
|
+
|
|
176
|
+
`node scripts/detector.mjs <session-folder> [--gate=session|manifest|move] [--json]`
|
|
177
|
+
|
|
178
|
+
- `session` (default) — the always-on integrity rules; run at any gate.
|
|
179
|
+
- `manifest` — adds the convergence gates (zero open forks, full aspect coverage, fresh compose);
|
|
180
|
+
the twin may not construct a manifest while any of these fail.
|
|
181
|
+
- `move` — adds the post-apply gates (manifest applied, uselessness pass recorded, no links into
|
|
182
|
+
scaffolding); the folder may not move while any fail.
|
|
183
|
+
|
|
184
|
+
Exit code 0 = clean, 1 = violations (listed with rule IDs), 2 = unusable input. Rules degrade
|
|
185
|
+
gracefully: no git context ⇒ BS-OPS-02 reports `skipped`, never blocks. Rule IDs are stable —
|
|
186
|
+
consumers (the twin, the evals, the maintenance census) key on them.
|
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// skills/brainstorm/scripts/detector.mjs - mechanical integrity checks for a brainstorm session folder.
|
|
3
|
+
// Contract: references/session-schema.md. Rule IDs are stable; consumers key on them.
|
|
4
|
+
// Usage: node detector.mjs <session-folder> [--gate=session|manifest|move] [--json]
|
|
5
|
+
|
|
6
|
+
import { readFileSync, existsSync, readdirSync, statSync } from 'node:fs';
|
|
7
|
+
import { join, basename, resolve } from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import { execFileSync } from 'node:child_process';
|
|
10
|
+
|
|
11
|
+
const GATES = ['session', 'manifest', 'move'];
|
|
12
|
+
|
|
13
|
+
// ---------- shared parsing ----------
|
|
14
|
+
|
|
15
|
+
function readIf(path) {
|
|
16
|
+
return existsSync(path) ? readFileSync(path, 'utf8') : null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function parseState(text) {
|
|
20
|
+
if (text == null) return null;
|
|
21
|
+
const field = (name) => {
|
|
22
|
+
const m = text.match(new RegExp(`^- ${name}:\\s*(.+)$`, 'm'));
|
|
23
|
+
return m ? m[1].trim() : null;
|
|
24
|
+
};
|
|
25
|
+
const aspects = [];
|
|
26
|
+
const mapSection = text.split(/^## Aspect map\s*$/m)[1];
|
|
27
|
+
if (mapSection != null) {
|
|
28
|
+
for (const line of mapSection.split('\n')) {
|
|
29
|
+
const m = line.match(/^- (.+?) — (.+?) → (.+)$/);
|
|
30
|
+
if (m) {
|
|
31
|
+
aspects.push({
|
|
32
|
+
name: m[1].trim(),
|
|
33
|
+
refs: m[3].split(',').map((r) => r.trim()).filter(Boolean),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
status: field('Status'),
|
|
40
|
+
posture: field('Posture'),
|
|
41
|
+
started: field('Started'),
|
|
42
|
+
sitting: field('Sitting'),
|
|
43
|
+
lastCompose: field('Last compose'),
|
|
44
|
+
hasAspectSection: mapSection != null,
|
|
45
|
+
aspects,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Fork entries: "## F3 — title [open]" / "[parked → destination]"
|
|
50
|
+
function parseForks(text) {
|
|
51
|
+
if (text == null) return [];
|
|
52
|
+
const forks = [];
|
|
53
|
+
const re = /^## (F\d+) — (.*?)\s*\[(open|parked → .+?)\]\s*$/gm;
|
|
54
|
+
let m;
|
|
55
|
+
while ((m = re.exec(text)) !== null) {
|
|
56
|
+
const start = m.index + m[0].length;
|
|
57
|
+
const next = text.indexOf('\n## ', start);
|
|
58
|
+
const body = text.slice(start, next === -1 ? undefined : next);
|
|
59
|
+
forks.push({
|
|
60
|
+
id: m[1],
|
|
61
|
+
title: m[2],
|
|
62
|
+
state: m[3] === 'open' ? 'open' : 'parked',
|
|
63
|
+
destination: m[3].startsWith('parked') ? m[3].replace('parked →', '').trim() : null,
|
|
64
|
+
closesWhen: /^- Closes when:[ \t]*\S/m.test(body),
|
|
65
|
+
raisedBy: (body.match(/^- Raised by:\s*(.+)$/m) || [])[1] || null,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return forks;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Ledger entries: "## D4 — title"
|
|
72
|
+
function parseLedger(text) {
|
|
73
|
+
if (text == null) return [];
|
|
74
|
+
const entries = [];
|
|
75
|
+
const re = /^## (D\d+) — (.+)$/gm;
|
|
76
|
+
let m;
|
|
77
|
+
while ((m = re.exec(text)) !== null) {
|
|
78
|
+
const start = m.index + m[0].length;
|
|
79
|
+
const next = text.indexOf('\n## ', start);
|
|
80
|
+
const body = text.slice(start, next === -1 ? undefined : next);
|
|
81
|
+
entries.push({
|
|
82
|
+
id: m[1],
|
|
83
|
+
title: m[2],
|
|
84
|
+
hasDecision: /^- Decision:[ \t]*\S/m.test(body),
|
|
85
|
+
hasWhy: /^- Why:[ \t]*\S/m.test(body),
|
|
86
|
+
hasHow: /^- How to apply:[ \t]*\S/m.test(body),
|
|
87
|
+
resolves: [...body.matchAll(/^- Resolves:\s*(.+)$/gm)]
|
|
88
|
+
.flatMap((r) => r[1].match(/F\d+/g) || []),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return entries;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Sync log: dispatch "S4 | gate: x | dispatched: ts | scope: y"
|
|
95
|
+
// result "S4 → reconciled|failed | ts | report"
|
|
96
|
+
function parseSyncLog(text) {
|
|
97
|
+
if (text == null) return { dispatches: [], results: [] };
|
|
98
|
+
const dispatches = [];
|
|
99
|
+
const results = [];
|
|
100
|
+
for (const line of text.split('\n')) {
|
|
101
|
+
let m = line.match(/^(S\d+) \| gate: (\S+) \| dispatched: (\S+)/);
|
|
102
|
+
if (m) { dispatches.push({ id: m[1], gate: m[2], at: m[3], line }); continue; }
|
|
103
|
+
m = line.match(/^(S\d+) → (reconciled|failed)\b/);
|
|
104
|
+
if (m) results.push({ id: m[1], outcome: m[2] });
|
|
105
|
+
}
|
|
106
|
+
return { dispatches, results };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Capture: "### T14 · 2026-07-08T14:22Z"
|
|
110
|
+
function parseCapture(text) {
|
|
111
|
+
if (text == null) return [];
|
|
112
|
+
return [...text.matchAll(/^### (T\d+) · (\S+)\s*$/gm)].map((m) => ({ id: m[1], at: m[2] }));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function parseManifest(text) {
|
|
116
|
+
if (text == null) return null;
|
|
117
|
+
const rows = [...text.matchAll(/^\|\s*\d+\s*\|(.+?)\|(.+?)\|(.+?)\|(.+?)\|\s*$/gm)].map((m) => ({
|
|
118
|
+
what: m[1].trim(), source: m[2].trim(), destination: m[3].trim(), action: m[4].trim(),
|
|
119
|
+
}));
|
|
120
|
+
const status = (text.match(/^Status:\s*(\S+)/m) || [])[1] || null;
|
|
121
|
+
const uSection = text.split(/^## Uselessness test\s*$/m)[1] || null;
|
|
122
|
+
return {
|
|
123
|
+
status,
|
|
124
|
+
rows,
|
|
125
|
+
uselessness: uSection == null ? null : {
|
|
126
|
+
result: (uSection.match(/^- Result:\s*(\S+)/m) || [])[1] || null,
|
|
127
|
+
gaps: (uSection.match(/^- Gaps:\s*(.+)$/m) || [])[1] || null,
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ---------- rule registry ----------
|
|
133
|
+
// Each rule: { id, gate, check(ctx) -> [] | [messages] | 'skipped' }
|
|
134
|
+
|
|
135
|
+
const RULES = [
|
|
136
|
+
{
|
|
137
|
+
id: 'BS-STATE-01',
|
|
138
|
+
gate: 'session',
|
|
139
|
+
title: 'state.md present and valid',
|
|
140
|
+
check: ({ state }) => {
|
|
141
|
+
if (state == null) return ['state.md missing'];
|
|
142
|
+
const out = [];
|
|
143
|
+
if (!['open', 'stopping', 'harvested'].includes(state.status)) out.push(`Status invalid: ${state.status}`);
|
|
144
|
+
if (!state.started) out.push('Started missing');
|
|
145
|
+
if (!['single', 'multi'].includes(state.sitting)) out.push(`Sitting invalid: ${state.sitting}`);
|
|
146
|
+
if (!state.lastCompose) out.push('Last compose missing');
|
|
147
|
+
if (!state.posture) out.push('Posture missing');
|
|
148
|
+
return out;
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
id: 'BS-STATE-02',
|
|
153
|
+
gate: 'session',
|
|
154
|
+
title: 'aspect map present with at least one aspect',
|
|
155
|
+
check: ({ state }) => {
|
|
156
|
+
if (state == null) return ['state.md missing'];
|
|
157
|
+
if (!state.hasAspectSection) return ['no "## Aspect map" section'];
|
|
158
|
+
if (state.aspects.length === 0) return ['aspect map has no parseable aspects'];
|
|
159
|
+
return [];
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
id: 'BS-ASPECT-01',
|
|
164
|
+
gate: 'session',
|
|
165
|
+
title: 'aspect refs resolve',
|
|
166
|
+
check: ({ state, forks, ledger, folder }) => {
|
|
167
|
+
if (state == null) return [];
|
|
168
|
+
const forkIds = new Set(forks.map((f) => f.id));
|
|
169
|
+
const ledgerIds = new Set(ledger.map((d) => d.id));
|
|
170
|
+
const resolvedForkIds = new Set(ledger.flatMap((d) => d.resolves));
|
|
171
|
+
const out = [];
|
|
172
|
+
for (const a of state.aspects) {
|
|
173
|
+
for (const ref of a.refs) {
|
|
174
|
+
if (ref === 'none yet' || ref === 'thesis') continue;
|
|
175
|
+
if (/^F\d+$/.test(ref)) {
|
|
176
|
+
// a fork ref may point at an open fork or one already resolved into the ledger
|
|
177
|
+
if (!forkIds.has(ref) && !resolvedForkIds.has(ref)) out.push(`aspect "${a.name}" → ${ref}: no such fork (open or resolved)`);
|
|
178
|
+
} else if (/^D\d+$/.test(ref)) {
|
|
179
|
+
if (!ledgerIds.has(ref)) out.push(`aspect "${a.name}" → ${ref}: no such ledger entry`);
|
|
180
|
+
} else if (ref.startsWith('fragment:')) {
|
|
181
|
+
const name = ref.slice('fragment:'.length);
|
|
182
|
+
if (!existsSync(join(folder, 'fragments', `${name}.md`))) out.push(`aspect "${a.name}" → ${ref}: fragments/${name}.md missing`);
|
|
183
|
+
} else {
|
|
184
|
+
out.push(`aspect "${a.name}" → unrecognized ref "${ref}"`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return out;
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
id: 'BS-ASPECT-02',
|
|
193
|
+
gate: 'manifest',
|
|
194
|
+
title: 'no uncovered aspects at the manifest gate',
|
|
195
|
+
check: ({ state }) => {
|
|
196
|
+
if (state == null) return [];
|
|
197
|
+
return state.aspects
|
|
198
|
+
.filter((a) => a.refs.length === 0 || a.refs.includes('none yet'))
|
|
199
|
+
.map((a) => `aspect "${a.name}" has no content`);
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
id: 'BS-THESIS-01',
|
|
204
|
+
gate: 'session',
|
|
205
|
+
title: 'thesis has the mandated shape and stamp',
|
|
206
|
+
check: ({ thesis }) => {
|
|
207
|
+
if (thesis == null) return ['thesis.md missing'];
|
|
208
|
+
const out = [];
|
|
209
|
+
if (!/^Current as of:\s*\S/m.test(thesis)) out.push('Current as of: stamp missing');
|
|
210
|
+
for (const s of ['## Claim', '## Argument', '## What changed']) {
|
|
211
|
+
if (!thesis.includes(s)) out.push(`section "${s}" missing`);
|
|
212
|
+
}
|
|
213
|
+
return out;
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
id: 'BS-COMPOSE-01',
|
|
218
|
+
gate: 'session',
|
|
219
|
+
title: 'thesis stamp matches state.md Last compose',
|
|
220
|
+
check: ({ state, thesis }) => {
|
|
221
|
+
if (state == null || thesis == null || state.lastCompose === 'never') return [];
|
|
222
|
+
const stamp = (thesis.match(/^Current as of:\s*(\S+)/m) || [])[1];
|
|
223
|
+
return stamp === state.lastCompose ? []
|
|
224
|
+
: [`thesis stamp ${stamp} ≠ state Last compose ${state.lastCompose}`];
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
id: 'BS-COMPOSE-02',
|
|
229
|
+
gate: 'manifest',
|
|
230
|
+
title: 'compose fresher than the newest capture entry',
|
|
231
|
+
check: ({ state, capture }) => {
|
|
232
|
+
if (state == null || capture.length === 0) return [];
|
|
233
|
+
if (state.lastCompose === 'never') return ['no compose has ever run'];
|
|
234
|
+
const newest = capture[capture.length - 1].at;
|
|
235
|
+
return state.lastCompose >= newest ? []
|
|
236
|
+
: [`last compose ${state.lastCompose} predates newest capture ${newest}`];
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
id: 'BS-FORK-01',
|
|
241
|
+
gate: 'session',
|
|
242
|
+
title: 'forks well-formed (unique IDs, close conditions, valid state)',
|
|
243
|
+
check: ({ forks }) => {
|
|
244
|
+
const out = [];
|
|
245
|
+
const seen = new Set();
|
|
246
|
+
for (const f of forks) {
|
|
247
|
+
if (seen.has(f.id)) out.push(`duplicate fork id ${f.id}`);
|
|
248
|
+
seen.add(f.id);
|
|
249
|
+
if (!f.closesWhen) out.push(`${f.id} has no "Closes when:"`);
|
|
250
|
+
if (f.state === 'parked' && !f.destination) out.push(`${f.id} parked without destination`);
|
|
251
|
+
}
|
|
252
|
+
return out;
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
id: 'BS-FORK-02',
|
|
257
|
+
gate: 'session',
|
|
258
|
+
title: 'no fork both resolved in the ledger and still open',
|
|
259
|
+
check: ({ forks, ledger }) => {
|
|
260
|
+
const open = new Set(forks.filter((f) => f.state === 'open').map((f) => f.id));
|
|
261
|
+
const out = [];
|
|
262
|
+
for (const d of ledger) {
|
|
263
|
+
for (const f of d.resolves) {
|
|
264
|
+
if (open.has(f)) out.push(`${d.id} resolves ${f} but ${f} is still open in forks.md`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return out;
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
id: 'BS-FORK-03',
|
|
272
|
+
gate: 'manifest',
|
|
273
|
+
title: 'zero open forks at the manifest gate',
|
|
274
|
+
check: ({ forks }) => forks.filter((f) => f.state === 'open').map((f) => `${f.id} is open`),
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
id: 'BS-LEDGER-01',
|
|
278
|
+
gate: 'session',
|
|
279
|
+
title: 'ledger entries carry the mandatory fields, IDs unique',
|
|
280
|
+
check: ({ ledger }) => {
|
|
281
|
+
const out = [];
|
|
282
|
+
const seen = new Set();
|
|
283
|
+
for (const d of ledger) {
|
|
284
|
+
if (seen.has(d.id)) out.push(`duplicate ledger id ${d.id}`);
|
|
285
|
+
seen.add(d.id);
|
|
286
|
+
if (!d.hasDecision) out.push(`${d.id} missing Decision`);
|
|
287
|
+
if (!d.hasWhy) out.push(`${d.id} missing Why`);
|
|
288
|
+
if (!d.hasHow) out.push(`${d.id} missing How to apply`);
|
|
289
|
+
}
|
|
290
|
+
return out;
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
id: 'BS-OPS-01',
|
|
295
|
+
gate: 'session',
|
|
296
|
+
title: 'ops/ hygiene: .gitignore present and covering',
|
|
297
|
+
check: ({ folder }) => {
|
|
298
|
+
const gi = readIf(join(folder, 'ops', '.gitignore'));
|
|
299
|
+
if (gi == null) return ['ops/.gitignore missing'];
|
|
300
|
+
return gi.split('\n').some((l) => l.trim() === '*') ? [] : ['ops/.gitignore does not contain "*"'];
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
id: 'BS-OPS-02',
|
|
305
|
+
gate: 'session',
|
|
306
|
+
title: 'ops/ never committed',
|
|
307
|
+
check: ({ folder }) => {
|
|
308
|
+
try {
|
|
309
|
+
const tracked = execFileSync('git', ['ls-files', '--', 'ops'], {
|
|
310
|
+
cwd: folder, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'],
|
|
311
|
+
}).trim();
|
|
312
|
+
return tracked === '' ? [] : [`ops/ files tracked by git: ${tracked.split('\n').join(', ')}`];
|
|
313
|
+
} catch {
|
|
314
|
+
return 'skipped'; // no git context — degrade, never block
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
id: 'BS-SYNC-01',
|
|
320
|
+
gate: 'session',
|
|
321
|
+
title: 'sync-log pairing: every dispatch has a result (newest may be in flight)',
|
|
322
|
+
check: ({ sync }) => {
|
|
323
|
+
const resulted = new Set(sync.results.map((r) => r.id));
|
|
324
|
+
const unpaired = sync.dispatches.filter((d) => !resulted.has(d.id));
|
|
325
|
+
if (unpaired.length === 0) return [];
|
|
326
|
+
const last = sync.dispatches[sync.dispatches.length - 1];
|
|
327
|
+
if (unpaired.length === 1 && unpaired[0].id === last.id) return []; // in flight
|
|
328
|
+
return unpaired.map((d) => `${d.id} dispatched but never resulted`);
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
id: 'BS-SYNC-02',
|
|
333
|
+
gate: 'session',
|
|
334
|
+
title: 'twin attributions cite a reconciled sync entry',
|
|
335
|
+
check: ({ forks, sync }) => {
|
|
336
|
+
const reconciled = new Set(sync.results.filter((r) => r.outcome === 'reconciled').map((r) => r.id));
|
|
337
|
+
const out = [];
|
|
338
|
+
for (const f of forks) {
|
|
339
|
+
if (f.raisedBy == null) continue;
|
|
340
|
+
const m = f.raisedBy.match(/^twin\s*\((S\d+)\)/);
|
|
341
|
+
if (f.raisedBy.startsWith('twin') && !m) { out.push(`${f.id} raised by twin without a sync id`); continue; }
|
|
342
|
+
if (m && !reconciled.has(m[1])) out.push(`${f.id} cites ${m[1]} which never reconciled`);
|
|
343
|
+
}
|
|
344
|
+
return out;
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
id: 'BS-MANIFEST-01',
|
|
349
|
+
gate: 'manifest',
|
|
350
|
+
title: 'manifest routes every parked fork and every fragment',
|
|
351
|
+
check: ({ forks, manifest, folder }) => {
|
|
352
|
+
if (manifest == null) return ['ops/manifest.md missing'];
|
|
353
|
+
const out = [];
|
|
354
|
+
const text = manifest.rows.map((r) => `${r.what} ${r.source}`).join('\n');
|
|
355
|
+
for (const f of forks.filter((x) => x.state === 'parked')) {
|
|
356
|
+
if (!text.includes(f.id)) out.push(`parked ${f.id} has no manifest row`);
|
|
357
|
+
}
|
|
358
|
+
const fragDir = join(folder, 'fragments');
|
|
359
|
+
if (existsSync(fragDir)) {
|
|
360
|
+
for (const frag of readdirSync(fragDir).filter((n) => n.endsWith('.md'))) {
|
|
361
|
+
if (!text.includes(frag) && !text.includes(basename(frag, '.md'))) {
|
|
362
|
+
out.push(`fragments/${frag} has no manifest row`);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return out;
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
id: 'BS-HARVEST-01',
|
|
371
|
+
gate: 'move',
|
|
372
|
+
title: 'no harvested destination links into the session folder',
|
|
373
|
+
check: ({ manifest, folder }) => {
|
|
374
|
+
if (manifest == null) return ['ops/manifest.md missing'];
|
|
375
|
+
const slug = basename(resolve(folder));
|
|
376
|
+
const out = [];
|
|
377
|
+
for (const row of manifest.rows) {
|
|
378
|
+
const dest = row.destination;
|
|
379
|
+
if (!dest || !dest.endsWith('.md')) continue;
|
|
380
|
+
const destPath = resolve(folder, '..', '..', '..', dest); // repo root = 3 up from docs/research/{slug}
|
|
381
|
+
const text = readIf(destPath) ?? readIf(resolve(dest));
|
|
382
|
+
if (text == null) { out.push(`destination ${dest} not found on disk`); continue; }
|
|
383
|
+
if (text.includes(slug)) out.push(`${dest} links into the session folder (${slug})`);
|
|
384
|
+
}
|
|
385
|
+
return out;
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
id: 'BS-USELESS-01',
|
|
390
|
+
gate: 'move',
|
|
391
|
+
title: 'recorded passing uselessness test with no gaps',
|
|
392
|
+
check: ({ manifest }) => {
|
|
393
|
+
if (manifest?.uselessness == null) return ['manifest has no "## Uselessness test" section'];
|
|
394
|
+
const out = [];
|
|
395
|
+
if (manifest.uselessness.result !== 'pass') out.push(`result is "${manifest.uselessness.result}"`);
|
|
396
|
+
if (manifest.uselessness.gaps !== 'none') out.push(`gaps recorded: ${manifest.uselessness.gaps}`);
|
|
397
|
+
if (manifest.status !== 'applied') out.push(`manifest status is "${manifest.status}", not applied`);
|
|
398
|
+
return out;
|
|
399
|
+
},
|
|
400
|
+
},
|
|
401
|
+
];
|
|
402
|
+
|
|
403
|
+
// ---------- runner ----------
|
|
404
|
+
|
|
405
|
+
export function runDetector(folder, gate = 'session') {
|
|
406
|
+
const ctx = {
|
|
407
|
+
folder,
|
|
408
|
+
state: parseState(readIf(join(folder, 'state.md'))),
|
|
409
|
+
thesis: readIf(join(folder, 'thesis.md')),
|
|
410
|
+
forks: parseForks(readIf(join(folder, 'forks.md'))),
|
|
411
|
+
ledger: parseLedger(readIf(join(folder, 'ledger.md'))),
|
|
412
|
+
capture: parseCapture(readIf(join(folder, 'ops', 'capture.md'))),
|
|
413
|
+
sync: parseSyncLog(readIf(join(folder, 'ops', 'sync-log.md'))),
|
|
414
|
+
manifest: parseManifest(readIf(join(folder, 'ops', 'manifest.md'))),
|
|
415
|
+
};
|
|
416
|
+
const activeGates = GATES.slice(0, GATES.indexOf(gate) + 1); // gates are cumulative
|
|
417
|
+
const results = [];
|
|
418
|
+
for (const rule of RULES) {
|
|
419
|
+
if (!activeGates.includes(rule.gate)) continue;
|
|
420
|
+
const res = rule.check(ctx);
|
|
421
|
+
if (res === 'skipped') results.push({ id: rule.id, title: rule.title, status: 'skipped', messages: [] });
|
|
422
|
+
else results.push({ id: rule.id, title: rule.title, status: res.length === 0 ? 'pass' : 'fail', messages: res });
|
|
423
|
+
}
|
|
424
|
+
return results;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function main() {
|
|
428
|
+
const args = process.argv.slice(2);
|
|
429
|
+
const folder = args.find((a) => !a.startsWith('--'));
|
|
430
|
+
const gate = (args.find((a) => a.startsWith('--gate=')) || '--gate=session').split('=')[1];
|
|
431
|
+
const asJson = args.includes('--json');
|
|
432
|
+
|
|
433
|
+
if (!folder || !existsSync(folder) || !statSync(folder).isDirectory()) {
|
|
434
|
+
console.error('usage: node detector.mjs <session-folder> [--gate=session|manifest|move] [--json]');
|
|
435
|
+
process.exit(2);
|
|
436
|
+
}
|
|
437
|
+
if (!GATES.includes(gate)) {
|
|
438
|
+
console.error(`unknown gate "${gate}" — one of: ${GATES.join(', ')}`);
|
|
439
|
+
process.exit(2);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const results = runDetector(resolve(folder), gate);
|
|
443
|
+
const failed = results.filter((r) => r.status === 'fail');
|
|
444
|
+
|
|
445
|
+
if (asJson) {
|
|
446
|
+
console.log(JSON.stringify({ folder: resolve(folder), gate, results }, null, 2));
|
|
447
|
+
} else {
|
|
448
|
+
for (const r of results) {
|
|
449
|
+
const mark = r.status === 'pass' ? '✓' : r.status === 'skipped' ? '~' : '✗';
|
|
450
|
+
console.log(`${mark} ${r.id} — ${r.title}`);
|
|
451
|
+
for (const m of r.messages) console.log(` ${m}`);
|
|
452
|
+
}
|
|
453
|
+
console.log(`\n${failed.length === 0 ? 'clean' : `${failed.length} rule(s) failing`} at gate "${gate}"`);
|
|
454
|
+
}
|
|
455
|
+
process.exit(failed.length === 0 ? 0 : 1);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
459
|
+
main();
|
|
460
|
+
}
|