quiver-cli 1.3.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +197 -239
- package/dist/cli.js +3163 -2040
- package/package.json +10 -11
- package/template/.agents/AGENTS.md +0 -26
- package/template/.agents/commands/cp.md +0 -108
- package/template/.agents/commands/next-setup.md +0 -1064
- package/template/.agents/commands/review.md +0 -68
- package/template/.agents/commands/terraform-readme.md +0 -38
- package/template/.agents/config.json +0 -80
- package/template/.agents/plugins/opencode/rtk.ts +0 -34
- package/template/.agents/skills/agent-browser/SKILL.md +0 -51
- package/template/.agents/skills/apps/skybridge/SKILL.md +0 -50
- package/template/.agents/skills/code/cleanup/SKILL.md +0 -26
- package/template/.agents/skills/code/improve/SKILL.md +0 -122
- package/template/.agents/skills/code/improve/references/audit-playbook.md +0 -130
- package/template/.agents/skills/code/improve/references/closing-the-loop.md +0 -96
- package/template/.agents/skills/code/improve/references/plan-template.md +0 -197
- package/template/.agents/skills/code/vercel-react-best-practices/AGENTS.md +0 -3810
- package/template/.agents/skills/code/vercel-react-best-practices/README.md +0 -123
- package/template/.agents/skills/code/vercel-react-best-practices/SKILL.md +0 -149
- package/template/.agents/skills/code/vercel-react-best-practices/metadata.json +0 -15
- package/template/.agents/skills/code/vercel-react-best-practices/rules/_sections.md +0 -46
- package/template/.agents/skills/code/vercel-react-best-practices/rules/_template.md +0 -28
- package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-effect-event-deps.md +0 -56
- package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -55
- package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-init-once.md +0 -42
- package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-use-latest.md +0 -39
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-api-routes.md +0 -38
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-cheap-condition-before-await.md +0 -37
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-defer-await.md +0 -82
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-dependencies.md +0 -51
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-parallel.md +0 -28
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -99
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-analyzable-paths.md +0 -63
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -60
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-conditional.md +0 -31
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -49
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -35
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-preload.md +0 -50
- package/template/.agents/skills/code/vercel-react-best-practices/rules/client-event-listeners.md +0 -74
- package/template/.agents/skills/code/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -71
- package/template/.agents/skills/code/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -48
- package/template/.agents/skills/code/vercel-react-best-practices/rules/client-swr-dedup.md +0 -56
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -107
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-cache-function-results.md +0 -80
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-cache-property-access.md +0 -28
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-cache-storage.md +0 -70
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-combine-iterations.md +0 -32
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-early-exit.md +0 -50
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-flatmap-filter.md +0 -60
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -45
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-index-maps.md +0 -37
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-length-check-first.md +0 -49
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-min-max-loop.md +0 -82
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-request-idle-callback.md +0 -105
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -24
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -57
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-activity.md +0 -26
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -40
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -38
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -46
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +0 -30
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-resource-hints.md +0 -85
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-script-defer-async.md +0 -68
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -28
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-usetransition-loading.md +0 -75
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -39
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-dependencies.md +0 -45
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +0 -40
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-derived-state.md +0 -29
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -74
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -58
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +0 -38
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-memo.md +0 -44
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +0 -45
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-no-inline-components.md +0 -82
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -35
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +0 -64
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-transitions.md +0 -40
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-use-deferred-value.md +0 -59
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +0 -73
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -73
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-auth-actions.md +0 -96
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-cache-lru.md +0 -41
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-cache-react.md +0 -76
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-dedup-props.md +0 -65
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-hoist-static-io.md +0 -149
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-no-shared-module-state.md +0 -50
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -83
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-parallel-nested-fetching.md +0 -34
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-serialization.md +0 -38
- package/template/.agents/skills/data/prisma-cli/SKILL.md +0 -247
- package/template/.agents/skills/data/prisma-cli/references/db-execute.md +0 -78
- package/template/.agents/skills/data/prisma-cli/references/db-pull.md +0 -185
- package/template/.agents/skills/data/prisma-cli/references/db-push.md +0 -148
- package/template/.agents/skills/data/prisma-cli/references/db-seed.md +0 -188
- package/template/.agents/skills/data/prisma-cli/references/debug.md +0 -46
- package/template/.agents/skills/data/prisma-cli/references/dev.md +0 -157
- package/template/.agents/skills/data/prisma-cli/references/format.md +0 -48
- package/template/.agents/skills/data/prisma-cli/references/generate.md +0 -173
- package/template/.agents/skills/data/prisma-cli/references/init.md +0 -136
- package/template/.agents/skills/data/prisma-cli/references/mcp.md +0 -38
- package/template/.agents/skills/data/prisma-cli/references/migrate-deploy.md +0 -127
- package/template/.agents/skills/data/prisma-cli/references/migrate-dev.md +0 -145
- package/template/.agents/skills/data/prisma-cli/references/migrate-diff.md +0 -89
- package/template/.agents/skills/data/prisma-cli/references/migrate-reset.md +0 -78
- package/template/.agents/skills/data/prisma-cli/references/migrate-resolve.md +0 -57
- package/template/.agents/skills/data/prisma-cli/references/migrate-status.md +0 -65
- package/template/.agents/skills/data/prisma-cli/references/studio.md +0 -137
- package/template/.agents/skills/data/prisma-cli/references/validate.md +0 -53
- package/template/.agents/skills/data/prisma-client-api/SKILL.md +0 -216
- package/template/.agents/skills/data/prisma-client-api/references/client-methods.md +0 -223
- package/template/.agents/skills/data/prisma-client-api/references/constructor.md +0 -208
- package/template/.agents/skills/data/prisma-client-api/references/filters.md +0 -256
- package/template/.agents/skills/data/prisma-client-api/references/model-queries.md +0 -281
- package/template/.agents/skills/data/prisma-client-api/references/query-options.md +0 -276
- package/template/.agents/skills/data/prisma-client-api/references/raw-queries.md +0 -194
- package/template/.agents/skills/data/prisma-client-api/references/relations.md +0 -308
- package/template/.agents/skills/data/prisma-client-api/references/transactions.md +0 -184
- package/template/.agents/skills/design/impeccable/SKILL.md +0 -84
- package/template/.agents/skills/design/impeccable/reference/adapt.md +0 -312
- package/template/.agents/skills/design/impeccable/reference/adapt.native.md +0 -58
- package/template/.agents/skills/design/impeccable/reference/android.md +0 -40
- package/template/.agents/skills/design/impeccable/reference/animate.md +0 -86
- package/template/.agents/skills/design/impeccable/reference/audit.md +0 -136
- package/template/.agents/skills/design/impeccable/reference/audit.native.md +0 -139
- package/template/.agents/skills/design/impeccable/reference/bolder.md +0 -31
- package/template/.agents/skills/design/impeccable/reference/clarify.md +0 -94
- package/template/.agents/skills/design/impeccable/reference/colorize.md +0 -86
- package/template/.agents/skills/design/impeccable/reference/craft-floor.md +0 -42
- package/template/.agents/skills/design/impeccable/reference/craft.md +0 -5
- package/template/.agents/skills/design/impeccable/reference/critique.md +0 -788
- package/template/.agents/skills/design/impeccable/reference/degraded/asset-producer.md +0 -90
- package/template/.agents/skills/design/impeccable/reference/degraded/documenter.md +0 -24
- package/template/.agents/skills/design/impeccable/reference/degraded/finish-reviewer.md +0 -37
- package/template/.agents/skills/design/impeccable/reference/degraded/manual-edit-applier.md +0 -92
- package/template/.agents/skills/design/impeccable/reference/delight.md +0 -70
- package/template/.agents/skills/design/impeccable/reference/distill.md +0 -111
- package/template/.agents/skills/design/impeccable/reference/doctor.md +0 -53
- package/template/.agents/skills/design/impeccable/reference/document.md +0 -416
- package/template/.agents/skills/design/impeccable/reference/extract.md +0 -69
- package/template/.agents/skills/design/impeccable/reference/harden.md +0 -336
- package/template/.agents/skills/design/impeccable/reference/hooks.md +0 -105
- package/template/.agents/skills/design/impeccable/reference/init.md +0 -125
- package/template/.agents/skills/design/impeccable/reference/ios.md +0 -45
- package/template/.agents/skills/design/impeccable/reference/layout.md +0 -84
- package/template/.agents/skills/design/impeccable/reference/live-setup.md +0 -102
- package/template/.agents/skills/design/impeccable/reference/live.md +0 -323
- package/template/.agents/skills/design/impeccable/reference/new-work.md +0 -105
- package/template/.agents/skills/design/impeccable/reference/onboard.md +0 -234
- package/template/.agents/skills/design/impeccable/reference/operate.md +0 -61
- package/template/.agents/skills/design/impeccable/reference/optimize.md +0 -258
- package/template/.agents/skills/design/impeccable/reference/overdrive.md +0 -127
- package/template/.agents/skills/design/impeccable/reference/polish.md +0 -97
- package/template/.agents/skills/design/impeccable/reference/quieter.md +0 -99
- package/template/.agents/skills/design/impeccable/reference/routing.md +0 -18
- package/template/.agents/skills/design/impeccable/reference/shape.md +0 -59
- package/template/.agents/skills/design/impeccable/reference/typeset.md +0 -80
- package/template/.agents/skills/design/impeccable/reference/visualize.md +0 -47
- package/template/.agents/skills/design/impeccable/scripts/command-metadata.json +0 -94
- package/template/.agents/skills/design/impeccable/scripts/concept-seed.mjs +0 -558
- package/template/.agents/skills/design/impeccable/scripts/context-signals.mjs +0 -334
- package/template/.agents/skills/design/impeccable/scripts/context.mjs +0 -1450
- package/template/.agents/skills/design/impeccable/scripts/critique-storage.mjs +0 -213
- package/template/.agents/skills/design/impeccable/scripts/detect-csp.mjs +0 -198
- package/template/.agents/skills/design/impeccable/scripts/detect.mjs +0 -21
- package/template/.agents/skills/design/impeccable/scripts/detector/browser/injected/index.mjs +0 -2023
- package/template/.agents/skills/design/impeccable/scripts/detector/cli/main.mjs +0 -438
- package/template/.agents/skills/design/impeccable/scripts/detector/design-system.mjs +0 -983
- package/template/.agents/skills/design/impeccable/scripts/detector/detect-antipatterns-browser.js +0 -8283
- package/template/.agents/skills/design/impeccable/scripts/detector/detect-antipatterns.mjs +0 -50
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/browser/detect-url.mjs +0 -372
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/regex/detect-text.mjs +0 -768
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +0 -1186
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/static-html/detect-html.mjs +0 -264
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/visual/screenshot-contrast.mjs +0 -189
- package/template/.agents/skills/design/impeccable/scripts/detector/findings.mjs +0 -18
- package/template/.agents/skills/design/impeccable/scripts/detector/node/file-system.mjs +0 -212
- package/template/.agents/skills/design/impeccable/scripts/detector/profile/profiler.mjs +0 -166
- package/template/.agents/skills/design/impeccable/scripts/detector/registry/antipatterns.mjs +0 -617
- package/template/.agents/skills/design/impeccable/scripts/detector/rules/checks.mjs +0 -5580
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/color.mjs +0 -124
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/constants.mjs +0 -112
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/fonts.mjs +0 -30
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/inline-ignores.mjs +0 -148
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/page.mjs +0 -7
- package/template/.agents/skills/design/impeccable/scripts/doctor.mjs +0 -336
- package/template/.agents/skills/design/impeccable/scripts/embed-prompt.mjs +0 -133
- package/template/.agents/skills/design/impeccable/scripts/generate-image.mjs +0 -240
- package/template/.agents/skills/design/impeccable/scripts/hook-admin.mjs +0 -741
- package/template/.agents/skills/design/impeccable/scripts/hook-before-edit.mjs +0 -516
- package/template/.agents/skills/design/impeccable/scripts/hook-lib.mjs +0 -2100
- package/template/.agents/skills/design/impeccable/scripts/hook.mjs +0 -78
- package/template/.agents/skills/design/impeccable/scripts/lib/artifact-schema.mjs +0 -93
- package/template/.agents/skills/design/impeccable/scripts/lib/composition-catalog.mjs +0 -200
- package/template/.agents/skills/design/impeccable/scripts/lib/concept-catalog.mjs +0 -357
- package/template/.agents/skills/design/impeccable/scripts/lib/design-parser.mjs +0 -842
- package/template/.agents/skills/design/impeccable/scripts/lib/impeccable-config.mjs +0 -658
- package/template/.agents/skills/design/impeccable/scripts/lib/impeccable-paths.mjs +0 -137
- package/template/.agents/skills/design/impeccable/scripts/lib/is-generated.mjs +0 -69
- package/template/.agents/skills/design/impeccable/scripts/lib/provider.mjs +0 -5
- package/template/.agents/skills/design/impeccable/scripts/lib/roll-selection.mjs +0 -362
- package/template/.agents/skills/design/impeccable/scripts/lib/staleness-deep.mjs +0 -457
- package/template/.agents/skills/design/impeccable/scripts/lib/staleness-notice.mjs +0 -169
- package/template/.agents/skills/design/impeccable/scripts/lib/staleness.mjs +0 -457
- package/template/.agents/skills/design/impeccable/scripts/lib/surface-briefs.mjs +0 -151
- package/template/.agents/skills/design/impeccable/scripts/lib/target-args.mjs +0 -42
- package/template/.agents/skills/design/impeccable/scripts/lib/target-slug.mjs +0 -33
- package/template/.agents/skills/design/impeccable/scripts/lib/template-extensions.mjs +0 -146
- package/template/.agents/skills/design/impeccable/scripts/live/accept-css.mjs +0 -617
- package/template/.agents/skills/design/impeccable/scripts/live/accept-verify.mjs +0 -60
- package/template/.agents/skills/design/impeccable/scripts/live/browser-script-parts.mjs +0 -55
- package/template/.agents/skills/design/impeccable/scripts/live/completion.mjs +0 -28
- package/template/.agents/skills/design/impeccable/scripts/live/event-validation.mjs +0 -199
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/astro.mjs +0 -47
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/detect-utils.mjs +0 -73
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/index.mjs +0 -143
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/journal.mjs +0 -197
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/nextjs.mjs +0 -49
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/nuxt.mjs +0 -161
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/script-src.mjs +0 -17
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/static-html.mjs +0 -26
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/sveltekit.mjs +0 -71
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/tag-strategy.mjs +0 -247
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/tanstack-start.mjs +0 -70
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/vite-generic.mjs +0 -42
- package/template/.agents/skills/design/impeccable/scripts/live/generation-preflight.mjs +0 -149
- package/template/.agents/skills/design/impeccable/scripts/live/insert-ui.mjs +0 -458
- package/template/.agents/skills/design/impeccable/scripts/live/instructions.mjs +0 -142
- package/template/.agents/skills/design/impeccable/scripts/live/manual-apply.mjs +0 -939
- package/template/.agents/skills/design/impeccable/scripts/live/manual-edit-routes.mjs +0 -357
- package/template/.agents/skills/design/impeccable/scripts/live/manual-edits-buffer.mjs +0 -152
- package/template/.agents/skills/design/impeccable/scripts/live/poll-lanes.mjs +0 -14
- package/template/.agents/skills/design/impeccable/scripts/live/roots.mjs +0 -508
- package/template/.agents/skills/design/impeccable/scripts/live/session-store.mjs +0 -563
- package/template/.agents/skills/design/impeccable/scripts/live/source-lock.mjs +0 -105
- package/template/.agents/skills/design/impeccable/scripts/live/source-search.mjs +0 -105
- package/template/.agents/skills/design/impeccable/scripts/live/svelte-ast.mjs +0 -961
- package/template/.agents/skills/design/impeccable/scripts/live/svelte-component.mjs +0 -1342
- package/template/.agents/skills/design/impeccable/scripts/live/sveltekit-adapter.mjs +0 -316
- package/template/.agents/skills/design/impeccable/scripts/live/tanstack-adapter.mjs +0 -280
- package/template/.agents/skills/design/impeccable/scripts/live/ui-core.mjs +0 -180
- package/template/.agents/skills/design/impeccable/scripts/live/vocabulary.mjs +0 -171
- package/template/.agents/skills/design/impeccable/scripts/live-accept.mjs +0 -954
- package/template/.agents/skills/design/impeccable/scripts/live-browser-dom.js +0 -146
- package/template/.agents/skills/design/impeccable/scripts/live-browser-session.js +0 -123
- package/template/.agents/skills/design/impeccable/scripts/live-browser.js +0 -12512
- package/template/.agents/skills/design/impeccable/scripts/live-commit-manual-edits.mjs +0 -1244
- package/template/.agents/skills/design/impeccable/scripts/live-complete.mjs +0 -107
- package/template/.agents/skills/design/impeccable/scripts/live-copy-edit-agent.mjs +0 -683
- package/template/.agents/skills/design/impeccable/scripts/live-discard-manual-edits.mjs +0 -51
- package/template/.agents/skills/design/impeccable/scripts/live-inject.mjs +0 -503
- package/template/.agents/skills/design/impeccable/scripts/live-insert.mjs +0 -292
- package/template/.agents/skills/design/impeccable/scripts/live-manual-edit-evidence.mjs +0 -368
- package/template/.agents/skills/design/impeccable/scripts/live-poll.mjs +0 -429
- package/template/.agents/skills/design/impeccable/scripts/live-resume.mjs +0 -123
- package/template/.agents/skills/design/impeccable/scripts/live-server.mjs +0 -1661
- package/template/.agents/skills/design/impeccable/scripts/live-status.mjs +0 -71
- package/template/.agents/skills/design/impeccable/scripts/live-target.mjs +0 -30
- package/template/.agents/skills/design/impeccable/scripts/live-wrap.mjs +0 -927
- package/template/.agents/skills/design/impeccable/scripts/live.mjs +0 -359
- package/template/.agents/skills/design/impeccable/scripts/modern-screenshot.umd.js +0 -14
- package/template/.agents/skills/design/impeccable/scripts/palette.mjs +0 -628
- package/template/.agents/skills/design/impeccable/scripts/pin.mjs +0 -221
- package/template/.agents/skills/design/impeccable/scripts/serve-question.mjs +0 -932
- package/template/.agents/skills/design/impeccable/scripts/surface-brief.mjs +0 -74
- package/template/.agents/skills/design/shadcn/SKILL.md +0 -277
- package/template/.agents/skills/design/shadcn/agents/openai.yml +0 -5
- package/template/.agents/skills/design/shadcn/assets/shadcn-small.png +0 -0
- package/template/.agents/skills/design/shadcn/assets/shadcn.png +0 -0
- package/template/.agents/skills/design/shadcn/cli.md +0 -290
- package/template/.agents/skills/design/shadcn/customization.md +0 -209
- package/template/.agents/skills/design/shadcn/evals/evals.json +0 -77
- package/template/.agents/skills/design/shadcn/mcp.md +0 -105
- package/template/.agents/skills/design/shadcn/registry.md +0 -277
- package/template/.agents/skills/design/shadcn/rules/base-vs-radix.md +0 -306
- package/template/.agents/skills/design/shadcn/rules/chat.md +0 -224
- package/template/.agents/skills/design/shadcn/rules/composition.md +0 -213
- package/template/.agents/skills/design/shadcn/rules/forms.md +0 -192
- package/template/.agents/skills/design/shadcn/rules/icons.md +0 -101
- package/template/.agents/skills/design/shadcn/rules/styling.md +0 -185
- package/template/.agents/skills/find-skills/SKILL.md +0 -141
- package/template/.agents/skills/hono/SKILL.md +0 -579
- package/template/.agents/skills/integrations/langfuse/SKILL.md +0 -146
- package/template/.agents/skills/integrations/langfuse/references/ci-cd.md +0 -41
- package/template/.agents/skills/integrations/langfuse/references/cli.md +0 -60
- package/template/.agents/skills/integrations/langfuse/references/error-analysis.md +0 -88
- package/template/.agents/skills/integrations/langfuse/references/instrumentation.md +0 -121
- package/template/.agents/skills/integrations/langfuse/references/judge-calibration.md +0 -291
- package/template/.agents/skills/integrations/langfuse/references/prompt-engineering.md +0 -35
- package/template/.agents/skills/integrations/langfuse/references/prompt-migration.md +0 -79
- package/template/.agents/skills/integrations/langfuse/references/skill-feedback.md +0 -55
- package/template/.agents/skills/integrations/langfuse/references/trace-evaluator-upgrade.md +0 -76
- package/template/.agents/skills/integrations/langfuse/references/user-feedback.md +0 -92
- package/template/.agents/skills/integrations/langfuse/references/v4-project-migration.md +0 -73
- package/template/.agents/skills/integrations/posthog/SKILL.md +0 -102
- package/template/.agents/skills/integrations/posthog/references/error-tracking-alerts.md +0 -63
- package/template/.agents/skills/integrations/posthog/references/error-tracking-assigning-issues.md +0 -77
- package/template/.agents/skills/integrations/posthog/references/error-tracking-fingerprints.md +0 -57
- package/template/.agents/skills/integrations/posthog/references/error-tracking-monitoring.md +0 -140
- package/template/.agents/skills/integrations/posthog/references/error-tracking-nextjs.md +0 -490
- package/template/.agents/skills/integrations/posthog/references/error-tracking-source-maps.md +0 -45
- package/template/.agents/skills/integrations/posthog/references/feature-flags-best-practices.md +0 -139
- package/template/.agents/skills/integrations/posthog/references/feature-flags-react.md +0 -302
- package/template/.agents/skills/integrations/posthog/references/identify-users.md +0 -202
- package/template/.agents/skills/integrations/posthog/references/integration-example.md +0 -706
- package/template/.agents/skills/integrations/posthog/references/integration-nextjs.md +0 -385
- package/template/.agents/skills/integrations/posthog/references/integration-step-1-begin.md +0 -43
- package/template/.agents/skills/integrations/posthog/references/integration-step-2-edit.md +0 -37
- package/template/.agents/skills/integrations/posthog/references/integration-step-3-revise.md +0 -22
- package/template/.agents/skills/integrations/posthog/references/integration-step-4-conclude.md +0 -38
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-anthropic.md +0 -200
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-basics.md +0 -62
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-costs.md +0 -197
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-manual-capture.md +0 -397
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-traces.md +0 -98
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-vercel-ai.md +0 -120
- package/template/.agents/skills/repo/repo-ci/SKILL.md +0 -265
- package/template/.agents/skills/repo/repo-init-next-js/SKILL.md +0 -129
- package/template/.agents/skills/repo/repo-init-next-js/references/file-contents.md +0 -800
- package/template/.agents/skills/repo/repo-init-next-js/scripts/setup.sh +0 -47
- package/template/.agents/skills/repo/repo-init-node/SKILL.md +0 -196
- package/template/.agents/skills/skill-creator/LICENSE.txt +0 -202
- package/template/.agents/skills/skill-creator/SKILL.md +0 -485
- package/template/.agents/skills/skill-creator/agents/analyzer.md +0 -274
- package/template/.agents/skills/skill-creator/agents/comparator.md +0 -202
- package/template/.agents/skills/skill-creator/agents/grader.md +0 -223
- package/template/.agents/skills/skill-creator/assets/eval_review.html +0 -146
- package/template/.agents/skills/skill-creator/eval-viewer/generate_review.py +0 -471
- package/template/.agents/skills/skill-creator/eval-viewer/viewer.html +0 -1325
- package/template/.agents/skills/skill-creator/references/schemas.md +0 -430
- package/template/.agents/skills/skill-creator/scripts/__init__.py +0 -0
- package/template/.agents/skills/skill-creator/scripts/aggregate_benchmark.py +0 -401
- package/template/.agents/skills/skill-creator/scripts/generate_report.py +0 -326
- package/template/.agents/skills/skill-creator/scripts/improve_description.py +0 -247
- package/template/.agents/skills/skill-creator/scripts/package_skill.py +0 -136
- package/template/.agents/skills/skill-creator/scripts/quick_validate.py +0 -103
- package/template/.agents/skills/skill-creator/scripts/run_eval.py +0 -310
- package/template/.agents/skills/skill-creator/scripts/run_loop.py +0 -328
- package/template/.agents/skills/skill-creator/scripts/utils.py +0 -47
- package/template/.agents/skills/supabase/CHANGELOG.md +0 -71
- package/template/.agents/skills/supabase/SKILL.md +0 -145
- package/template/.agents/skills/supabase/assets/feedback-issue-template.md +0 -17
- package/template/.agents/skills/supabase/references/skill-feedback.md +0 -17
- package/template/.agents/skills/supabase-postgres-best-practices/CHANGELOG.md +0 -73
- package/template/.agents/skills/supabase-postgres-best-practices/SKILL.md +0 -64
- package/template/.agents/skills/supabase-postgres-best-practices/references/_contributing.md +0 -170
- package/template/.agents/skills/supabase-postgres-best-practices/references/_sections.md +0 -39
- package/template/.agents/skills/supabase-postgres-best-practices/references/_template.md +0 -34
- package/template/.agents/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +0 -55
- package/template/.agents/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +0 -49
- package/template/.agents/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +0 -46
- package/template/.agents/skills/supabase-postgres-best-practices/references/conn-limits.md +0 -44
- package/template/.agents/skills/supabase-postgres-best-practices/references/conn-pooling.md +0 -41
- package/template/.agents/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +0 -46
- package/template/.agents/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +0 -54
- package/template/.agents/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +0 -53
- package/template/.agents/skills/supabase-postgres-best-practices/references/data-pagination.md +0 -50
- package/template/.agents/skills/supabase-postgres-best-practices/references/data-upsert.md +0 -50
- package/template/.agents/skills/supabase-postgres-best-practices/references/lock-advisory.md +0 -56
- package/template/.agents/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +0 -68
- package/template/.agents/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +0 -50
- package/template/.agents/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +0 -54
- package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +0 -45
- package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +0 -55
- package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +0 -55
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +0 -44
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +0 -40
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-index-types.md +0 -48
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +0 -43
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +0 -45
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-constraints.md +0 -80
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-data-types.md +0 -46
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +0 -59
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +0 -55
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-partitioning.md +0 -55
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +0 -61
- package/template/.agents/skills/supabase-postgres-best-practices/references/security-privileges.md +0 -54
- package/template/.agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md +0 -50
- package/template/.agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md +0 -63
- package/template/.agents/skills/writing/humanizer/SKILL.md +0 -621
- package/template/.agents/upstreams.json +0 -116
|
@@ -1,457 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tier 2 staleness checks: the ones that cost too much to run on every session
|
|
3
|
-
* boot. Shelling out to git, walking workspaces, resolving hook script paths,
|
|
4
|
-
* and validating ignore lists against the live rule registry all belong here.
|
|
5
|
-
*
|
|
6
|
-
* The boot tier answers "did an older Impeccable write this". This tier also
|
|
7
|
-
* asks "does it still describe the code", which no file comparison can settle
|
|
8
|
-
* on its own. Where the answer needs judgment, the finding reports a measured
|
|
9
|
-
* proxy and says it is a proxy. It never claims a document is wrong because a
|
|
10
|
-
* number is large.
|
|
11
|
-
*
|
|
12
|
-
* Same finding shape and severities as lib/staleness.mjs.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import fs from 'node:fs';
|
|
16
|
-
import path from 'node:path';
|
|
17
|
-
import { execFileSync } from 'node:child_process';
|
|
18
|
-
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
19
|
-
|
|
20
|
-
const VISUAL_SOURCE_DIRS = ['src', 'app', 'pages', 'components', 'site', 'styles', 'public'];
|
|
21
|
-
|
|
22
|
-
const HOOK_MANIFESTS_BY_PROVIDER = Object.freeze({
|
|
23
|
-
'claude-code': ['.claude/settings.local.json', '.claude/settings.json'],
|
|
24
|
-
codex: ['.codex/hooks.json'],
|
|
25
|
-
agents: ['.codex/hooks.json'],
|
|
26
|
-
cursor: ['.cursor/hooks.json'],
|
|
27
|
-
github: ['.github/hooks/impeccable.json'],
|
|
28
|
-
grok: ['.grok/hooks/impeccable.json'],
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
const HOOK_SCRIPT_MARKERS = [
|
|
32
|
-
'skills/impeccable/scripts/hook.mjs',
|
|
33
|
-
'skills/impeccable/scripts/hook-before-edit.mjs',
|
|
34
|
-
];
|
|
35
|
-
|
|
36
|
-
// Retired live-mode state locations. impeccable-paths still reads these as
|
|
37
|
-
// fallbacks; reporting them is what eventually lets the fallbacks go.
|
|
38
|
-
const LEGACY_LIVE_PATHS = ['.impeccable-live.json', '.impeccable-live'];
|
|
39
|
-
|
|
40
|
-
function finding({ id, artifact, filePath = null, severity, summary, fix }) {
|
|
41
|
-
return { id, artifact, path: filePath, severity, summary, fix };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function readJson(filePath) {
|
|
45
|
-
try {
|
|
46
|
-
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
47
|
-
} catch {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function toRelative(filePath, root) {
|
|
53
|
-
if (!filePath) return null;
|
|
54
|
-
const rel = path.relative(root, filePath);
|
|
55
|
-
return rel && !rel.startsWith('..') && !path.isAbsolute(rel)
|
|
56
|
-
? rel.split(path.sep).join('/')
|
|
57
|
-
: filePath;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function git(args, cwd) {
|
|
61
|
-
try {
|
|
62
|
-
return execFileSync('git', args, {
|
|
63
|
-
cwd,
|
|
64
|
-
encoding: 'utf-8',
|
|
65
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
66
|
-
timeout: 5000,
|
|
67
|
-
}).trim();
|
|
68
|
-
} catch {
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// ─── DESIGN.md truth drift ─────────────────────────────────────────────────
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* How much UI work has landed since DESIGN.md was last touched, measured in
|
|
77
|
-
* commits to the visual source directories. A proxy, and reported as one: a
|
|
78
|
-
* large number means the document is worth re-reading, not that it is wrong.
|
|
79
|
-
* Silent outside a git repo, on an untracked DESIGN.md, and when the count is
|
|
80
|
-
* small enough to be ordinary maintenance.
|
|
81
|
-
*/
|
|
82
|
-
export function checkDesignDrift({ designPath, projectRoot, threshold = 25 }) {
|
|
83
|
-
if (!designPath || !projectRoot) return [];
|
|
84
|
-
if (!git(['rev-parse', '--is-inside-work-tree'], projectRoot)) return [];
|
|
85
|
-
|
|
86
|
-
const relDesign = toRelative(designPath, projectRoot);
|
|
87
|
-
const lastDesignCommit = git(['log', '-1', '--format=%H', '--', relDesign], projectRoot);
|
|
88
|
-
if (!lastDesignCommit) return [];
|
|
89
|
-
|
|
90
|
-
const dirs = VISUAL_SOURCE_DIRS.filter((dir) => fs.existsSync(path.join(projectRoot, dir)));
|
|
91
|
-
if (!dirs.length) return [];
|
|
92
|
-
|
|
93
|
-
const log = git(
|
|
94
|
-
['log', '--oneline', `${lastDesignCommit}..HEAD`, '--', ...dirs],
|
|
95
|
-
projectRoot,
|
|
96
|
-
);
|
|
97
|
-
if (log === null) return [];
|
|
98
|
-
const commits = log ? log.split('\n').filter(Boolean).length : 0;
|
|
99
|
-
if (commits < threshold) return [];
|
|
100
|
-
|
|
101
|
-
const when = git(['log', '-1', '--format=%ad', '--date=short', '--', relDesign], projectRoot);
|
|
102
|
-
return [finding({
|
|
103
|
-
id: 'design-md-drift',
|
|
104
|
-
artifact: 'DESIGN.md',
|
|
105
|
-
filePath: relDesign,
|
|
106
|
-
severity: 'route',
|
|
107
|
-
summary: `${commits} commits have touched ${dirs.join(', ')} since ${relDesign} was last edited`
|
|
108
|
-
+ `${when ? ` (${when})` : ''}. This counts commits, not contradictions: it says the document is worth `
|
|
109
|
-
+ 're-reading, not that it is wrong.',
|
|
110
|
-
fix: 'Read DESIGN.md against the current tokens and components before trusting it as authority. '
|
|
111
|
-
+ 'If it has genuinely drifted, `document` regenerates it from the code.',
|
|
112
|
-
})];
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Canonical DESIGN.md sections that carry nothing. Distinct from truth drift:
|
|
117
|
-
* a section can be absent because it never applied, so this is reported as a
|
|
118
|
-
* documentation gap for a human to judge, never as an error.
|
|
119
|
-
*/
|
|
120
|
-
export function checkDesignCoverage({ design, designPath, parseDesignMd }) {
|
|
121
|
-
if (!design || typeof parseDesignMd !== 'function') return [];
|
|
122
|
-
let model;
|
|
123
|
-
try {
|
|
124
|
-
model = parseDesignMd(design);
|
|
125
|
-
} catch {
|
|
126
|
-
return [];
|
|
127
|
-
}
|
|
128
|
-
const missing = ['colors', 'typography', 'components']
|
|
129
|
-
.filter((section) => !model[section]);
|
|
130
|
-
if (!missing.length) return [];
|
|
131
|
-
return [finding({
|
|
132
|
-
id: 'design-md-coverage',
|
|
133
|
-
artifact: 'DESIGN.md',
|
|
134
|
-
filePath: designPath,
|
|
135
|
-
severity: 'mention',
|
|
136
|
-
summary: `${designPath || 'DESIGN.md'} has no ${missing.join(', ')} section. `
|
|
137
|
-
+ 'Agents generating new screens get no normative guidance for those, and the live design panel renders '
|
|
138
|
-
+ 'generic approximations in their place.',
|
|
139
|
-
fix: 'Ask whether the section never applied or was never written. `document` fills it from the code if the '
|
|
140
|
-
+ 'project has the answer in its CSS.',
|
|
141
|
-
})];
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// ─── detector ignore lists ─────────────────────────────────────────────────
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Ignore entries that no longer match anything: rule ids the engine dropped or
|
|
148
|
-
* renamed, and file paths that are gone. Both read as working suppressions
|
|
149
|
-
* until someone checks, and a dead rule ignore also hides that the rule left.
|
|
150
|
-
*/
|
|
151
|
-
export function checkDetectorIgnores({ projectRoot, knownRuleIds = null }) {
|
|
152
|
-
const findings = [];
|
|
153
|
-
if (!projectRoot) return findings;
|
|
154
|
-
|
|
155
|
-
for (const name of ['config.json', 'config.local.json']) {
|
|
156
|
-
const filePath = path.join(projectRoot, '.impeccable', name);
|
|
157
|
-
const raw = readJson(filePath);
|
|
158
|
-
const detector = raw?.detector;
|
|
159
|
-
if (!detector || typeof detector !== 'object') continue;
|
|
160
|
-
const rel = toRelative(filePath, projectRoot);
|
|
161
|
-
|
|
162
|
-
if (knownRuleIds && Array.isArray(detector.ignoreRules)) {
|
|
163
|
-
const unknown = detector.ignoreRules
|
|
164
|
-
.map((rule) => String(rule || '').trim().toLowerCase())
|
|
165
|
-
.filter((rule) => rule && rule !== '*' && !knownRuleIds.has(rule));
|
|
166
|
-
if (unknown.length) {
|
|
167
|
-
findings.push(finding({
|
|
168
|
-
id: 'detector-ignore-rules-unknown',
|
|
169
|
-
artifact: 'config.json',
|
|
170
|
-
filePath: rel,
|
|
171
|
-
severity: 'mention',
|
|
172
|
-
summary: `${rel} ignores rule id(s) the detector does not have: `
|
|
173
|
-
+ `${unknown.map((rule) => `\`${rule}\``).join(', ')}. Either the rule was renamed or removed, or the `
|
|
174
|
-
+ 'id was mistyped and has never suppressed anything.',
|
|
175
|
-
fix: 'Report the exact ids. Removing them is safe; keeping a dead ignore hides that the rule is gone.',
|
|
176
|
-
}));
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
if (Array.isArray(detector.ignoreFiles)) {
|
|
181
|
-
const missing = detector.ignoreFiles
|
|
182
|
-
.map((entry) => String(entry || '').trim())
|
|
183
|
-
.filter((entry) => entry && !entry.includes('*') && !fs.existsSync(path.join(projectRoot, entry)));
|
|
184
|
-
if (missing.length) {
|
|
185
|
-
findings.push(finding({
|
|
186
|
-
id: 'detector-ignore-files-missing',
|
|
187
|
-
artifact: 'config.json',
|
|
188
|
-
filePath: rel,
|
|
189
|
-
severity: 'mention',
|
|
190
|
-
summary: `${rel} ignores file path(s) that no longer exist: `
|
|
191
|
-
+ `${missing.map((entry) => `\`${entry}\``).join(', ')}.`,
|
|
192
|
-
fix: 'Ask whether the file moved (repoint the entry) or was deleted (drop it). '
|
|
193
|
-
+ 'A stale entry silently stops covering the file that replaced it.',
|
|
194
|
-
}));
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
return findings;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// ─── hook installation ─────────────────────────────────────────────────────
|
|
202
|
-
|
|
203
|
-
function collectHookCommands(value, out = []) {
|
|
204
|
-
if (typeof value === 'string') {
|
|
205
|
-
if (HOOK_SCRIPT_MARKERS.some((marker) => value.includes(marker))) out.push(value);
|
|
206
|
-
return out;
|
|
207
|
-
}
|
|
208
|
-
if (Array.isArray(value)) {
|
|
209
|
-
for (const entry of value) collectHookCommands(entry, out);
|
|
210
|
-
return out;
|
|
211
|
-
}
|
|
212
|
-
if (value && typeof value === 'object') {
|
|
213
|
-
for (const entry of Object.values(value)) collectHookCommands(entry, out);
|
|
214
|
-
}
|
|
215
|
-
return out;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const HOOK_MARKER = /skills\/impeccable\/scripts\/hook(?:-before-edit)?\.mjs/;
|
|
219
|
-
|
|
220
|
-
// Pull the script-path token out of a hook command line, placeholders intact.
|
|
221
|
-
// The forms our manifests ship:
|
|
222
|
-
// * bare: node "${CLAUDE_PROJECT_DIR}/.../hook.mjs"
|
|
223
|
-
// * bundle-relative: node ".agents/.../hook.mjs"
|
|
224
|
-
// * legacy unquoted: node .claude/.../hook.mjs
|
|
225
|
-
// * guarded (#399): [ ! -f "PATH" ] || node "PATH" (PATH twice, identical)
|
|
226
|
-
// * absolute: node "/Users/.../hook.mjs" (user-level installs)
|
|
227
|
-
// * github portable: node "$(git rev-parse --show-toplevel)/.../hook.mjs"
|
|
228
|
-
// A quoted path wins; the guard's two occurrences are identical, so the first
|
|
229
|
-
// quoted match is the path. Otherwise fall back to the whitespace/metachar-
|
|
230
|
-
// delimited token that ends at the marker, so we don't absorb `node`, `[`, `!`
|
|
231
|
-
// or `||`. Returns the token verbatim; resolution happens separately.
|
|
232
|
-
function hookScriptTokenFrom(command) {
|
|
233
|
-
const str = String(command);
|
|
234
|
-
if (!HOOK_MARKER.test(str)) return null;
|
|
235
|
-
const quoted = str.match(/"([^"]*skills\/impeccable\/scripts\/hook(?:-before-edit)?\.mjs)"/);
|
|
236
|
-
if (quoted) return quoted[1];
|
|
237
|
-
const bare = str.match(/([^\s"'|&;()]*skills\/impeccable\/scripts\/hook(?:-before-edit)?\.mjs)/);
|
|
238
|
-
return bare ? bare[1] : null;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// Resolve a script token to an absolute path the doctor can existsSync, or null
|
|
242
|
-
// when the doctor cannot know where it points — in which case the caller must
|
|
243
|
-
// NOT report it missing (a doctor never asserts a negative it cannot verify).
|
|
244
|
-
//
|
|
245
|
-
// Per-placeholder policy, mirroring what each runtime actually expands:
|
|
246
|
-
// ${CLAUDE_PROJECT_DIR} → the project root being scanned. This is exactly the
|
|
247
|
-
// runtime mapping (Claude Code sets it to the project
|
|
248
|
-
// dir at hook time), so we EXPAND it against `root`.
|
|
249
|
-
// Not doing so was the #402 bug: the literal
|
|
250
|
-
// `${CLAUDE_PROJECT_DIR}/...` string never exists.
|
|
251
|
-
// ${CLAUDE_PLUGIN_ROOT} → plugin-package install dir, set by the harness to
|
|
252
|
-
// ${PLUGIN_ROOT} wherever the plugin/codex/grok bundle was unpacked
|
|
253
|
-
// ${GROK_PLUGIN_ROOT} (grok aliases CLAUDE_PLUGIN_ROOT). The doctor has no
|
|
254
|
-
// way to know that location → SKIP (return null).
|
|
255
|
-
// $(...) / backticks → command substitution, e.g. GitHub's
|
|
256
|
-
// `$(git rev-parse --show-toplevel)`. Not statically
|
|
257
|
-
// resolvable → SKIP.
|
|
258
|
-
// any other ${VAR}/$VAR → unknown to the doctor → SKIP.
|
|
259
|
-
// A token with no placeholder is a literal path: absolute as-is, else relative
|
|
260
|
-
// to `root`.
|
|
261
|
-
function resolveHookScriptPath(token, root) {
|
|
262
|
-
if (!token) return null;
|
|
263
|
-
// Command substitution or backtick expansion we can't evaluate.
|
|
264
|
-
if (token.includes('$(') || token.includes('`')) return null;
|
|
265
|
-
const expanded = token.replace(/\$\{CLAUDE_PROJECT_DIR\}/g, root);
|
|
266
|
-
// Any placeholder or shell variable still present is one we can't map.
|
|
267
|
-
if (/\$\{[^}]*\}|\$[A-Za-z_]/.test(expanded)) return null;
|
|
268
|
-
return path.isAbsolute(expanded) ? expanded : path.join(root, expanded);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* A hook whose script path does not resolve is a silent no-op, and the user
|
|
273
|
-
* believes the project is covered. Also catches the contradiction of an
|
|
274
|
-
* installed manifest against `hook.enabled: false`.
|
|
275
|
-
*/
|
|
276
|
-
export function checkHookInstallation({ projectRoot, repoRoot, providerId }) {
|
|
277
|
-
const findings = [];
|
|
278
|
-
const manifests = HOOK_MANIFESTS_BY_PROVIDER[providerId] || [];
|
|
279
|
-
if (!manifests.length) return findings;
|
|
280
|
-
|
|
281
|
-
const roots = [...new Set([projectRoot, repoRoot].filter(Boolean).map((root) => path.resolve(root)))];
|
|
282
|
-
let installedAt = null;
|
|
283
|
-
|
|
284
|
-
for (const root of roots) {
|
|
285
|
-
for (const rel of manifests) {
|
|
286
|
-
const manifestPath = path.join(root, rel);
|
|
287
|
-
const raw = readJson(manifestPath);
|
|
288
|
-
if (!raw?.hooks) continue;
|
|
289
|
-
const commands = collectHookCommands(raw.hooks);
|
|
290
|
-
if (!commands.length) continue;
|
|
291
|
-
installedAt = toRelative(manifestPath, projectRoot || root);
|
|
292
|
-
|
|
293
|
-
const broken = commands.filter((command) => {
|
|
294
|
-
const token = hookScriptTokenFrom(command);
|
|
295
|
-
if (!token) return false;
|
|
296
|
-
const abs = resolveHookScriptPath(token, root);
|
|
297
|
-
// Unresolvable placeholder or command substitution: never assert missing.
|
|
298
|
-
if (!abs) return false;
|
|
299
|
-
return !fs.existsSync(abs);
|
|
300
|
-
});
|
|
301
|
-
if (broken.length) {
|
|
302
|
-
findings.push(finding({
|
|
303
|
-
id: 'hook-script-missing',
|
|
304
|
-
artifact: 'hook manifest',
|
|
305
|
-
filePath: installedAt,
|
|
306
|
-
severity: 'mention',
|
|
307
|
-
summary: `${installedAt} installs the design hook, but its script path does not exist: `
|
|
308
|
-
+ `${broken.map((command) => `\`${command}\``).join(', ')}. The hook runs as a no-op, so UI edits `
|
|
309
|
-
+ 'have been going unscanned while the project looks covered.',
|
|
310
|
-
fix: `Reinstall with \`impeccable hooks on\`, which rewrites the manifest against the skill's current location.`,
|
|
311
|
-
}));
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
if (installedAt) {
|
|
317
|
-
for (const root of roots) {
|
|
318
|
-
for (const name of ['config.json', 'config.local.json']) {
|
|
319
|
-
const raw = readJson(path.join(root, '.impeccable', name));
|
|
320
|
-
if (raw?.hook && raw.hook.enabled === false) {
|
|
321
|
-
findings.push(finding({
|
|
322
|
-
id: 'hook-enabled-conflict',
|
|
323
|
-
artifact: 'config.json',
|
|
324
|
-
filePath: toRelative(path.join(root, '.impeccable', name), projectRoot || root),
|
|
325
|
-
severity: 'mention',
|
|
326
|
-
summary: `${installedAt} installs the design hook while this config sets \`hook.enabled: false\`, `
|
|
327
|
-
+ 'so the hook fires and then declines to scan.',
|
|
328
|
-
fix: 'Ask which was intended: `impeccable hooks on` to enable, or `impeccable hooks off` to uninstall '
|
|
329
|
-
+ 'the manifest entry as well.',
|
|
330
|
-
}));
|
|
331
|
-
return findings;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
return findings;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// ─── retired locations ─────────────────────────────────────────────────────
|
|
341
|
-
|
|
342
|
-
export function checkLegacyLiveState({ projectRoot }) {
|
|
343
|
-
if (!projectRoot) return [];
|
|
344
|
-
const present = LEGACY_LIVE_PATHS.filter((rel) => fs.existsSync(path.join(projectRoot, rel)));
|
|
345
|
-
if (!present.length) return [];
|
|
346
|
-
return [finding({
|
|
347
|
-
id: 'legacy-live-state',
|
|
348
|
-
artifact: 'live state',
|
|
349
|
-
filePath: present.join(', '),
|
|
350
|
-
severity: 'auto',
|
|
351
|
-
summary: `Live-mode state sits in retired location(s): ${present.map((rel) => `\`${rel}\``).join(', ')}. `
|
|
352
|
-
+ 'Current live mode writes under `.impeccable/live/`.',
|
|
353
|
-
fix: 'These are read only through backward-compatible fallbacks and are safe to delete once no live session '
|
|
354
|
-
+ 'is running. No user decision is needed.',
|
|
355
|
-
})];
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
// ─── monorepo sweep ────────────────────────────────────────────────────────
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Per-workspace context, plus the case worth acting on: a workspace with
|
|
362
|
-
* native build files inheriting a repo-root PRODUCT.md that says web. Each
|
|
363
|
-
* such app gets web guidance and never loads the native references, and
|
|
364
|
-
* nothing at boot reports it because the root record parses cleanly.
|
|
365
|
-
*
|
|
366
|
-
* `candidates` comes from context.mjs's discovery so the walk is not repeated.
|
|
367
|
-
*/
|
|
368
|
-
export function checkWorkspaces({ repoRoot, candidates = [], checkNativePlatformEvidence, extractPlatform, readFile }) {
|
|
369
|
-
if (!repoRoot || !candidates.length) return { findings: [], workspaces: [] };
|
|
370
|
-
const findings = [];
|
|
371
|
-
const workspaces = [];
|
|
372
|
-
|
|
373
|
-
for (const candidate of candidates) {
|
|
374
|
-
const workspaceRoot = path.join(repoRoot, candidate.path);
|
|
375
|
-
const productPath = candidate.productPath ? path.join(repoRoot, candidate.productPath) : null;
|
|
376
|
-
const product = productPath && readFile ? readFile(productPath) : null;
|
|
377
|
-
const platform = extractPlatform ? extractPlatform(product) : null;
|
|
378
|
-
|
|
379
|
-
workspaces.push({
|
|
380
|
-
name: candidate.name,
|
|
381
|
-
path: candidate.path,
|
|
382
|
-
productStatus: candidate.productStatus,
|
|
383
|
-
productPath: candidate.productPath,
|
|
384
|
-
designStatus: candidate.designStatus,
|
|
385
|
-
designPath: candidate.designPath,
|
|
386
|
-
platform: platform || (product ? 'web (default)' : null),
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
if (!checkNativePlatformEvidence) continue;
|
|
390
|
-
const native = checkNativePlatformEvidence({
|
|
391
|
-
projectRoot: workspaceRoot,
|
|
392
|
-
platform,
|
|
393
|
-
product,
|
|
394
|
-
productPath: candidate.productPath,
|
|
395
|
-
});
|
|
396
|
-
for (const entry of native) {
|
|
397
|
-
findings.push(finding({
|
|
398
|
-
id: 'workspace-platform-native-evidence',
|
|
399
|
-
artifact: 'PRODUCT.md',
|
|
400
|
-
filePath: candidate.productPath || `${candidate.path}/PRODUCT.md`,
|
|
401
|
-
severity: 'mention',
|
|
402
|
-
summary: `Workspace \`${candidate.path}\` ${
|
|
403
|
-
candidate.productStatus === 'inherited'
|
|
404
|
-
? 'inherits the repo-root PRODUCT.md'
|
|
405
|
-
: 'has a PRODUCT.md'
|
|
406
|
-
} that resolves to web, but the workspace itself carries native build files. ${entry.summary}`,
|
|
407
|
-
fix: candidate.productStatus === 'inherited'
|
|
408
|
-
? `Give \`${candidate.path}\` its own PRODUCT.md with the right \`## Platform\`. `
|
|
409
|
-
+ 'An inherited record cannot describe two platforms at once.'
|
|
410
|
-
: entry.fix,
|
|
411
|
-
}));
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
const inherited = workspaces.filter((entry) => entry.productStatus === 'inherited');
|
|
416
|
-
if (inherited.length) {
|
|
417
|
-
findings.push(finding({
|
|
418
|
-
id: 'workspace-context-inherited',
|
|
419
|
-
artifact: 'PRODUCT.md',
|
|
420
|
-
filePath: null,
|
|
421
|
-
severity: 'mention',
|
|
422
|
-
summary: `${inherited.length} of ${workspaces.length} workspace(s) inherit the repo-root PRODUCT.md: `
|
|
423
|
-
+ `${inherited.map((entry) => `\`${entry.path}\``).join(', ')}. Inheritance is intended; whether one `
|
|
424
|
-
+ 'record truthfully describes these apps is not something this check can tell.',
|
|
425
|
-
fix: 'Ask the user whether the inherited record describes each app. Where it does not, `init` in that '
|
|
426
|
-
+ 'workspace writes a child PRODUCT.md that overrides it.',
|
|
427
|
-
}));
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
return { findings, workspaces };
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
// ─── rule registry ─────────────────────────────────────────────────────────
|
|
434
|
-
|
|
435
|
-
/**
|
|
436
|
-
* Rule ids from the bundled detector, or null when it cannot be resolved (a
|
|
437
|
-
* partial install, or a harness that ships the skill without the engine).
|
|
438
|
-
* Null means "cannot check", which the ignore-rule check treats as skip rather
|
|
439
|
-
* than as every id being unknown.
|
|
440
|
-
*/
|
|
441
|
-
export async function loadKnownRuleIds(scriptsDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')) {
|
|
442
|
-
// Same two locations detect.mjs resolves: the bundled copy in an installed
|
|
443
|
-
// skill, then the source-repo engine when running from a checkout.
|
|
444
|
-
const candidates = [
|
|
445
|
-
path.join(scriptsDir, 'detector', 'detect-antipatterns.mjs'),
|
|
446
|
-
path.join(scriptsDir, '..', '..', 'cli', 'engine', 'detect-antipatterns.mjs'),
|
|
447
|
-
];
|
|
448
|
-
const detectorPath = candidates.find((candidate) => fs.existsSync(candidate));
|
|
449
|
-
if (!detectorPath) return null;
|
|
450
|
-
try {
|
|
451
|
-
const { ANTIPATTERNS } = await import(pathToFileURL(detectorPath).href);
|
|
452
|
-
if (!Array.isArray(ANTIPATTERNS)) return null;
|
|
453
|
-
return new Set(ANTIPATTERNS.map((rule) => String(rule.id).toLowerCase()));
|
|
454
|
-
} catch {
|
|
455
|
-
return null;
|
|
456
|
-
}
|
|
457
|
-
}
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Notice throttling and directive rendering for staleness findings.
|
|
3
|
-
*
|
|
4
|
-
* The boot path already carries PRODUCT.md, DESIGN.md, a surface brief,
|
|
5
|
-
* RESOLVED_CONTEXT, the detector fallback, native platform references, and the
|
|
6
|
-
* update directive. An unthrottled staleness block would push real context out
|
|
7
|
-
* of attention and train the agent to open every session with housekeeping, so
|
|
8
|
-
* the rules here are deliberately strict:
|
|
9
|
-
*
|
|
10
|
-
* - One directive for the whole set, never one per finding.
|
|
11
|
-
* - A 'mention' or 'route' finding surfaces at most once a week per project,
|
|
12
|
-
* mirroring the update check's anti-nag window. A finding the user has
|
|
13
|
-
* already declined to act on must not reappear tomorrow.
|
|
14
|
-
* - 'auto' findings are not throttled and are not shown to the user. They are
|
|
15
|
-
* migrations the next write performs anyway, so the agent needs the note
|
|
16
|
-
* every session until the write happens, and the user needs it never.
|
|
17
|
-
*
|
|
18
|
-
* State lives in the user's home dir alongside the update cache rather than in
|
|
19
|
-
* the project, so no gitignore entry is owed and a clone does not inherit
|
|
20
|
-
* someone else's dismissals.
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
import fs from 'node:fs';
|
|
24
|
-
import os from 'node:os';
|
|
25
|
-
import path from 'node:path';
|
|
26
|
-
|
|
27
|
-
const RENOTIFY_INTERVAL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
28
|
-
|
|
29
|
-
// Resolved per call rather than at import so a test (or a sandboxed run) can
|
|
30
|
-
// redirect the cache without reloading the module.
|
|
31
|
-
function cachePath() {
|
|
32
|
-
return process.env.IMPECCABLE_STALENESS_CACHE
|
|
33
|
-
|| path.join(os.homedir(), '.impeccable', 'staleness-check.json');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function readCache() {
|
|
37
|
-
try {
|
|
38
|
-
const raw = JSON.parse(fs.readFileSync(cachePath(), 'utf-8'));
|
|
39
|
-
return raw && typeof raw === 'object' && raw.projects ? raw : { projects: {} };
|
|
40
|
-
} catch {
|
|
41
|
-
return { projects: {} };
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Drop project entries whose newest stamp has aged past the renotify window.
|
|
47
|
-
* They would be re-notified on the next boot anyway, so keeping them only lets
|
|
48
|
-
* the file accumulate one entry per directory Impeccable has ever booted in
|
|
49
|
-
* (scratch dirs and test fixtures included).
|
|
50
|
-
*/
|
|
51
|
-
function pruneCache(cache, now) {
|
|
52
|
-
const projects = {};
|
|
53
|
-
for (const [key, entries] of Object.entries(cache.projects || {})) {
|
|
54
|
-
if (!entries || typeof entries !== 'object') continue;
|
|
55
|
-
const stamps = Object.values(entries).filter((value) => typeof value === 'number');
|
|
56
|
-
if (stamps.length && now - Math.max(...stamps) < RENOTIFY_INTERVAL_MS) projects[key] = entries;
|
|
57
|
-
}
|
|
58
|
-
return { projects };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function writeCache(cache) {
|
|
62
|
-
try {
|
|
63
|
-
const filePath = cachePath();
|
|
64
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
65
|
-
fs.writeFileSync(filePath, JSON.stringify(cache));
|
|
66
|
-
} catch {
|
|
67
|
-
// Best-effort. A read-only home dir means the notice repeats next session,
|
|
68
|
-
// which is strictly better than failing the boot.
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function readJson(filePath) {
|
|
73
|
-
try {
|
|
74
|
-
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
75
|
-
} catch {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Opt out with IMPECCABLE_NO_STALENESS_CHECK=1 or `"stalenessCheck": false` in
|
|
82
|
-
* .impeccable/config.json. Local config overrides shared, matching how
|
|
83
|
-
* updateCheck resolves.
|
|
84
|
-
*/
|
|
85
|
-
export function stalenessCheckDisabled(roots = [process.cwd()]) {
|
|
86
|
-
if (process.env.IMPECCABLE_NO_STALENESS_CHECK) return true;
|
|
87
|
-
let value;
|
|
88
|
-
for (const root of roots) {
|
|
89
|
-
if (!root) continue;
|
|
90
|
-
for (const name of ['config.json', 'config.local.json']) {
|
|
91
|
-
const raw = readJson(path.join(root, '.impeccable', name));
|
|
92
|
-
if (raw && typeof raw === 'object' && typeof raw.stalenessCheck === 'boolean') {
|
|
93
|
-
value = raw.stalenessCheck;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return value === false;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Drop findings already surfaced for this project inside the renotify window,
|
|
102
|
-
* and stamp the ones that survive. 'auto' findings pass through untouched and
|
|
103
|
-
* unstamped: they are for the agent, not the user, and repeat until fixed.
|
|
104
|
-
*/
|
|
105
|
-
export function filterFreshFindings(findings, { projectRoot, now = Date.now() } = {}) {
|
|
106
|
-
if (!findings.length) return [];
|
|
107
|
-
const auto = findings.filter((entry) => entry.severity === 'auto');
|
|
108
|
-
const notifiable = findings.filter((entry) => entry.severity !== 'auto');
|
|
109
|
-
if (!notifiable.length) return auto;
|
|
110
|
-
|
|
111
|
-
const key = path.resolve(projectRoot || process.cwd());
|
|
112
|
-
const cache = readCache();
|
|
113
|
-
const seen = cache.projects[key] && typeof cache.projects[key] === 'object' ? cache.projects[key] : {};
|
|
114
|
-
|
|
115
|
-
const fresh = notifiable.filter((entry) => {
|
|
116
|
-
const last = seen[entry.id];
|
|
117
|
-
return !(typeof last === 'number' && now - last < RENOTIFY_INTERVAL_MS);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
// Forget stamps for findings that no longer fire, so a recurrence after a
|
|
121
|
-
// real fix is reported again instead of being suppressed by an old stamp.
|
|
122
|
-
// This has to run even when nothing is fresh: the common shape is one
|
|
123
|
-
// finding fixed while another is still inside its window.
|
|
124
|
-
const live = new Set(notifiable.map((entry) => entry.id));
|
|
125
|
-
const next = Object.fromEntries(
|
|
126
|
-
Object.entries(seen).filter(([id]) => live.has(id)),
|
|
127
|
-
);
|
|
128
|
-
for (const entry of fresh) next[entry.id] = now;
|
|
129
|
-
|
|
130
|
-
const changed = JSON.stringify(next) !== JSON.stringify(seen);
|
|
131
|
-
if (changed) {
|
|
132
|
-
const pruned = pruneCache(cache, now);
|
|
133
|
-
pruned.projects[key] = next;
|
|
134
|
-
writeCache(pruned);
|
|
135
|
-
}
|
|
136
|
-
return [...auto, ...fresh];
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Render the single boot directive, or null when nothing survived throttling.
|
|
141
|
-
*/
|
|
142
|
-
export function buildStalenessDirective(findings) {
|
|
143
|
-
if (!findings.length) return null;
|
|
144
|
-
const payload = findings.map((entry) => ({
|
|
145
|
-
id: entry.id,
|
|
146
|
-
artifact: entry.artifact,
|
|
147
|
-
path: entry.path,
|
|
148
|
-
severity: entry.severity,
|
|
149
|
-
summary: entry.summary,
|
|
150
|
-
fix: entry.fix,
|
|
151
|
-
}));
|
|
152
|
-
|
|
153
|
-
const hasReportable = findings.some((entry) => entry.severity !== 'auto');
|
|
154
|
-
const lines = [
|
|
155
|
-
`CONTEXT_STALE:\n${JSON.stringify(payload, null, 2)}`,
|
|
156
|
-
"Impeccable's own project files have drifted from what this version reads. "
|
|
157
|
-
+ 'Do not stop, reorder, or expand the requested task for any of this.',
|
|
158
|
-
'By severity: `auto` is a migration the next write to that file performs anyway, so apply it then and do not '
|
|
159
|
-
+ 'raise it with the user. `mention` gets one short line in your reply with the offered fix. `route` names the '
|
|
160
|
-
+ 'command that owns the repair; offer it, and run it only if the user asks.',
|
|
161
|
-
'A finding that reports a deprecated field is binding: treat that field as absent for every decision in this '
|
|
162
|
-
+ 'session, whatever value it holds.',
|
|
163
|
-
];
|
|
164
|
-
if (hasReportable) {
|
|
165
|
-
lines.push('Surface the reportable findings once, after the task response, in at most two sentences. '
|
|
166
|
-
+ 'They are already throttled, so say them plainly rather than hedging about whether they matter.');
|
|
167
|
-
}
|
|
168
|
-
return lines.join(' ');
|
|
169
|
-
}
|