@xhulz/nina 0.53.3 → 0.55.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 +1 -1
- package/package.json +1 -1
- package/releases/0.54.0/core/GAPS.md +125 -0
- package/releases/0.54.0/core/answered.json +68 -0
- package/releases/0.54.0/core/defaults/tree/.claude/agents/architect.md +1 -0
- package/releases/0.54.0/core/defaults/tree/.claude/agents/dba.md +3 -0
- package/releases/0.54.0/core/defaults/tree/.claude/agents/devops.md +1 -0
- package/releases/0.54.0/core/defaults/tree/.claude/agents/implementer.md +1 -0
- package/releases/0.54.0/core/defaults/tree/.claude/agents/integration-tester.md +3 -0
- package/releases/0.54.0/core/defaults/tree/.claude/agents/qa.md +7 -0
- package/releases/0.54.0/core/defaults/tree/.claude/agents/reviewer.md +3 -0
- package/releases/0.54.0/core/defaults/tree/.claude/agents/secops.md +3 -0
- package/releases/0.54.0/core/defaults/tree/.claude/agents/solidity-auditor.md +3 -0
- package/releases/0.54.0/core/defaults/tree/.claude/agents/solidity-dev.md +3 -0
- package/releases/0.54.0/core/tree/.claude/agents/architect.md +129 -0
- package/releases/0.54.0/core/tree/.claude/agents/dba.md +117 -0
- package/releases/0.54.0/core/tree/.claude/agents/devops.md +118 -0
- package/releases/0.54.0/core/tree/.claude/agents/implementer.md +163 -0
- package/releases/0.54.0/core/tree/.claude/agents/integration-tester.md +168 -0
- package/releases/0.54.0/core/tree/.claude/agents/planner.md +132 -0
- package/releases/0.54.0/core/tree/.claude/agents/qa.md +150 -0
- package/releases/0.54.0/core/tree/.claude/agents/reviewer.md +184 -0
- package/releases/0.54.0/core/tree/.claude/agents/secops.md +120 -0
- package/releases/0.54.0/core/tree/.claude/agents/solidity-auditor.md +126 -0
- package/releases/0.54.0/core/tree/.claude/agents/solidity-dev.md +123 -0
- package/releases/0.54.0/core/tree/.claude/agents-overview.md +64 -0
- package/releases/0.54.0/core/tree/.claude/frontend.md +10 -0
- package/releases/0.54.0/core/tree/.claude/graph.md +75 -0
- package/releases/0.54.0/core/tree/.claude/patterns.md +251 -0
- package/releases/0.54.0/core/tree/.claude/pills/README.md +150 -0
- package/releases/0.54.0/core/tree/.claude/pipeline.md +101 -0
- package/releases/0.54.0/core/tree/.claude/retrieval.md +103 -0
- package/releases/0.54.0/core/tree/.claude/router.md +202 -0
- package/releases/0.54.0/core/tree/.claude/templates/integration.md +48 -0
- package/releases/0.54.0/core/tree/CLAUDE.md +164 -0
- package/releases/0.54.0/core/tree/scripts/cost-watch.mjs +25 -0
- package/releases/0.54.0/core/tree/scripts/edit-guard.mjs +24 -0
- package/releases/0.54.0/core/tree/scripts/harness-check.mjs +71 -0
- package/releases/0.54.0/core/tree/scripts/loop-gate.mjs +19 -0
- package/releases/0.54.0/core/vocabulary.json +13 -0
- package/releases/0.54.0/surfaces/blockchain/tree/.claude/agents/architect.md +5 -0
- package/releases/0.54.0/surfaces/blockchain/tree/.claude/agents/devops.md +5 -0
- package/releases/0.54.0/surfaces/blockchain/tree/.claude/agents/reviewer.md +5 -0
- package/releases/0.54.0/surfaces/blockchain/tree/.claude/agents/solidity-auditor.md +18 -0
- package/releases/0.54.0/surfaces/blockchain/tree/.claude/agents/solidity-dev.md +16 -0
- package/releases/0.54.0/surfaces/blockchain/tree/.claude/agents-overview.md +6 -0
- package/releases/0.54.0/surfaces/blockchain/tree/.claude/graph.md +11 -0
- package/releases/0.54.0/surfaces/blockchain/tree/.claude/router.md +6 -0
- package/releases/0.54.0/surfaces/blockchain/tree/CLAUDE.md +12 -0
- package/releases/0.54.0/surfaces/d1/tree/.claude/agents/dba.md +15 -0
- package/releases/0.54.0/surfaces/d1/tree/.claude/agents/devops.md +2 -0
- package/releases/0.54.0/surfaces/d1/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.54.0/surfaces/d1/tree/.claude/patterns.md +8 -0
- package/releases/0.54.0/surfaces/d1/tree/CLAUDE.md +2 -0
- package/releases/0.54.0/surfaces/db/tree/.claude/agents/architect.md +5 -0
- package/releases/0.54.0/surfaces/db/tree/.claude/agents/dba.md +54 -0
- package/releases/0.54.0/surfaces/db/tree/.claude/agents/devops.md +5 -0
- package/releases/0.54.0/surfaces/db/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.54.0/surfaces/db/tree/.claude/agents/integration-tester.md +10 -0
- package/releases/0.54.0/surfaces/db/tree/.claude/agents/planner.md +2 -0
- package/releases/0.54.0/surfaces/db/tree/.claude/agents/reviewer.md +22 -0
- package/releases/0.54.0/surfaces/db/tree/.claude/agents/secops.md +2 -0
- package/releases/0.54.0/surfaces/db/tree/.claude/agents-overview.md +5 -0
- package/releases/0.54.0/surfaces/db/tree/.claude/graph.md +8 -0
- package/releases/0.54.0/surfaces/db/tree/.claude/patterns.md +22 -0
- package/releases/0.54.0/surfaces/db/tree/.claude/pipeline.md +13 -0
- package/releases/0.54.0/surfaces/db/tree/.claude/retrieval.md +5 -0
- package/releases/0.54.0/surfaces/db/tree/.claude/router.md +4 -0
- package/releases/0.54.0/surfaces/db/tree/CLAUDE.md +17 -0
- package/releases/0.54.0/surfaces/drizzle/tree/.claude/agents/dba.md +9 -0
- package/releases/0.54.0/surfaces/drizzle/tree/.claude/agents/devops.md +5 -0
- package/releases/0.54.0/surfaces/drizzle/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.54.0/surfaces/drizzle/tree/.claude/patterns.md +7 -0
- package/releases/0.54.0/surfaces/edge-cf/tree/.claude/agents/architect.md +14 -0
- package/releases/0.54.0/surfaces/edge-cf/tree/.claude/agents/dba.md +2 -0
- package/releases/0.54.0/surfaces/edge-cf/tree/.claude/agents/devops.md +29 -0
- package/releases/0.54.0/surfaces/edge-cf/tree/.claude/agents/implementer.md +14 -0
- package/releases/0.54.0/surfaces/edge-cf/tree/.claude/agents/integration-tester.md +11 -0
- package/releases/0.54.0/surfaces/edge-cf/tree/.claude/agents/qa.md +3 -0
- package/releases/0.54.0/surfaces/edge-cf/tree/.claude/agents/reviewer.md +8 -0
- package/releases/0.54.0/surfaces/edge-cf/tree/.claude/agents/secops.md +8 -0
- package/releases/0.54.0/surfaces/edge-cf/tree/.claude/patterns.md +17 -0
- package/releases/0.54.0/surfaces/edge-cf/tree/.claude/retrieval.md +8 -0
- package/releases/0.54.0/surfaces/edge-cf/tree/CLAUDE.md +27 -0
- package/releases/0.54.0/surfaces/frontend/tree/.claude/agents/architect.md +20 -0
- package/releases/0.54.0/surfaces/frontend/tree/.claude/agents/devops.md +28 -0
- package/releases/0.54.0/surfaces/frontend/tree/.claude/agents/implementer.md +25 -0
- package/releases/0.54.0/surfaces/frontend/tree/.claude/agents/qa.md +17 -0
- package/releases/0.54.0/surfaces/frontend/tree/.claude/agents/reviewer.md +56 -0
- package/releases/0.54.0/surfaces/frontend/tree/.claude/patterns.md +8 -0
- package/releases/0.54.0/surfaces/frontend/tree/.claude/retrieval.md +2 -0
- package/releases/0.54.0/surfaces/frontend/tree/.claude/router.md +14 -0
- package/releases/0.54.0/surfaces/frontend/tree/CLAUDE.md +5 -0
- package/releases/0.54.0/surfaces/integrations/tree/.claude/agents/architect.md +16 -0
- package/releases/0.54.0/surfaces/integrations/tree/.claude/agents/implementer.md +12 -0
- package/releases/0.54.0/surfaces/integrations/tree/.claude/agents/integration-tester.md +20 -0
- package/releases/0.54.0/surfaces/integrations/tree/.claude/agents/planner.md +2 -0
- package/releases/0.54.0/surfaces/integrations/tree/.claude/agents/reviewer.md +21 -0
- package/releases/0.54.0/surfaces/integrations/tree/.claude/agents/secops.md +2 -0
- package/releases/0.54.0/surfaces/integrations/tree/.claude/agents-overview.md +8 -0
- package/releases/0.54.0/surfaces/integrations/tree/.claude/graph.md +10 -0
- package/releases/0.54.0/surfaces/integrations/tree/.claude/patterns.md +38 -0
- package/releases/0.54.0/surfaces/integrations/tree/.claude/pipeline.md +16 -0
- package/releases/0.54.0/surfaces/integrations/tree/.claude/retrieval.md +16 -0
- package/releases/0.54.0/surfaces/integrations/tree/.claude/router.md +6 -0
- package/releases/0.54.0/surfaces/integrations/tree/CLAUDE.md +17 -0
- package/releases/0.54.0/surfaces/money/tree/.claude/agents/architect.md +12 -0
- package/releases/0.54.0/surfaces/money/tree/.claude/agents/dba.md +14 -0
- package/releases/0.54.0/surfaces/money/tree/.claude/agents/implementer.md +11 -0
- package/releases/0.54.0/surfaces/money/tree/.claude/agents/integration-tester.md +3 -0
- package/releases/0.54.0/surfaces/money/tree/.claude/agents/reviewer.md +23 -0
- package/releases/0.54.0/surfaces/money/tree/.claude/agents/secops.md +5 -0
- package/releases/0.54.0/surfaces/money/tree/.claude/agents/solidity-auditor.md +4 -0
- package/releases/0.54.0/surfaces/money/tree/.claude/agents/solidity-dev.md +4 -0
- package/releases/0.54.0/surfaces/money/tree/.claude/graph.md +2 -0
- package/releases/0.54.0/surfaces/money/tree/.claude/patterns.md +49 -0
- package/releases/0.54.0/surfaces/money/tree/.claude/pipeline.md +2 -0
- package/releases/0.54.0/surfaces/money/tree/.claude/retrieval.md +2 -0
- package/releases/0.54.0/surfaces/money/tree/CLAUDE.md +11 -0
- package/releases/0.54.0/surfaces/pii/tree/.claude/agents/dba.md +2 -0
- package/releases/0.54.0/surfaces/pii/tree/.claude/agents/devops.md +8 -0
- package/releases/0.54.0/surfaces/pii/tree/.claude/agents/reviewer.md +8 -0
- package/releases/0.54.0/surfaces/pii/tree/.claude/agents/secops.md +2 -0
- package/releases/0.54.0/surfaces/pii/tree/.claude/agents/solidity-auditor.md +5 -0
- package/releases/0.54.0/surfaces/pii/tree/CLAUDE.md +5 -0
- package/releases/0.54.0/surfaces/prisma/tree/.claude/agents/architect.md +2 -0
- package/releases/0.54.0/surfaces/prisma/tree/.claude/agents/dba.md +42 -0
- package/releases/0.54.0/surfaces/prisma/tree/.claude/agents/devops.md +11 -0
- package/releases/0.54.0/surfaces/prisma/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.54.0/surfaces/prisma/tree/.claude/agents/integration-tester.md +2 -0
- package/releases/0.54.0/surfaces/prisma/tree/.claude/agents/reviewer.md +2 -0
- package/releases/0.54.0/surfaces/prisma/tree/.claude/patterns.md +15 -0
- package/releases/0.54.0/surfaces/prisma/tree/CLAUDE.md +5 -0
- package/releases/0.55.0/core/GAPS.md +125 -0
- package/releases/0.55.0/core/answered.json +68 -0
- package/releases/0.55.0/core/defaults/tree/.claude/agents/architect.md +1 -0
- package/releases/0.55.0/core/defaults/tree/.claude/agents/dba.md +3 -0
- package/releases/0.55.0/core/defaults/tree/.claude/agents/devops.md +1 -0
- package/releases/0.55.0/core/defaults/tree/.claude/agents/implementer.md +1 -0
- package/releases/0.55.0/core/defaults/tree/.claude/agents/integration-tester.md +3 -0
- package/releases/0.55.0/core/defaults/tree/.claude/agents/qa.md +7 -0
- package/releases/0.55.0/core/defaults/tree/.claude/agents/reviewer.md +3 -0
- package/releases/0.55.0/core/defaults/tree/.claude/agents/secops.md +3 -0
- package/releases/0.55.0/core/defaults/tree/.claude/agents/solidity-auditor.md +3 -0
- package/releases/0.55.0/core/defaults/tree/.claude/agents/solidity-dev.md +3 -0
- package/releases/0.55.0/core/tree/.claude/agents/architect.md +130 -0
- package/releases/0.55.0/core/tree/.claude/agents/dba.md +119 -0
- package/releases/0.55.0/core/tree/.claude/agents/design-reviewer.md +75 -0
- package/releases/0.55.0/core/tree/.claude/agents/devops.md +118 -0
- package/releases/0.55.0/core/tree/.claude/agents/implementer.md +163 -0
- package/releases/0.55.0/core/tree/.claude/agents/integration-tester.md +170 -0
- package/releases/0.55.0/core/tree/.claude/agents/planner.md +132 -0
- package/releases/0.55.0/core/tree/.claude/agents/qa.md +150 -0
- package/releases/0.55.0/core/tree/.claude/agents/reviewer.md +187 -0
- package/releases/0.55.0/core/tree/.claude/agents/secops.md +120 -0
- package/releases/0.55.0/core/tree/.claude/agents/solidity-auditor.md +126 -0
- package/releases/0.55.0/core/tree/.claude/agents/solidity-dev.md +123 -0
- package/releases/0.55.0/core/tree/.claude/agents-overview.md +65 -0
- package/releases/0.55.0/core/tree/.claude/frontend.md +10 -0
- package/releases/0.55.0/core/tree/.claude/graph.md +79 -0
- package/releases/0.55.0/core/tree/.claude/patterns.md +251 -0
- package/releases/0.55.0/core/tree/.claude/pills/README.md +150 -0
- package/releases/0.55.0/core/tree/.claude/pipeline.md +101 -0
- package/releases/0.55.0/core/tree/.claude/retrieval.md +103 -0
- package/releases/0.55.0/core/tree/.claude/router.md +205 -0
- package/releases/0.55.0/core/tree/.claude/templates/integration.md +48 -0
- package/releases/0.55.0/core/tree/CLAUDE.md +166 -0
- package/releases/0.55.0/core/tree/scripts/cost-watch.mjs +25 -0
- package/releases/0.55.0/core/tree/scripts/edit-guard.mjs +24 -0
- package/releases/0.55.0/core/tree/scripts/harness-check.mjs +71 -0
- package/releases/0.55.0/core/tree/scripts/loop-gate.mjs +19 -0
- package/releases/0.55.0/core/vocabulary.json +14 -0
- package/releases/0.55.0/surfaces/blockchain/tree/.claude/agents/architect.md +5 -0
- package/releases/0.55.0/surfaces/blockchain/tree/.claude/agents/devops.md +5 -0
- package/releases/0.55.0/surfaces/blockchain/tree/.claude/agents/reviewer.md +5 -0
- package/releases/0.55.0/surfaces/blockchain/tree/.claude/agents/solidity-auditor.md +18 -0
- package/releases/0.55.0/surfaces/blockchain/tree/.claude/agents/solidity-dev.md +16 -0
- package/releases/0.55.0/surfaces/blockchain/tree/.claude/agents-overview.md +6 -0
- package/releases/0.55.0/surfaces/blockchain/tree/.claude/graph.md +11 -0
- package/releases/0.55.0/surfaces/blockchain/tree/.claude/router.md +6 -0
- package/releases/0.55.0/surfaces/blockchain/tree/CLAUDE.md +12 -0
- package/releases/0.55.0/surfaces/d1/tree/.claude/agents/dba.md +15 -0
- package/releases/0.55.0/surfaces/d1/tree/.claude/agents/devops.md +2 -0
- package/releases/0.55.0/surfaces/d1/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.55.0/surfaces/d1/tree/.claude/patterns.md +8 -0
- package/releases/0.55.0/surfaces/d1/tree/CLAUDE.md +2 -0
- package/releases/0.55.0/surfaces/db/tree/.claude/agents/architect.md +5 -0
- package/releases/0.55.0/surfaces/db/tree/.claude/agents/dba.md +54 -0
- package/releases/0.55.0/surfaces/db/tree/.claude/agents/devops.md +5 -0
- package/releases/0.55.0/surfaces/db/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.55.0/surfaces/db/tree/.claude/agents/integration-tester.md +10 -0
- package/releases/0.55.0/surfaces/db/tree/.claude/agents/planner.md +2 -0
- package/releases/0.55.0/surfaces/db/tree/.claude/agents/reviewer.md +22 -0
- package/releases/0.55.0/surfaces/db/tree/.claude/agents/secops.md +2 -0
- package/releases/0.55.0/surfaces/db/tree/.claude/agents-overview.md +5 -0
- package/releases/0.55.0/surfaces/db/tree/.claude/graph.md +8 -0
- package/releases/0.55.0/surfaces/db/tree/.claude/patterns.md +22 -0
- package/releases/0.55.0/surfaces/db/tree/.claude/pipeline.md +13 -0
- package/releases/0.55.0/surfaces/db/tree/.claude/retrieval.md +5 -0
- package/releases/0.55.0/surfaces/db/tree/.claude/router.md +4 -0
- package/releases/0.55.0/surfaces/db/tree/CLAUDE.md +17 -0
- package/releases/0.55.0/surfaces/drizzle/tree/.claude/agents/dba.md +9 -0
- package/releases/0.55.0/surfaces/drizzle/tree/.claude/agents/devops.md +5 -0
- package/releases/0.55.0/surfaces/drizzle/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.55.0/surfaces/drizzle/tree/.claude/patterns.md +7 -0
- package/releases/0.55.0/surfaces/edge-cf/tree/.claude/agents/architect.md +14 -0
- package/releases/0.55.0/surfaces/edge-cf/tree/.claude/agents/dba.md +2 -0
- package/releases/0.55.0/surfaces/edge-cf/tree/.claude/agents/devops.md +29 -0
- package/releases/0.55.0/surfaces/edge-cf/tree/.claude/agents/implementer.md +14 -0
- package/releases/0.55.0/surfaces/edge-cf/tree/.claude/agents/integration-tester.md +11 -0
- package/releases/0.55.0/surfaces/edge-cf/tree/.claude/agents/qa.md +3 -0
- package/releases/0.55.0/surfaces/edge-cf/tree/.claude/agents/reviewer.md +8 -0
- package/releases/0.55.0/surfaces/edge-cf/tree/.claude/agents/secops.md +8 -0
- package/releases/0.55.0/surfaces/edge-cf/tree/.claude/patterns.md +17 -0
- package/releases/0.55.0/surfaces/edge-cf/tree/.claude/retrieval.md +8 -0
- package/releases/0.55.0/surfaces/edge-cf/tree/CLAUDE.md +27 -0
- package/releases/0.55.0/surfaces/frontend/tree/.claude/agents/architect.md +20 -0
- package/releases/0.55.0/surfaces/frontend/tree/.claude/agents/devops.md +28 -0
- package/releases/0.55.0/surfaces/frontend/tree/.claude/agents/implementer.md +25 -0
- package/releases/0.55.0/surfaces/frontend/tree/.claude/agents/qa.md +17 -0
- package/releases/0.55.0/surfaces/frontend/tree/.claude/agents/reviewer.md +56 -0
- package/releases/0.55.0/surfaces/frontend/tree/.claude/patterns.md +8 -0
- package/releases/0.55.0/surfaces/frontend/tree/.claude/retrieval.md +2 -0
- package/releases/0.55.0/surfaces/frontend/tree/.claude/router.md +14 -0
- package/releases/0.55.0/surfaces/frontend/tree/CLAUDE.md +5 -0
- package/releases/0.55.0/surfaces/integrations/tree/.claude/agents/architect.md +16 -0
- package/releases/0.55.0/surfaces/integrations/tree/.claude/agents/implementer.md +12 -0
- package/releases/0.55.0/surfaces/integrations/tree/.claude/agents/integration-tester.md +20 -0
- package/releases/0.55.0/surfaces/integrations/tree/.claude/agents/planner.md +2 -0
- package/releases/0.55.0/surfaces/integrations/tree/.claude/agents/reviewer.md +21 -0
- package/releases/0.55.0/surfaces/integrations/tree/.claude/agents/secops.md +2 -0
- package/releases/0.55.0/surfaces/integrations/tree/.claude/agents-overview.md +8 -0
- package/releases/0.55.0/surfaces/integrations/tree/.claude/graph.md +10 -0
- package/releases/0.55.0/surfaces/integrations/tree/.claude/patterns.md +38 -0
- package/releases/0.55.0/surfaces/integrations/tree/.claude/pipeline.md +16 -0
- package/releases/0.55.0/surfaces/integrations/tree/.claude/retrieval.md +16 -0
- package/releases/0.55.0/surfaces/integrations/tree/.claude/router.md +6 -0
- package/releases/0.55.0/surfaces/integrations/tree/CLAUDE.md +17 -0
- package/releases/0.55.0/surfaces/money/tree/.claude/agents/architect.md +12 -0
- package/releases/0.55.0/surfaces/money/tree/.claude/agents/dba.md +14 -0
- package/releases/0.55.0/surfaces/money/tree/.claude/agents/implementer.md +11 -0
- package/releases/0.55.0/surfaces/money/tree/.claude/agents/integration-tester.md +3 -0
- package/releases/0.55.0/surfaces/money/tree/.claude/agents/reviewer.md +23 -0
- package/releases/0.55.0/surfaces/money/tree/.claude/agents/secops.md +5 -0
- package/releases/0.55.0/surfaces/money/tree/.claude/agents/solidity-auditor.md +4 -0
- package/releases/0.55.0/surfaces/money/tree/.claude/agents/solidity-dev.md +4 -0
- package/releases/0.55.0/surfaces/money/tree/.claude/graph.md +2 -0
- package/releases/0.55.0/surfaces/money/tree/.claude/patterns.md +49 -0
- package/releases/0.55.0/surfaces/money/tree/.claude/pipeline.md +2 -0
- package/releases/0.55.0/surfaces/money/tree/.claude/retrieval.md +2 -0
- package/releases/0.55.0/surfaces/money/tree/CLAUDE.md +11 -0
- package/releases/0.55.0/surfaces/pii/tree/.claude/agents/dba.md +2 -0
- package/releases/0.55.0/surfaces/pii/tree/.claude/agents/devops.md +8 -0
- package/releases/0.55.0/surfaces/pii/tree/.claude/agents/reviewer.md +8 -0
- package/releases/0.55.0/surfaces/pii/tree/.claude/agents/secops.md +2 -0
- package/releases/0.55.0/surfaces/pii/tree/.claude/agents/solidity-auditor.md +5 -0
- package/releases/0.55.0/surfaces/pii/tree/CLAUDE.md +5 -0
- package/releases/0.55.0/surfaces/prisma/tree/.claude/agents/architect.md +2 -0
- package/releases/0.55.0/surfaces/prisma/tree/.claude/agents/dba.md +42 -0
- package/releases/0.55.0/surfaces/prisma/tree/.claude/agents/devops.md +11 -0
- package/releases/0.55.0/surfaces/prisma/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.55.0/surfaces/prisma/tree/.claude/agents/integration-tester.md +2 -0
- package/releases/0.55.0/surfaces/prisma/tree/.claude/agents/reviewer.md +2 -0
- package/releases/0.55.0/surfaces/prisma/tree/.claude/patterns.md +15 -0
- package/releases/0.55.0/surfaces/prisma/tree/CLAUDE.md +5 -0
- package/src/commands/check.mjs +107 -6
- package/src/commands/learn.mjs +44 -17
- package/src/commands/pills.mjs +6 -2
- package/src/commands/stats.mjs +28 -9
- package/src/dashboard.html +3 -2
- package/src/office.html +2 -2
- package/src/transcripts.mjs +15 -2
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<!-- nina:slot money.1 -->
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Monetary values & percentages
|
|
6
|
+
|
|
7
|
+
- **Money is an integer of the currency's minor unit**, end to end — {{MINOR_UNIT}}, never a float, never a type that can hold a fraction of one. Source of precision: `{{MONEY_MODULE}}`.
|
|
8
|
+
- **Percentages are basis points** (`40% → 4000`, `100% → 10000`) so a distribution is exact without floating point.
|
|
9
|
+
- **Parsing, formatting and percentage arithmetic live in one module and nowhere else.** A second place that turns a string into money is a second rounding rule, and the two will disagree on a value somebody is owed.
|
|
10
|
+
- **Never** convert to a floating-point type before formatting, and never let a display format round a stored value.
|
|
11
|
+
- Monetary database columns are integer. JSON responses serialize them as **strings**, not numbers, so no client parses them into a float. The service owns the conversion.
|
|
12
|
+
|
|
13
|
+
<!-- nina:slot money.2 -->
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Distribution invariants (enforced by reviewer + unit tests)
|
|
18
|
+
|
|
19
|
+
The distribution engine lives in `{{CORE_PKG}}`. It is pure and total over integer {{MINOR_UNIT}}:
|
|
20
|
+
|
|
21
|
+
- A destination is either a percentage (basis points of the amount) or a fixed value.
|
|
22
|
+
- `total = Σ destinations`, computed in {{MINOR_UNIT}}.
|
|
23
|
+
- `total > amount` → **reject.** Never clamp, never distribute what is not there.
|
|
24
|
+
- `total < amount` → **allow**, surface the shortfall, and leave the remainder **parked**. Silence is the defect here: an unexplained remainder is indistinguishable from a bug.
|
|
25
|
+
- `total = amount` → OK.
|
|
26
|
+
- A retention is just another destination — the same arithmetic applies to it, with no special case.
|
|
27
|
+
|
|
28
|
+
<!-- nina:slot money.3 -->
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## State machines & idempotency (enforced by reviewer)
|
|
33
|
+
|
|
34
|
+
- **Every money-moving entity is a state machine.** Its states and legal transitions are declared in `.claude/architecture.md`; the code follows the declaration, not the other way round. Illegal transitions throw; they are never silently coerced.
|
|
35
|
+
- **Every transition writes an audit row** (entity type, entity id, from, to, actor). No transition without a trail — the trail is what makes a money bug diagnosable after the money has moved.
|
|
36
|
+
- **Outbound transfers are idempotent.** Each carries a unique key, and dedupe happens before the side effect, at the serialization point.
|
|
37
|
+
- **One serialization point per balance.** Whatever computes and dispatches against a single balance never runs concurrently with itself. Two concurrent runs over one balance is how a double send happens even when every individual write is correct.
|
|
38
|
+
|
|
39
|
+
<!-- nina:slot money.4 -->
|
|
40
|
+
- **Money computation and dispatch go through the serialization point.** Routes, queue consumers and tools never run a distribution or a transfer synchronously in the request path.
|
|
41
|
+
|
|
42
|
+
<!-- nina:slot money.5 -->
|
|
43
|
+
- **The distribution engine lives in `{{CORE_PKG}}`.** Services call it as a pure function; they do not embed money logic inline.
|
|
44
|
+
|
|
45
|
+
<!-- nina:slot money.6 -->
|
|
46
|
+
- Idempotency on money-moving writes: the record carries an idempotency key, and the serialization point refuses the second attempt *before* the side effect.
|
|
47
|
+
|
|
48
|
+
<!-- nina:slot money.7 -->
|
|
49
|
+
- `{{CORE_PKG}}` is the most-tested package — pure functions over fixtures. Cover the distribution invariants exhaustively: over, under, exact, mixed percentage and fixed, and rounding.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<!-- nina:slot money.1 -->
|
|
2
|
+
3. **An outbound transfer is idempotent — it is NEVER sent twice.** Every transfer carries an idempotency key, and deduplication happens at a single serialization point **before** the side effect, never after it. A retry, a re-delivered queue message, a double-click and a replayed webhook must all collapse to one transfer. This is the highest-blast-radius invariant in the system: almost everything else can be corrected afterwards, and a duplicated transfer cannot.
|
|
3
|
+
|
|
4
|
+
<!-- nina:slot money.2 -->
|
|
5
|
+
4. **Conservation — what comes in equals what goes out plus what is retained.** A distribution may NEVER exceed the amount it distributes → **block**. If it is **less**, **alert** and leave the remainder **parked** and visible — never silently distributed, never silently absorbed. All arithmetic is integer {{MINOR_UNIT}}; percentages are basis points. The LLM never computes a monetary value.
|
|
6
|
+
|
|
7
|
+
<!-- nina:slot money.3 -->
|
|
8
|
+
5. **State-machine integrity.** Every money-moving entity has an explicit set of states and legal transitions, declared in `.claude/architecture.md` § *State machines* — not inferred from whatever code happens to exist. Only declared transitions are legal; an illegal one throws and is never silently coerced. **Every transition writes an audit row** (entity, id, from → to, actor, when). Skipping a state, inventing one, or landing a transition with no audit row is a hard reject.
|
|
9
|
+
|
|
10
|
+
<!-- nina:slot money.4 -->
|
|
11
|
+
- **money movement**: anything that creates, moves, settles or records a balance
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
<!-- nina:slot pii.1 -->
|
|
2
|
+
- **Privacy.** No sensitive value in clear text where it must not be. The categories are declared in `.claude/architecture.md` § *Privacy* — they are not decided per query, and not decided by you. **Document bytes live only in the object store, referenced by key: the column holds the key, never the bytes.** Any column the architect's spec flagged for masking must be encrypted at rest. Reject a schema that widens what is stored in the clear.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<!-- nina:slot pii.1 -->
|
|
2
|
+
|
|
3
|
+
**Point it at an UNAUTHENTICATED route — a sign-in page is the right one.** Never sign in, and never
|
|
4
|
+
screenshot a signed-in page. Accounts on deployed environments hold real personal data, and a
|
|
5
|
+
screenshot or a console dump pulls it into agent transcripts and logs, where it persists and nobody
|
|
6
|
+
ever looks for it again. That is a privacy leak with no upside here: the sign-in page proves
|
|
7
|
+
everything this check is for. It renders from the same bundle, it exercises the same build-time env
|
|
8
|
+
inlining (a missing variable blanks it identically), and it needs no session.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<!-- nina:slot pii.1 -->
|
|
2
|
+
- Check for privacy regressions: **no sensitive value in a log, an error message — a library's own included — a URL or a test fixture**, per the categories in `.claude/architecture.md` § *Privacy*; document bytes only in the object store, never plaintext in the database; no leaked secret.
|
|
3
|
+
|
|
4
|
+
<!-- nina:slot pii.2 -->
|
|
5
|
+
- **privacy** — the privacy check above, in full: no sensitive value in a log, an error message, a
|
|
6
|
+
URL or a test fixture; document bytes only in the object store; no leaked secret. Where
|
|
7
|
+
**tenant-and-privacy** is dispatched, its reviewer owns this too and there is no separate one; where
|
|
8
|
+
it is not, this is a dimension of its own. Either way it is never nobody's.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
<!-- nina:slot pii.1 -->
|
|
2
|
+
- **Privacy (Hard Rule #8)** — the categories declared in `.claude/architecture.md` § *Privacy* must never appear in logs, in responses that do not need them, in error paths, or in the database in clear text. Check every endpoint that returns a person's record for fields it includes by accident: a `select` that quietly grew a column is the usual way this leaks. Check the error paths too — they are written last and reviewed least — and what the libraries on them print or carry in their own errors, bound values included.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<!-- nina:slot pii.1 -->
|
|
2
|
+
- **Nothing personal reaches the chain.** What is written on-chain is public, permanent, and beyond
|
|
3
|
+
deletion by anyone — including by you, and including after a subject asks. A hash of a personal
|
|
4
|
+
identifier is not a protection: it is a lookup table for whoever holds the input set. Reject a
|
|
5
|
+
personal datum stored in state, emitted in an event, or passed as calldata.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<!-- nina:slot pii.1 -->
|
|
2
|
+
8. **Sensitive personal data is classified, and the classification is enforced.** What counts as sensitive here — identity documents, financial identifiers, anything a person would not expect to be readable by whoever can read a log — is declared in `.claude/architecture.md` § *Privacy*, along with the regime that governs it ({{PRIVACY_REGIME}}). Encrypted at rest. **No sensitive value in a log, an error message, a URL, an analytics event, or an agent transcript** — the places nobody thinks about are exactly the ones that persist. That includes what a library puts in its own errors and prints itself: a database client's error can carry the query and every bound value, and a framework can log a whole error past the logger it was given. A database error is mapped at the data layer to a typed error from a closed list before anything logs or returns it, and a test proves that a bound value it writes reaches no thrown error. Document bytes live only in the object store, referenced by key, never in the database in clear text.
|
|
3
|
+
|
|
4
|
+
<!-- nina:slot pii.2 -->
|
|
5
|
+
- **personal data**: where it is collected, stored, logged or sent
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<!-- nina:slot prisma.1 -->
|
|
2
|
+
| `prisma-cli` | **before ANY `prisma` CLI command** — `validate`, `format`, `migrate dev`, `migrate diff`, `migrate deploy`. Flags differ between versions, and one of them (`migrate diff --shadow-database-url` against a live database) destroys the database it points at |
|
|
3
|
+
| `prisma-client-api` | auditing a new or changed query — filters, operators, `$transaction` semantics. Through a driver adapter, cite the adapter's installed source for what a transaction does: the skill describes the default engine, and an adapter can roll back less |
|
|
4
|
+
|
|
5
|
+
<!-- nina:slot prisma.2 -->
|
|
6
|
+
Neither skill covers a **caching or edge layer sitting on top of the client** — cache strategy,
|
|
7
|
+
edge-client behaviour and the rule about never caching a read that authorizes a write belong to that
|
|
8
|
+
layer's own integration doc, declared like any other integration. A skill does not replace it.
|
|
9
|
+
|
|
10
|
+
<!-- nina:slot prisma.3 -->
|
|
11
|
+
- **With Prisma, both offline.** Run `pnpm --filter {{DB_PKG_NAME}} exec prisma validate`; it must pass. Then run `prisma migrate diff` in its **offline, file-only form** and read the generated SQL, not just the Prisma delta. Its flags changed in Prisma 7, so read the installed major (`prisma --version`) before writing the command:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
# Prisma 6. Compare the PREVIOUS schema against the working one — pure file-to-file, no database.
|
|
15
|
+
git show HEAD:{{DB_PKG}}/prisma/schema.prisma > /tmp/schema-head.prisma
|
|
16
|
+
pnpm --filter {{DB_PKG_NAME}} exec prisma migrate diff \
|
|
17
|
+
--from-schema-datamodel /tmp/schema-head.prisma \
|
|
18
|
+
--to-schema-datamodel prisma/schema.prisma \
|
|
19
|
+
--script
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
From Prisma 7 the two flags are `--from-schema` and `--to-schema`, and the schema engine starts from the
|
|
23
|
+
datasource in `prisma.config.ts` even for this diff: with none there, it prints nothing and exits 0. For
|
|
24
|
+
SQLite a placeholder the diff never opens is enough, a `file:` URL under a gitignored directory; for any
|
|
25
|
+
other provider, find out what the diff opens before you give it one. Never a real database's URL. A first schema has nothing at `HEAD`: diff it `--from-empty`. Compare the output against the
|
|
26
|
+
hand-written `migration.sql` to confirm the declarative parts match.
|
|
27
|
+
|
|
28
|
+
⚠️ **Do NOT reach for `--from-migrations`.** It looks like the natural choice and it is a trap:
|
|
29
|
+
Prisma refuses it without a shadow database (`--shadow-database-url`, or from Prisma 7 a
|
|
30
|
+
`shadowDatabaseUrl` in `prisma.config.ts`), which pushes you toward supplying a database URL — the exact move that destroys databases (below). The file-to-file form above answers the
|
|
31
|
+
same question with no database involved.
|
|
32
|
+
|
|
33
|
+
⛔ **NEVER point `--shadow-database-url`, `--from-url`, `--to-url`, `--from-schema-datasource` — or, from Prisma 7, a `shadowDatabaseUrl` or the config datasource behind `--from-config-datasource` — at a real database, most of all not the one `{{SECRETS_LOCAL}}` names.** Prisma **executes** the entire migration history against whatever database those flags name, which **DESTROYS ALL DATA** in it. A shadow database must be a disposable, empty database and nothing else. It does not announce itself: the command completes with a reassuring "empty migration" result and no error, having already destroyed everything in the database it was pointed at. If the offline form above cannot answer your question, **STOP and report that to the orchestrator** instead of reaching for a database URL.
|
|
34
|
+
|
|
35
|
+
<!-- nina:slot prisma.4 -->
|
|
36
|
+
- **Where reads are cached through Prisma Accelerate,** every `findUnique` / `findMany` on a hot read path names its `cacheStrategy` (`ttl` / `swr`), and one that feeds a correctness-critical write names none.
|
|
37
|
+
|
|
38
|
+
<!-- nina:slot prisma.5 -->
|
|
39
|
+
- **On an edge runtime,** new Prisma code paths use the edge client of the installed major: `@prisma/client/edge` up to Prisma 6; from 7, the client the `prisma-client` generator writes with the platform's `runtime` set, imported from where it is generated — `@prisma/client/edge` fails there with `MODULE_NOT_FOUND`.
|
|
40
|
+
|
|
41
|
+
<!-- nina:slot prisma.6 -->
|
|
42
|
+
- Run a Prisma command that writes to a real database — `prisma migrate dev`, `migrate deploy`, `migrate reset`, `migrate resolve`, `db push`, `db execute`, `$executeRaw*` — or **any `prisma migrate diff` variant carrying a database URL**, which silently wipes the database it points at.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<!-- nina:slot prisma.1 -->
|
|
2
|
+
- **`prisma-cli`** — before `migrate deploy` or any other Prisma CLI command against a real database.
|
|
3
|
+
|
|
4
|
+
<!-- nina:slot prisma.2 -->
|
|
5
|
+
- **Prisma migrations go out with `prisma migrate deploy`**, and nothing else changes a shared database's schema.
|
|
6
|
+
|
|
7
|
+
<!-- nina:slot prisma.3 -->
|
|
8
|
+
- Run `prisma migrate diff --shadow-database-url <url>` against any live database. It **executes** the migration history against that database, destroying everything in it, and reports success. Use a disposable shadow database or don't run it.
|
|
9
|
+
|
|
10
|
+
<!-- nina:slot prisma.4 -->
|
|
11
|
+
- Run `prisma migrate reset` against a shared database, ever.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!-- nina:slot prisma.1 -->
|
|
2
|
+
- **Database table/column names** (Prisma `@map` / `@@map`): `snake_case` in SQL, `camelCase` in TS.
|
|
3
|
+
|
|
4
|
+
<!-- nina:slot prisma.2 -->
|
|
5
|
+
- Where Prisma reads are cached through Accelerate, `cacheStrategy` lives in `{{DB_PKG}}`: services do not add, strip, or override cache policies.
|
|
6
|
+
|
|
7
|
+
<!-- nina:slot prisma.3 -->
|
|
8
|
+
|
|
9
|
+
### Prisma
|
|
10
|
+
|
|
11
|
+
- Schema lives in `{{DB_PKG}}/prisma/schema.prisma`. Nowhere else.
|
|
12
|
+
- **Never write raw SQL** unless justified in a code comment with perf data.
|
|
13
|
+
- N+1 is solved with `include` / `select`, chosen deliberately.
|
|
14
|
+
- Where reads are cached through Accelerate, every `findUnique` / `findMany` on a hot path defines its `cacheStrategy`, and no direct connection string is embedded in code.
|
|
15
|
+
- Tests run a real Prisma client against a real database; the client is never mocked.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<!-- nina:slot prisma.1 -->
|
|
2
|
+
| Run any `prisma` CLI command (the database gate, devops, and the integration gate where there is one) | `prisma-cli` | flags differ between versions; `migrate diff --shadow-database-url` against a live DB wiped dev/staging once |
|
|
3
|
+
|
|
4
|
+
<!-- nina:slot prisma.2 -->
|
|
5
|
+
| Write or audit a Prisma query (architect, implementer, the database gate, reviewer) | `prisma-client-api` | filters, operators, `$transaction` semantics. a caching or edge layer on top of the client is **NOT covered** — its cache strategy belongs to that layer's own integration doc |
|
package/src/commands/check.mjs
CHANGED
|
@@ -14,11 +14,12 @@ import { expectedUnfilled } from '../expected.mjs';
|
|
|
14
14
|
import { parseGraph, validateGraph } from '../graph.mjs';
|
|
15
15
|
import { frontmatterFindings, installedSkills, modelFindings, toolFindings } from '../tools.mjs';
|
|
16
16
|
import { HOOK_SCRIPTS, missingWiring, shippedScripts } from '../wiring.mjs';
|
|
17
|
-
import { existsSync, readdirSync, realpathSync } from 'node:fs';
|
|
18
|
-
import { join, resolve, sep } from 'node:path';
|
|
17
|
+
import { existsSync, readFileSync, readdirSync, realpathSync } from 'node:fs';
|
|
18
|
+
import { basename, dirname, isAbsolute, join, resolve, sep } from 'node:path';
|
|
19
19
|
import { SLOT, closedGate, defaultedSlots, layerRootFor, noticeOf, readLayerText, stripWhy, walk } from './compose.mjs';
|
|
20
20
|
import { PLACEHOLDER, defaultVocabulary } from '../vocabulary.mjs';
|
|
21
21
|
import { missingNeeds } from '../surfaces.mjs';
|
|
22
|
+
import { resolveCitation } from './pills.mjs';
|
|
22
23
|
|
|
23
24
|
/** Fields every declared integration must carry, and why each one matters. */
|
|
24
25
|
const INTEGRATION_FIELDS = {
|
|
@@ -260,6 +261,34 @@ function liveStoreDirs(target) {
|
|
|
260
261
|
return live;
|
|
261
262
|
}
|
|
262
263
|
|
|
264
|
+
/**
|
|
265
|
+
* A text with its fenced blocks blanked. What a command printed, quoted as evidence, cites nothing: re-citing a path
|
|
266
|
+
* in it would falsify the evidence, and a note that cannot be cleared trains its reader to skip the check, the
|
|
267
|
+
* citations it is right about included. One project's `readlink` transcript held a store directory a peer change
|
|
268
|
+
* had since renamed. A fence left open runs to the end, as Markdown reads it.
|
|
269
|
+
*
|
|
270
|
+
* @param {string} text
|
|
271
|
+
* @returns {string}
|
|
272
|
+
*/
|
|
273
|
+
export function outsideFences(text) {
|
|
274
|
+
let fence = null;
|
|
275
|
+
return text
|
|
276
|
+
.split('\n')
|
|
277
|
+
.map((line) => {
|
|
278
|
+
if (fence) {
|
|
279
|
+
const close = /^\s*(`{3,}|~{3,})\s*$/.exec(line)?.[1];
|
|
280
|
+
if (close && close[0] === fence[0] && close.length >= fence.length) fence = null;
|
|
281
|
+
return '';
|
|
282
|
+
}
|
|
283
|
+
// Indented any depth, since a list item's fence is indented past the marker; and a backtick run whose rest
|
|
284
|
+
// holds a backtick is code in a line, not a fence.
|
|
285
|
+
const [, open, info] = /^\s*(`{3,}|~{3,})(.*)$/.exec(line) ?? [];
|
|
286
|
+
fence = open && !(open[0] === '`' && info.includes('`')) ? open : null;
|
|
287
|
+
return fence ? '' : line;
|
|
288
|
+
})
|
|
289
|
+
.join('\n');
|
|
290
|
+
}
|
|
291
|
+
|
|
263
292
|
/**
|
|
264
293
|
* The paths into the package manager's store that a text cites and the install no longer uses. Only the store: its
|
|
265
294
|
* directory names carry a suffix per peer, renamed when an unrelated dependency changes one, and the old directory
|
|
@@ -269,7 +298,8 @@ function liveStoreDirs(target) {
|
|
|
269
298
|
* package's own link, or one written from some package's directory, cannot be told stale from here. A line number
|
|
270
299
|
* after a path is not part of it; an elision (`...`, `…`), a template and a URL are not citations. Each occurrence of
|
|
271
300
|
* the store is read outwards, and the next is looked for past it, so the text is read once. A directory that is not
|
|
272
|
-
* `<name>@<version>` is a mention of the store, not a citation, except its hoisting `node_modules`.
|
|
301
|
+
* `<name>@<version>` is a mention of the store, not a citation, except its hoisting `node_modules`. A path in a fenced
|
|
302
|
+
* block is quoted output, not a citation (`outsideFences`).
|
|
273
303
|
*
|
|
274
304
|
* @param {string} text
|
|
275
305
|
* @param {string} target - The project directory.
|
|
@@ -277,7 +307,8 @@ function liveStoreDirs(target) {
|
|
|
277
307
|
* the docs of one run so the store is walked once.
|
|
278
308
|
* @returns {string[]} Each stale path once, in the order cited.
|
|
279
309
|
*/
|
|
280
|
-
export function unresolvedCitations(
|
|
310
|
+
export function unresolvedCitations(written, target, reached = new Map()) {
|
|
311
|
+
const text = outsideFences(written);
|
|
281
312
|
const cited = new Set();
|
|
282
313
|
let at = text.indexOf(STORE);
|
|
283
314
|
while (at !== -1) {
|
|
@@ -321,6 +352,69 @@ export function unresolvedCitations(text, target, reached = new Map()) {
|
|
|
321
352
|
return [...cited].filter(stale);
|
|
322
353
|
}
|
|
323
354
|
|
|
355
|
+
/**
|
|
356
|
+
* `<package dir>/node_modules/<parent> → <lib>@<version>/<file>[:<line>]`: a library no package of the project links,
|
|
357
|
+
* cited through the package that depends on it.
|
|
358
|
+
*/
|
|
359
|
+
const TRANSITIVE = /(\/?(?:[\w.@+-]+\/)*node_modules\/(?:@[\w.-]+\/)?[\w.-]+)\s*(?:→|->)\s*((?:@[\w.-]+\/)?[\w.-]+)@(\d[\w.+-]*)\/([^\s:`|),;]*[^\s:`|),;.])(?::(\d+))?/g;
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Where Node finds a library from a directory: the `node_modules` beside each directory up from it, one that is a
|
|
363
|
+
* `node_modules` itself skipped. From a package's real path in the store, that is the directory its dependencies are
|
|
364
|
+
* linked in.
|
|
365
|
+
*
|
|
366
|
+
* @param {string} from - A real path.
|
|
367
|
+
* @param {string} lib - The library's name, scoped or not.
|
|
368
|
+
* @returns {string|null} The library's real path.
|
|
369
|
+
*/
|
|
370
|
+
function resolveFrom(from, lib) {
|
|
371
|
+
for (let dir = from; ; dir = dirname(dir)) {
|
|
372
|
+
const candidate = join(dir, 'node_modules', lib);
|
|
373
|
+
if (basename(dir) !== 'node_modules' && existsSync(join(candidate, 'package.json'))) return realpathSync(candidate);
|
|
374
|
+
if (dirname(dir) === dir) return null;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* The citations of a library through its parent's link that do not resolve as written. A dependency of a dependency
|
|
380
|
+
* has no link of its own in any package — the emulator one project's every database premise was about is a dependency
|
|
381
|
+
* of its CLI, not of the project — and its only other path is a store directory a peer change renames. So it is cited
|
|
382
|
+
* through the parent's link, and resolved from where that link really leads, as Node resolves it: the parent there,
|
|
383
|
+
* the library found from it at the version written, the file in it, and the line within it.
|
|
384
|
+
*
|
|
385
|
+
* @param {string} text
|
|
386
|
+
* @param {string} target - The project directory the package directories are relative to.
|
|
387
|
+
* @returns {string[]} Each citation that does not resolve, with why, once.
|
|
388
|
+
*/
|
|
389
|
+
export function transitiveCitations(text, target) {
|
|
390
|
+
const wrong = new Map();
|
|
391
|
+
for (const [cited, parent, lib, version, file, line] of outsideFences(text).matchAll(TRANSITIVE)) {
|
|
392
|
+
if (wrong.has(cited)) continue;
|
|
393
|
+
let real;
|
|
394
|
+
try {
|
|
395
|
+
real = realpathSync(isAbsolute(parent) ? parent : join(target, parent));
|
|
396
|
+
} catch {
|
|
397
|
+
wrong.set(cited, `${parent} is not there`);
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
const found = resolveFrom(real, lib);
|
|
401
|
+
let installed = null;
|
|
402
|
+
try {
|
|
403
|
+
installed = found ? JSON.parse(readFileSync(join(found, 'package.json'), 'utf8')).version ?? null : null;
|
|
404
|
+
} catch {
|
|
405
|
+
// A manifest that does not parse says no version.
|
|
406
|
+
}
|
|
407
|
+
if (!found) wrong.set(cited, `${lib} does not resolve from it`);
|
|
408
|
+
else if (installed !== version) wrong.set(cited, `${lib} resolves to ${installed ?? 'no version'} there`);
|
|
409
|
+
else {
|
|
410
|
+
const at = resolveCitation(found, line ? `${file}:${line}` : file);
|
|
411
|
+
if (at.state === 'gone') wrong.set(cited, `${file} is not in ${lib}@${version}`);
|
|
412
|
+
else if (at.state === 'truncated') wrong.set(cited, `${file} has ${at.lines} line(s)`);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return [...wrong].map(([cited, why]) => `${cited}: ${why}`);
|
|
416
|
+
}
|
|
417
|
+
|
|
324
418
|
/**
|
|
325
419
|
* `nina check`.
|
|
326
420
|
*
|
|
@@ -452,10 +546,17 @@ export async function check(argv, ctx) {
|
|
|
452
546
|
const reached = new Map();
|
|
453
547
|
for (const doc of docs.filter((name) => name.endsWith('.md')).sort()) {
|
|
454
548
|
const key = `.claude/integrations/${doc}`;
|
|
455
|
-
const
|
|
549
|
+
const text = await readFile(join(target, key), 'utf8').catch(() => '');
|
|
550
|
+
const gone = unresolvedCitations(text, target, reached);
|
|
456
551
|
if (gone.length > 0) {
|
|
457
552
|
notes.push(
|
|
458
|
-
`${key} cites ${gone.length} path(s) in the package manager's store that the install no longer uses — ${gone[0]}${gone.length > 1 ? ', …' : ''}: a peer change renames those directories, and the old one stays on disk linked by nothing; re-cite each from the depending package's own node_modules link, with its version beside it
|
|
553
|
+
`${key} cites ${gone.length} path(s) in the package manager's store that the install no longer uses — ${gone[0]}${gone.length > 1 ? ', …' : ''}: a peer change renames those directories, and the old one stays on disk linked by nothing; re-cite each from the depending package's own node_modules link, with its version beside it — or, for a library no package links, through the one that depends on it: \`<package dir>/node_modules/<parent> → <lib>@<version>/<file>:<line>\``,
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
const wrong = transitiveCitations(text, target);
|
|
557
|
+
if (wrong.length > 0) {
|
|
558
|
+
notes.push(
|
|
559
|
+
`${key} cites ${wrong.length} librar${wrong.length > 1 ? 'ies' : 'y'} through a parent's link that ${wrong.length > 1 ? 'do' : 'does'} not resolve as written — ${wrong[0]}${wrong.length > 1 ? '; …' : ''}: read where the parent's link leads, and cite the version, file and line found there`,
|
|
459
560
|
);
|
|
460
561
|
}
|
|
461
562
|
}
|
package/src/commands/learn.mjs
CHANGED
|
@@ -38,7 +38,7 @@ import { deepLearn, transcriptsOf } from '../deep.mjs';
|
|
|
38
38
|
import { autoExport } from './export.mjs';
|
|
39
39
|
import { beforeModel } from '../detectors.mjs';
|
|
40
40
|
|
|
41
|
-
/**
|
|
41
|
+
/** Times one stage's work was sent back, since its newest lesson, that make a lesson overdue. */
|
|
42
42
|
export const CAPTURE_AT = 3;
|
|
43
43
|
|
|
44
44
|
/**
|
|
@@ -111,12 +111,16 @@ const SENT_BACK_HOURS = 24;
|
|
|
111
111
|
|
|
112
112
|
/**
|
|
113
113
|
* The stage each loop-back sent work back to: the next one dispatched in its session, after it reported, among
|
|
114
|
-
* the stages the project's graph routes that verdict of that stage to — or the only one it routes it to.
|
|
114
|
+
* the stages the project's graph routes that verdict of that stage to — or the only one it routes it to. One the
|
|
115
|
+
* graph routes to several, none of which has taken it back yet, went to no stage that can be told: it is charged to
|
|
116
|
+
* none, where it was charged to the stage that gave it — a gate that rejected work, doing its job, read as a stage
|
|
117
|
+
* sent back, and asked every turn for a lesson that was not its own.
|
|
115
118
|
*
|
|
116
119
|
* @param {object[]} records - Recorded dispatches.
|
|
117
120
|
* @param {Map<string, Map<string, Map<string, number>>>|null} loops - The graph's capped loop-back edges.
|
|
118
|
-
* @returns {Map<object, {to: string, fix: object|null}>} Loop-back record → the stage it sent work back to,
|
|
119
|
-
*
|
|
121
|
+
* @returns {Map<object, {to: string|null, fix: object|null}>} Loop-back record → the stage it sent work back to, null
|
|
122
|
+
* while that cannot be told, and the dispatch of that stage that took the work back, where one was found. A
|
|
123
|
+
* loop-back the graph does not route is not in it.
|
|
120
124
|
*/
|
|
121
125
|
export function sentBackTo(records, loops) {
|
|
122
126
|
const out = new Map();
|
|
@@ -134,11 +138,32 @@ export function sentBackTo(records, loops) {
|
|
|
134
138
|
const within = (x) => Date.parse(x.ts) - Date.parse(back) <= SENT_BACK_HOURS * 3_600_000;
|
|
135
139
|
const next = (bySession.get(r.session) ?? []).find((x) => String(x.ts) > back && within(x) && targets.has(x.role));
|
|
136
140
|
const to = next?.role ?? (targets.size === 1 ? [...targets.keys()][0] : null);
|
|
137
|
-
|
|
141
|
+
out.set(r, { to, fix: next ?? null });
|
|
138
142
|
}
|
|
139
143
|
return out;
|
|
140
144
|
}
|
|
141
145
|
|
|
146
|
+
/**
|
|
147
|
+
* The stage a loop-back is charged to: where it sent work back (`sentBackTo`), none while that cannot be told, and
|
|
148
|
+
* the stage that gave it only where the graph routes it nowhere.
|
|
149
|
+
*
|
|
150
|
+
* @param {ReturnType<typeof sentBackTo>} owners
|
|
151
|
+
* @param {object} r - A loop-back record.
|
|
152
|
+
* @returns {string|null}
|
|
153
|
+
*/
|
|
154
|
+
const chargedTo = (owners, r) => (owners.has(r) ? owners.get(r).to : r.role);
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* How many rounds some loop-backs sent back: those one dispatch took back are one, since the checkers that run beside
|
|
158
|
+
* each other each reject the same work. One no dispatch took back counts on its own, since nothing then says which
|
|
159
|
+
* work it rejected.
|
|
160
|
+
*
|
|
161
|
+
* @param {ReturnType<typeof sentBackTo>} owners
|
|
162
|
+
* @param {object[]} loops - Loop-back records.
|
|
163
|
+
* @returns {number}
|
|
164
|
+
*/
|
|
165
|
+
const sendings = (owners, loops) => new Set(loops.map((r) => owners.get(r)?.fix ?? r)).size;
|
|
166
|
+
|
|
142
167
|
/**
|
|
143
168
|
* Roles that looped back often enough, since their newest lesson, that one is overdue.
|
|
144
169
|
*
|
|
@@ -156,7 +181,7 @@ export function overdue(records, known, now = new Date(), days = CAPTURE_DAYS, o
|
|
|
156
181
|
// A loop-back is the lesson of the stage it sent work back to, where that is known (`sentBackTo`): charged
|
|
157
182
|
// to the stage that gave the verdict, the reviewer owed the implementer's lessons, and only a pill naming
|
|
158
183
|
// every checker in its applies_to ever settled the count.
|
|
159
|
-
const ownerOf = (r) => owners
|
|
184
|
+
const ownerOf = (r) => chargedTo(owners, r);
|
|
160
185
|
const roles = [...new Set(records.map(ownerOf).filter(Boolean))];
|
|
161
186
|
const out = [];
|
|
162
187
|
for (const role of roles) {
|
|
@@ -176,12 +201,17 @@ export function overdue(records, known, now = new Date(), days = CAPTURE_DAYS, o
|
|
|
176
201
|
const at = floor === newest ? taught?.at ?? null : null;
|
|
177
202
|
const after = (r) => day(r.ts) > floor || (at !== null && day(r.ts) === floor && String(r.ts) > at);
|
|
178
203
|
const loops = records.filter((r) => ownerOf(r) === role && readable(r.verdict) && isLoopBack(r.verdict) && after(r));
|
|
179
|
-
|
|
204
|
+
// Rounds sent back, not loop-backs: three reviewers beside each other rejecting one change sent it back once.
|
|
205
|
+
const count = sendings(owners, loops);
|
|
206
|
+
if (count >= CAPTURE_AT) {
|
|
207
|
+
// One per round sent back, as the count is: three reviewers beside each other are one entry, not three.
|
|
208
|
+
const listed = new Set();
|
|
180
209
|
const recent = loops
|
|
181
210
|
.sort((a, b) => String(b.ts).localeCompare(String(a.ts)))
|
|
211
|
+
.filter((r) => !listed.has(owners.get(r)?.fix ?? r) && listed.add(owners.get(r)?.fix ?? r))
|
|
182
212
|
.slice(0, 3)
|
|
183
213
|
.map((r) => ({ ts: day(r.ts), desc: r.desc ?? '', session: String(r.session ?? '').slice(0, 8) }));
|
|
184
|
-
out.push({ role, count
|
|
214
|
+
out.push({ role, count, since: newest, recent });
|
|
185
215
|
}
|
|
186
216
|
}
|
|
187
217
|
return out.sort((a, b) => b.count - a.count);
|
|
@@ -264,14 +294,11 @@ function wilson(k, n) {
|
|
|
264
294
|
*/
|
|
265
295
|
export function verified(records, known, { owners = new Map(), targets = null } = {}) {
|
|
266
296
|
const out = [];
|
|
267
|
-
const ownerOf = (r) => owners
|
|
297
|
+
const ownerOf = (r) => chargedTo(owners, r);
|
|
268
298
|
const sentBack = records.filter((r) => readable(r.verdict) && isLoopBack(r.verdict));
|
|
269
|
-
// The rounds these loop-backs sent back: those one dispatch took back are one. One no dispatch took back counts on
|
|
270
|
-
// its own, since nothing then says which work it rejected.
|
|
271
|
-
const sendings = (backs) => new Set(backs.map((r) => owners.get(r)?.fix ?? r)).size;
|
|
272
299
|
const sideOf = (these, backs) => {
|
|
273
300
|
const days = these.map((r) => day(r.ts)).sort();
|
|
274
|
-
return { n: these.length, loops: Math.min(these.length, sendings(backs)), span: [days[0] ?? null, days.at(-1) ?? null] };
|
|
301
|
+
return { n: these.length, loops: Math.min(these.length, sendings(owners, backs)), span: [days[0] ?? null, days.at(-1) ?? null] };
|
|
275
302
|
};
|
|
276
303
|
const ranOn = (r) => (r.usage_model ? `${r.usage_model}${r.effort ? ` · ${r.effort}` : ''}` : null);
|
|
277
304
|
for (const lesson of known.filter((l) => l.date)) {
|
|
@@ -309,7 +336,7 @@ export function verified(records, known, { owners = new Map(), targets = null }
|
|
|
309
336
|
const [bLo, bHi] = wilson(before.loops, before.n);
|
|
310
337
|
const [aLo, aHi] = wilson(after.loops, after.n);
|
|
311
338
|
const change = aHi < bLo ? 'lower' : aLo > bHi ? 'higher' : 'unclear';
|
|
312
|
-
const others = [...(targets ?? new Set(sentBack.map(ownerOf)))].filter((x) => x !== role);
|
|
339
|
+
const others = [...(targets ?? new Set(sentBack.map(ownerOf)))].filter((x) => x && x !== role);
|
|
313
340
|
const theirs = records.filter((r) => others.includes(r.role) && readable(r.verdict));
|
|
314
341
|
const otherBacks = sentBack.filter((r) => others.includes(ownerOf(r)));
|
|
315
342
|
const control = (pick) => sideOf(theirs.filter(pick), otherBacks.filter(pick));
|
|
@@ -1057,7 +1084,7 @@ export async function learn(argv, ctx) {
|
|
|
1057
1084
|
}
|
|
1058
1085
|
for (const o of late) {
|
|
1059
1086
|
console.log(
|
|
1060
|
-
` ${o.role}: ${o.count}
|
|
1087
|
+
` ${o.role}: sent back ${o.count} time(s) in the last ${days} days ` +
|
|
1061
1088
|
(o.since ? `since its newest lesson (${o.since})` : 'and no lesson at all') +
|
|
1062
1089
|
' — the newest:',
|
|
1063
1090
|
);
|
|
@@ -1119,10 +1146,10 @@ export async function learn(argv, ctx) {
|
|
|
1119
1146
|
? ` observe ${learning.runs} run(s) in ${records.length} round(s) recorded, ${span}`
|
|
1120
1147
|
: ' observe ✗ nothing recorded — no transcripts found for this project, so no link below can be measured',
|
|
1121
1148
|
);
|
|
1122
|
-
if (late.length === 0) console.log(` capture ✓ no role has
|
|
1149
|
+
if (late.length === 0) console.log(` capture ✓ no role has been sent back ${CAPTURE_AT}+ times without a lesson in the last ${days} days`);
|
|
1123
1150
|
late.forEach((o, i) => {
|
|
1124
1151
|
console.log(
|
|
1125
|
-
` ${i === 0 ? 'capture ' : ' '} ✗ ${o.role}: ${o.count}
|
|
1152
|
+
` ${i === 0 ? 'capture ' : ' '} ✗ ${o.role}: sent back ${o.count} time(s) ` +
|
|
1126
1153
|
(o.since ? `since its newest lesson (${o.since})` : 'and no lesson at all'),
|
|
1127
1154
|
);
|
|
1128
1155
|
});
|
package/src/commands/pills.mjs
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { mkdir, readFile, readdir, rename } from 'node:fs/promises';
|
|
14
14
|
import { HARNESS, readProfile } from '../paths.mjs';
|
|
15
|
+
import { localDay } from '../store.mjs';
|
|
15
16
|
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
16
17
|
import { spawnSync } from 'node:child_process';
|
|
17
18
|
import { dirname, join, resolve } from 'node:path';
|
|
@@ -124,7 +125,7 @@ export function list(value) {
|
|
|
124
125
|
* @param {string} citation - `path` or `path:line`.
|
|
125
126
|
* @returns {{state: 'ok'|'gone'|'truncated', path: string, line: number|null, lines?: number}}
|
|
126
127
|
*/
|
|
127
|
-
function resolveCitation(target, citation) {
|
|
128
|
+
export function resolveCitation(target, citation) {
|
|
128
129
|
const at = /^(.*):(\d+)$/.exec(citation);
|
|
129
130
|
const path = at ? at[1] : citation;
|
|
130
131
|
const line = at ? Number(at[2]) : null;
|
|
@@ -350,7 +351,10 @@ export async function pillsData(target, ctx) {
|
|
|
350
351
|
.filter((f) => f.endsWith('.md'))
|
|
351
352
|
.map((f) => f.replace(/\.md$/, ''))
|
|
352
353
|
.sort();
|
|
353
|
-
|
|
354
|
+
// The day where this machine is, the one the capture detector counts loop-backs by and names its requests with: read
|
|
355
|
+
// in UTC, for an hour after midnight at UTC+1 a lesson dated today was refused as in the future, and the loop-backs
|
|
356
|
+
// it answered, dated today, went on being reported.
|
|
357
|
+
const today = localDay(new Date().toISOString());
|
|
354
358
|
const files = existsSync(pillsDir) ? await pillFiles(pillsDir) : [];
|
|
355
359
|
|
|
356
360
|
if (files.length === 0) return { files: 0, active: 0, retired: 0, problems: [], notes: [], pills: [] };
|